sensemaking 0.18.3 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/cjs/chunk/group.js +10 -23
- package/dist/cjs/chunk/group.js.map +1 -1
- package/dist/cjs/chunk/parse.js +2 -5
- package/dist/cjs/chunk/parse.js.map +1 -1
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/shared.js +6 -10
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/status.js +44 -10
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/cli.js +2 -8
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/map.js +1 -3
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.js +3 -5
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.js +6 -8
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +1 -1
- package/dist/cjs/config/index.d.ts +1 -1
- package/dist/cjs/config/index.js +3 -0
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.js +10 -24
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/resolve.js.map +1 -1
- package/dist/cjs/config/signals.js +2 -3
- package/dist/cjs/config/signals.js.map +1 -1
- package/dist/cjs/config/types.d.cts +2 -1
- package/dist/cjs/config/types.d.ts +2 -1
- package/dist/cjs/config/types.js +8 -0
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.d.cts +1 -1
- package/dist/cjs/config/validate.d.ts +1 -1
- package/dist/cjs/config/validate.js +9 -10
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/cohere.js +2 -2
- package/dist/cjs/embed/cohere.js.map +1 -1
- package/dist/cjs/embed/distribution.js +3 -3
- package/dist/cjs/embed/distribution.js.map +1 -1
- package/dist/cjs/embed/handoff.d.cts +3 -0
- package/dist/cjs/embed/handoff.d.ts +3 -0
- package/dist/cjs/embed/handoff.js +39 -0
- package/dist/cjs/embed/handoff.js.map +1 -0
- package/dist/cjs/embed/identity.d.cts +11 -10
- package/dist/cjs/embed/identity.d.ts +11 -10
- package/dist/cjs/embed/identity.js +30 -15
- package/dist/cjs/embed/identity.js.map +1 -1
- package/dist/cjs/embed/langfit.js +2 -3
- package/dist/cjs/embed/langfit.js.map +1 -1
- package/dist/cjs/embed/languages.js +2 -4
- package/dist/cjs/embed/languages.js.map +1 -1
- package/dist/cjs/embed/openai.js +2 -2
- package/dist/cjs/embed/openai.js.map +1 -1
- package/dist/cjs/embed/query.js +58 -20
- package/dist/cjs/embed/query.js.map +1 -1
- package/dist/cjs/embed/registry.js +1 -2
- package/dist/cjs/embed/registry.js.map +1 -1
- package/dist/cjs/embed/static.d.cts +1 -1
- package/dist/cjs/embed/static.d.ts +1 -1
- package/dist/cjs/embed/static.js +8 -10
- package/dist/cjs/embed/static.js.map +1 -1
- package/dist/cjs/embed/store.d.cts +2 -2
- package/dist/cjs/embed/store.d.ts +2 -2
- package/dist/cjs/embed/store.js +48 -34
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/embed/types.js +1 -3
- package/dist/cjs/embed/types.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.js +19 -17
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/fences.js +5 -10
- package/dist/cjs/features/fences.js.map +1 -1
- package/dist/cjs/features/links.js +20 -37
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/sections.js +21 -19
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/features/tags.js +5 -8
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/graph/traverse.js +1 -2
- package/dist/cjs/graph/traverse.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +3 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output/column-hint.js +3 -6
- package/dist/cjs/output/column-hint.js.map +1 -1
- package/dist/cjs/output/output.js +7 -14
- package/dist/cjs/output/output.js.map +1 -1
- package/dist/cjs/output/search-error.js +2 -5
- package/dist/cjs/output/search-error.js.map +1 -1
- package/dist/cjs/scan/frontmatter.d.cts +1 -0
- package/dist/cjs/scan/frontmatter.d.ts +1 -0
- package/dist/cjs/scan/frontmatter.js +14 -18
- package/dist/cjs/scan/frontmatter.js.map +1 -1
- package/dist/cjs/scan/list.js +2 -3
- package/dist/cjs/scan/list.js.map +1 -1
- package/dist/cjs/scan/reparse.js +12 -26
- package/dist/cjs/scan/reparse.js.map +1 -1
- package/dist/cjs/scan/worker-error.js.map +1 -1
- package/dist/cjs/store/cache.d.cts +2 -0
- package/dist/cjs/store/cache.d.ts +2 -0
- package/dist/cjs/store/cache.js +20 -0
- package/dist/cjs/store/cache.js.map +1 -0
- package/dist/cjs/store/duckdb/batch.js +4 -16
- package/dist/cjs/store/duckdb/batch.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js +8 -20
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/fieldStats.js +2 -8
- package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
- package/dist/cjs/store/duckdb/lexical.js +21 -29
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/open.js +12 -13
- package/dist/cjs/store/duckdb/open.js.map +1 -1
- package/dist/cjs/store/duckdb/reconcile.js +4 -11
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js +2 -4
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
- package/dist/cjs/store/duckdb/store.js +2 -3
- package/dist/cjs/store/duckdb/store.js.map +1 -1
- package/dist/cjs/store/duckdb/vectors.js +8 -18
- package/dist/cjs/store/duckdb/vectors.js.map +1 -1
- package/dist/cjs/store/index.d.cts +3 -2
- package/dist/cjs/store/index.d.ts +3 -2
- package/dist/cjs/store/index.js +7 -8
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/native.js +6 -16
- package/dist/cjs/store/native.js.map +1 -1
- package/dist/cjs/store/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/connection.js +4 -8
- package/dist/cjs/store/sqlite/connection.js.map +1 -1
- package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
- package/dist/cjs/store/sqlite/lexical.js +3 -5
- package/dist/cjs/store/sqlite/lexical.js.map +1 -1
- package/dist/cjs/store/sqlite/open.d.cts +0 -1
- package/dist/cjs/store/sqlite/open.d.ts +0 -1
- package/dist/cjs/store/sqlite/open.js +22 -40
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/reconcile.js +2 -3
- package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
- package/dist/cjs/store/sqlite/sql-functions.js +2 -4
- 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/transaction.js +1 -3
- package/dist/cjs/store/transaction.js.map +1 -1
- package/dist/cjs/store/turso/connection.js +2 -6
- package/dist/cjs/store/turso/connection.js.map +1 -1
- package/dist/cjs/store/turso/fieldStats.js.map +1 -1
- package/dist/cjs/store/turso/lexical.d.cts +2 -0
- package/dist/cjs/store/turso/lexical.d.ts +2 -0
- package/dist/cjs/store/turso/lexical.js +347 -0
- package/dist/cjs/store/turso/lexical.js.map +1 -0
- package/dist/cjs/store/turso/native.js.map +1 -1
- package/dist/cjs/store/turso/open.d.cts +1 -1
- package/dist/cjs/store/turso/open.d.ts +1 -1
- package/dist/cjs/store/turso/open.js +81 -54
- package/dist/cjs/store/turso/open.js.map +1 -1
- package/dist/cjs/store/turso/reconcile.js +22 -22
- package/dist/cjs/store/turso/reconcile.js.map +1 -1
- package/dist/cjs/store/turso/store.js +18 -41
- package/dist/cjs/store/turso/store.js.map +1 -1
- package/dist/cjs/store/turso/vectors.d.cts +8 -0
- package/dist/cjs/store/turso/vectors.d.ts +8 -0
- package/dist/cjs/store/turso/vectors.js +435 -0
- package/dist/cjs/store/turso/vectors.js.map +1 -0
- package/dist/cjs/store/types.js +2 -3
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.js.map +1 -1
- package/dist/cjs/text/segment.d.cts +1 -0
- package/dist/cjs/text/segment.d.ts +1 -0
- package/dist/cjs/text/segment.js +10 -14
- package/dist/cjs/text/segment.js.map +1 -1
- package/dist/cjs/watch.js +2 -5
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/parse.js.map +1 -1
- package/dist/esm/chunk/group.js +10 -23
- package/dist/esm/chunk/group.js.map +1 -1
- package/dist/esm/chunk/parse.js +4 -8
- package/dist/esm/chunk/parse.js.map +1 -1
- package/dist/esm/cli/index.js +3 -5
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/shared.js +12 -22
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/status.js +43 -9
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/cli.js +2 -8
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/map.js +1 -3
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.js +3 -5
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.js +3 -5
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.js +10 -16
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.js +3 -7
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/config/access.js +8 -13
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +1 -1
- package/dist/esm/config/index.js +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.js +10 -24
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/resolve.js +2 -3
- package/dist/esm/config/resolve.js.map +1 -1
- package/dist/esm/config/signals.js +3 -5
- package/dist/esm/config/signals.js.map +1 -1
- package/dist/esm/config/types.d.ts +2 -1
- package/dist/esm/config/types.js +8 -2
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.d.ts +1 -1
- package/dist/esm/config/validate.js +7 -10
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/cohere.js +2 -2
- package/dist/esm/embed/cohere.js.map +1 -1
- package/dist/esm/embed/distribution.js +1 -1
- package/dist/esm/embed/distribution.js.map +1 -1
- package/dist/esm/embed/handoff.d.ts +3 -0
- package/dist/esm/embed/handoff.js +21 -0
- package/dist/esm/embed/handoff.js.map +1 -0
- package/dist/esm/embed/identity.d.ts +11 -10
- package/dist/esm/embed/identity.js +29 -26
- package/dist/esm/embed/identity.js.map +1 -1
- package/dist/esm/embed/langfit.js +2 -3
- package/dist/esm/embed/langfit.js.map +1 -1
- package/dist/esm/embed/languages.js +2 -4
- package/dist/esm/embed/languages.js.map +1 -1
- package/dist/esm/embed/openai.js +2 -2
- package/dist/esm/embed/openai.js.map +1 -1
- package/dist/esm/embed/query.js +21 -6
- package/dist/esm/embed/query.js.map +1 -1
- package/dist/esm/embed/registry.js +1 -2
- package/dist/esm/embed/registry.js.map +1 -1
- package/dist/esm/embed/static.d.ts +1 -1
- package/dist/esm/embed/static.js +8 -10
- package/dist/esm/embed/static.js.map +1 -1
- package/dist/esm/embed/store.d.ts +2 -2
- package/dist/esm/embed/store.js +28 -23
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/embed/types.js +1 -3
- package/dist/esm/embed/types.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.js +16 -16
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/features/fences.js +9 -19
- package/dist/esm/features/fences.js.map +1 -1
- package/dist/esm/features/links.js +24 -49
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/sections.js +20 -20
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/features/tags.js +5 -8
- package/dist/esm/features/tags.js.map +1 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/graph/traverse.js +1 -2
- package/dist/esm/graph/traverse.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output/column-hint.js +3 -6
- package/dist/esm/output/column-hint.js.map +1 -1
- package/dist/esm/output/output.js +9 -20
- package/dist/esm/output/output.js.map +1 -1
- package/dist/esm/output/search-error.js +2 -5
- package/dist/esm/output/search-error.js.map +1 -1
- package/dist/esm/scan/frontmatter.d.ts +1 -0
- package/dist/esm/scan/frontmatter.js +13 -18
- package/dist/esm/scan/frontmatter.js.map +1 -1
- package/dist/esm/scan/list.js +2 -3
- package/dist/esm/scan/list.js.map +1 -1
- package/dist/esm/scan/reparse.js +16 -34
- package/dist/esm/scan/reparse.js.map +1 -1
- package/dist/esm/scan/worker-error.js.map +1 -1
- package/dist/esm/store/cache.d.ts +2 -0
- package/dist/esm/store/cache.js +11 -0
- package/dist/esm/store/cache.js.map +1 -0
- package/dist/esm/store/duckdb/batch.js +4 -16
- package/dist/esm/store/duckdb/batch.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js +8 -20
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/fieldStats.js +4 -12
- package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
- package/dist/esm/store/duckdb/lexical.js +29 -36
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.js +2 -7
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/open.js +16 -23
- package/dist/esm/store/duckdb/open.js.map +1 -1
- package/dist/esm/store/duckdb/reconcile.js +4 -11
- package/dist/esm/store/duckdb/reconcile.js.map +1 -1
- package/dist/esm/store/duckdb/sql-functions.js +4 -9
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
- package/dist/esm/store/duckdb/store.js +6 -14
- package/dist/esm/store/duckdb/store.js.map +1 -1
- package/dist/esm/store/duckdb/vectors.js +14 -31
- package/dist/esm/store/duckdb/vectors.js.map +1 -1
- package/dist/esm/store/index.d.ts +3 -2
- package/dist/esm/store/index.js +5 -6
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/native.js +10 -25
- package/dist/esm/store/native.js.map +1 -1
- package/dist/esm/store/sql-functions.js +3 -5
- package/dist/esm/store/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/connection.js +4 -8
- package/dist/esm/store/sqlite/connection.js.map +1 -1
- package/dist/esm/store/sqlite/fieldStats.js +2 -6
- package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
- package/dist/esm/store/sqlite/lexical.js +5 -9
- package/dist/esm/store/sqlite/lexical.js.map +1 -1
- package/dist/esm/store/sqlite/open.d.ts +0 -1
- package/dist/esm/store/sqlite/open.js +21 -41
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/reconcile.js +6 -13
- package/dist/esm/store/sqlite/reconcile.js.map +1 -1
- package/dist/esm/store/sqlite/sql-functions.js +2 -4
- package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/store.js +1 -2
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/transaction.js +2 -5
- package/dist/esm/store/transaction.js.map +1 -1
- package/dist/esm/store/turso/connection.js +2 -6
- package/dist/esm/store/turso/connection.js.map +1 -1
- package/dist/esm/store/turso/fieldStats.js +2 -5
- package/dist/esm/store/turso/fieldStats.js.map +1 -1
- package/dist/esm/store/turso/lexical.d.ts +2 -0
- package/dist/esm/store/turso/lexical.js +128 -0
- package/dist/esm/store/turso/lexical.js.map +1 -0
- package/dist/esm/store/turso/native.js +2 -7
- package/dist/esm/store/turso/native.js.map +1 -1
- package/dist/esm/store/turso/open.d.ts +1 -1
- package/dist/esm/store/turso/open.js +36 -29
- package/dist/esm/store/turso/open.js.map +1 -1
- package/dist/esm/store/turso/reconcile.js +22 -22
- package/dist/esm/store/turso/reconcile.js.map +1 -1
- package/dist/esm/store/turso/store.js +17 -28
- package/dist/esm/store/turso/store.js.map +1 -1
- package/dist/esm/store/turso/vectors.d.ts +8 -0
- package/dist/esm/store/turso/vectors.js +98 -0
- package/dist/esm/store/turso/vectors.js.map +1 -0
- package/dist/esm/store/types.js +2 -3
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.js +2 -3
- package/dist/esm/store/vectors.js.map +1 -1
- package/dist/esm/text/segment.d.ts +1 -0
- package/dist/esm/text/segment.js +13 -21
- package/dist/esm/text/segment.js.map +1 -1
- package/dist/esm/watch.js +2 -5
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/parse.js.map +1 -1
- package/package.json +3 -1
- package/schema.json +2 -2
- package/skills/sense/SKILL.md +2 -2
- package/skills/sense-setup/SKILL.md +3 -3
- package/dist/cjs/store/meta.d.cts +0 -3
- package/dist/cjs/store/meta.d.ts +0 -3
- package/dist/cjs/store/meta.js +0 -215
- package/dist/cjs/store/meta.js.map +0 -1
- package/dist/esm/store/meta.d.ts +0 -3
- package/dist/esm/store/meta.js +0 -17
- package/dist/esm/store/meta.js.map +0 -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 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 baseKey\n// (indexed, for the incremental resolve below), dst the resolved path or NULL (a\n// queryable dead link), embed whether it's `![[x]]`/`` rather than `[[x]]`/`[](x.md)`\n// -- Obsidian's grain: a target both linked and embedded in the same note is two rows.\n\n// Wikilinks ([[target]], [[target#anchor|alias]], embeds), internal markdown links, and\n// frontmatter values that are exactly a wikilink (\"[[X]]\"; mid-string and ![[...]] forms are\n// not links there -- Obsidian's rule, probe-verified).\n// One rule for [[inner]] text wherever it appears: alias stripped after |, a leading #\n// keeps the anchor as the target (a same-note self-link needs a heading name), otherwise\n// 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\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: Obsidian gives markdown links full\n // linkpath resolution, so \\](Zektor) resolves like [[Zektor]] and \\](#anchor) is a\n // self-edge. External URLs (a scheme anywhere survives the malformed double-paren case)\n // and titled links (dest stops at whitespace) are skipped.\n // A space in the destination is only valid ahead of a quoted title; a domain-shaped first\n // segment (www.example.com/...) is external even without a scheme.\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\n// note's directory, then basename match (shortest path wins on ties -- verified against a\n// cold-loaded Obsidian vault on 6+ real collision pairs; byBase's lists are pre-sorted that way).\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 just the rows whose dst actually changed -- the\n// caller writes those in one runBatch call, keyed on (src, target) so a link/embed sibling\n// pair sharing one resolution rewrites both.\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// A new or deleted file can change any note's resolution, so re-resolve the whole table.\n// Fallback for cold builds and large deltas -- see afterReconcile's threshold.\nasync function resolveAll(db: Connection, files: FileStat[]): Promise<boolean> {\n const pathSet = new Set(files.map((f) => f.relPath));\n const byBase = buildByBase(files);\n const stmt = await db.prepare('SELECT src, target, dst, embed FROM links');\n const rows = (await stmt.all()) as unknown as LinkRow[];\n const changed = resolveRows(rows, pathSet, byBase);\n await writeResolved(db, changed);\n return changed.length > 0;\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-resolve only what this reconcile could have touched: re-stored sources, links whose\n// target basename matches an added/vanished file, and links whose dst just vanished. All\n// three are indexed lookups, so this never reads the whole table.\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 row, as 0.12's grain always had it -- two written targets resolving to one\n// dst stay two edges (a weight the fusion evals were gated on). The only exclusion is an\n// embed whose exact (src, target) also exists as a link: that second row is new with the\n// embed grain and would double an edge that used to be one row. The NOT EXISTS probes the\n// primary key and fires only for embed rows; both branches still scan the table.\n// Self-edges (same-note anchors) are excluded here so PageRank mass is not self-recycled --\n// Obsidian's own graph view hides self-loops too. The rows themselves stay in the table for\n// backlinks/peek. Exported (not just linkEdges below) so commands/signals.ts's async caller,\n// which only has the Store's prepare(), can run the identical statement itself.\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// remove()/store() have already deleted rows by the time afterReconcile runs, so this records\n// whether any reconcile pass deleted at least one link row -- whether a file vanished, or a\n// reparse's stale rows shrank. dstChanged alone misses the reparsed-to-zero-links case (no\n// surviving rows to re-resolve). Keyed on the delta object, so the state dies with the reconcile.\nconst removedWithLinks = new WeakMap<ReconcileDelta, boolean>();\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() below instead of wiped here: deleting and re-inserting\n // resets dst to NULL, which made every touch-only reparse read as an edge change and\n // recompute PageRank -- measured as most of the remaining update cost. Only genuinely\n // vanished files clear here.\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 (existing target/embed pairs the new parse no longer contains) are real edge\n // removals; diffed in JS from one bulk SELECT rather than a per-file NOT IN statement, so\n // this whole 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 // Upsert preserves dst on surviving rows, so an unchanged link resolves to the same value\n // and reports no change; only genuinely new rows start at NULL. A same-note anchor's dst is\n // always its own src, never another file's basename, so it gets no target_base -- SQL's\n // `IN` never matches NULL, keeping it out of resolveIncremental's target_base lookup.\n const upsertRows: unknown[][] = [];\n for (const [path, targets] of byPath) {\n for (const { target, embed } of targets) upsertRows.push([path, target, target.startsWith('#') ? null : baseKey(cleanTarget(target)), embed ? 1 : 0]);\n }\n if (upsertRows.length > 0) {\n await db.runBatch('INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, NULL, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base', upsertRows);\n }\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 const churn = delta.reparsed.length + delta.vanished.length;\n // Past this share of the tree, a full pass is the only one guaranteed to match\n // resolveTarget's ambiguity rules. A cold build clears the threshold on its own.\n const large = delta.files.length === 0 || churn > 0.2 * delta.files.length;\n\n const dstChanged = large ? await resolveAll(db, delta.files) : 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","resolveAll","stmt","prepare","all","selectIn","column","keys","i","chunk","slice","resolveIncremental","delta","changedBasenames","p","collect","added","vanished","reparsed","removedWithLinks","WeakMap","name","schema","remove","vanishedSet","existingRows","filter","store","docs","byPath","addedSet","reparsedExisting","staleRows","upsertRows","targets","d","extracted","some","t","afterReconcile","removeHadLinks","churn","large","dstChanged","linksChanged"],"mappings":"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"}
|
|
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 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// A new or deleted file can change any note's resolution, so re-resolve the whole table.\n// Fallback for cold builds and large deltas -- see afterReconcile's threshold.\nasync function resolveAll(db: Connection, files: FileStat[]): Promise<boolean> {\n const pathSet = new Set(files.map((f) => f.relPath));\n const byBase = buildByBase(files);\n const stmt = await db.prepare('SELECT src, target, dst, embed FROM links');\n const rows = (await stmt.all()) as unknown as LinkRow[];\n const changed = resolveRows(rows, pathSet, byBase);\n await writeResolved(db, changed);\n return changed.length > 0;\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\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 // Upsert preserves dst on surviving rows; only new rows start at NULL. A same-note anchor\n // gets no target_base, so SQL's `IN` excludes it from resolveIncremental's lookup.\n const upsertRows: unknown[][] = [];\n for (const [path, targets] of byPath) {\n for (const { target, embed } of targets) upsertRows.push([path, target, target.startsWith('#') ? null : baseKey(cleanTarget(target)), embed ? 1 : 0]);\n }\n if (upsertRows.length > 0) {\n await db.runBatch('INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, NULL, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base', upsertRows);\n }\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 const churn = delta.reparsed.length + delta.vanished.length;\n // Past this share of the tree, a full pass is the only one guaranteed to match\n // resolveTarget's ambiguity rules. A cold build clears the threshold on its own.\n const large = delta.files.length === 0 || churn > 0.2 * delta.files.length;\n\n const dstChanged = large ? await resolveAll(db, delta.files) : 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","resolveAll","stmt","prepare","all","selectIn","column","keys","i","chunk","slice","resolveIncremental","delta","changedBasenames","p","collect","added","vanished","reparsed","removedWithLinks","WeakMap","name","schema","remove","vanishedSet","existingRows","filter","store","docs","byPath","addedSet","reparsedExisting","staleRows","upsertRows","targets","d","extracted","some","t","afterReconcile","removeHadLinks","churn","large","dstChanged","linksChanged"],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "sections", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
var _indexts = require("../chunk/index.js");
|
|
12
|
-
var
|
|
12
|
+
var _frontmatterts = require("../scan/frontmatter.js");
|
|
13
13
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
14
14
|
try {
|
|
15
15
|
var info = gen[key](arg);
|
|
@@ -135,26 +135,26 @@ function _ts_generator(thisArg, body) {
|
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
var
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
var
|
|
147
|
-
|
|
148
|
-
level:
|
|
149
|
-
heading:
|
|
150
|
-
startLine:
|
|
151
|
-
endLine:
|
|
138
|
+
// Heading blocks parse() already found (mdast/CommonMark fences), offset back onto the raw file;
|
|
139
|
+
// a section runs to just before the next heading, or EOF.
|
|
140
|
+
function sectionsFromBlocks(blocks, raw, body) {
|
|
141
|
+
var rawLines = raw.split('\n');
|
|
142
|
+
var offset = rawLines.length - (0, _frontmatterts.countLines)(body);
|
|
143
|
+
var found = blocks.filter(function(b) {
|
|
144
|
+
return b.type === 'heading';
|
|
145
|
+
}).map(function(b) {
|
|
146
|
+
var _b_depth, _b_text;
|
|
147
|
+
return {
|
|
148
|
+
level: (_b_depth = b.depth) !== null && _b_depth !== void 0 ? _b_depth : 1,
|
|
149
|
+
heading: ((_b_text = b.text) !== null && _b_text !== void 0 ? _b_text : '').trim(),
|
|
150
|
+
startLine: b.startLine + offset,
|
|
151
|
+
endLine: rawLines.length,
|
|
152
152
|
tokens: 0
|
|
153
|
-
}
|
|
154
|
-
}
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
155
|
for(var s = 0; s < found.length; s++){
|
|
156
156
|
if (s + 1 < found.length) found[s].endLine = found[s + 1].startLine - 1;
|
|
157
|
-
var text =
|
|
157
|
+
var text = rawLines.slice(found[s].startLine - 1, found[s].endLine).join('\n');
|
|
158
158
|
found[s].tokens = Math.ceil((0, _indexts.estimateTokens)(text));
|
|
159
159
|
}
|
|
160
160
|
return found;
|
|
@@ -179,7 +179,9 @@ var sections = {
|
|
|
179
179
|
});
|
|
180
180
|
})();
|
|
181
181
|
},
|
|
182
|
-
extract: extract,
|
|
182
|
+
extract: function extract(raw, body, _search, _data, _cfg, blocks) {
|
|
183
|
+
return sectionsFromBlocks(blocks !== null && blocks !== void 0 ? blocks : (0, _indexts.parse)(body), raw, body);
|
|
184
|
+
},
|
|
183
185
|
remove: function remove(db, paths) {
|
|
184
186
|
return _async_to_generator(function() {
|
|
185
187
|
return _ts_generator(this, function(_state) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/sections.ts"],"sourcesContent":["import { estimateTokens } from '../chunk/index.ts';\nimport {
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 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 (mdast/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\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 if (rows.length === 0) return;\n await db.runBatch('INSERT INTO sections (\"path\", idx, level, heading, start_line, end_line, tokens) VALUES (?, ?, ?, ?, ?, ?, ?)', 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","name","schema","db","exec","extract","_search","_data","_cfg","parse","remove","paths","runBatch","p","store","docs","rows","path","extracted","forEach","idx","push"],"mappings":";;;;+BA8BaA;;;eAAAA;;;uBA7ByB;6BACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAc3B,iGAAiG;AACjG,0DAA0D;AAC1D,SAASC,mBAAmBC,MAAe,EAAEC,GAAW,EAAEC,IAAY;IACpE,IAAMC,WAAWF,IAAIG,KAAK,CAAC;IAC3B,IAAMC,SAASF,SAASG,MAAM,GAAGC,IAAAA,yBAAU,EAACL;IAC5C,IAAMM,QAAmBR,OAAOS,MAAM,CAAC,SAACC;eAAMA,EAAEC,IAAI,KAAK;OAAWC,GAAG,CAAC,SAACF;YAAgBA,UAAwBA;eAAjC;YAAEG,KAAK,GAAEH,WAAAA,EAAEI,KAAK,cAAPJ,sBAAAA,WAAW;YAAGK,SAAS,EAACL,UAAAA,EAAEM,IAAI,cAANN,qBAAAA,UAAU,IAAIO,IAAI;YAAIC,WAAWR,EAAEQ,SAAS,GAAGb;YAAQc,SAAShB,SAASG,MAAM;YAAEc,QAAQ;QAAE;;IAC5M,IAAK,IAAIC,IAAI,GAAGA,IAAIb,MAAMF,MAAM,EAAEe,IAAK;QACrC,IAAIA,IAAI,IAAIb,MAAMF,MAAM,EAAEE,KAAK,CAACa,EAAE,CAACF,OAAO,GAAGX,KAAK,CAACa,IAAI,EAAE,CAACH,SAAS,GAAG;QACtE,IAAMF,OAAOb,SAASmB,KAAK,CAACd,KAAK,CAACa,EAAE,CAACH,SAAS,GAAG,GAAGV,KAAK,CAACa,EAAE,CAACF,OAAO,EAAEI,IAAI,CAAC;QAC3Ef,KAAK,CAACa,EAAE,CAACD,MAAM,GAAGI,KAAKC,IAAI,CAACC,IAAAA,uBAAc,EAACV;IAC7C;IACA,OAAOR;AACT;AAEO,IAAMV,WAAoB;IAC/B6B,MAAM;IACAC,QAAN,SAAMA,OAAOC,EAAE;;;;;wBACb;;4BAAMA,GAAGC,IAAI,CAAC;;;wBAAd;;;;;;QACF;;IACAC,SAAAA,SAAAA,QAAQ9B,GAAG,EAAEC,IAAI,EAAE8B,OAAO,EAAEC,KAAK,EAAEC,IAAI,EAAElC,MAAM;QAC7C,OAAOD,mBAAmBC,mBAAAA,oBAAAA,SAAUmC,IAAAA,cAAK,EAACjC,OAAOD,KAAKC;IACxD;IACMkC,QAAN,SAAMA,OAAOP,EAAE,EAAEQ,KAAK;;;;;wBACpB,IAAIA,MAAM/B,MAAM,KAAK,GAAG;;;wBACxB;;4BAAMuB,GAAGS,QAAQ,CACf,yCACAD,MAAMzB,GAAG,CAAC,SAAC2B;uCAAM;oCAACA;iCAAE;;;;wBAFtB;;;;;;QAIF;;IACMC,OAAN,SAAMA,MAAMX,EAAE,EAAEY,IAAI;;gBACZC,MACD,2BAAA,mBAAA,uBAAA,WAAA;;;;wBADCA;wBACD,kCAAA,2BAAA;;;gCAAA,kBAAA,aAAQC,mBAAAA,MAAMC,wBAAAA;gCAAsBA,UAAwBC,OAAO,CAAC,SAACxB,GAAGyB;2CAAQJ,KAAKK,IAAI,CAAC;wCAACJ;wCAAMG;wCAAKzB,EAAER,KAAK;wCAAEQ,EAAEN,OAAO;wCAAEM,EAAEH,SAAS;wCAAEG,EAAEF,OAAO;wCAAEE,EAAED,MAAM;qCAAC;;;4BAAhK,IAAK,YAA6BqB,2BAA7B,6BAAA,QAAA,yBAAA;;4BAAA;4BAAA;;;qCAAA,6BAAA;oCAAA;;;oCAAA;0CAAA;;;;wBACL,IAAIC,KAAKpC,MAAM,KAAK,GAAG;;;wBACvB;;4BAAMuB,GAAGS,QAAQ,CAAC,iHAAiHI;;;wBAAnI;;;;;;QACF;;AACF"}
|
|
@@ -162,8 +162,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
162
162
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
163
163
|
}
|
|
164
164
|
// tags(path, tag): Obsidian's file.tags grain -- frontmatter list/string tags plus inline
|
|
165
|
-
// #tags
|
|
166
|
-
// (book/scifi); `tag = 'book' OR tag LIKE 'book/%'` is how a caller matches the parent too.
|
|
165
|
+
// #tags, deduplicated, source not distinguished. Nested tags store full (book/scifi); `tag = 'book' OR tag LIKE 'book/%'` matches the parent too.
|
|
167
166
|
// Obsidian treats [[#Heading]] as a same-note link, not a tag.
|
|
168
167
|
var WIKILINK_RE = /\[\[.*?\]\]/g; // to the first ]], so a heading holding a lone ] still masks
|
|
169
168
|
// Obsidian doesn't read tags inside HTML markup.
|
|
@@ -211,9 +210,8 @@ function frontmatterTags(data) {
|
|
|
211
210
|
}
|
|
212
211
|
return found;
|
|
213
212
|
}
|
|
214
|
-
// #tag tokens outside
|
|
215
|
-
//
|
|
216
|
-
// concerns (and code spans, masked once there); this loop only does per-line tag extraction.
|
|
213
|
+
// #tag tokens outside the regions maskRegions() masks (fences, code spans, wikilinks, HTML,
|
|
214
|
+
// comments, link destinations); this loop only does per-line tag extraction.
|
|
217
215
|
function inlineTags(body) {
|
|
218
216
|
var found = [];
|
|
219
217
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
@@ -299,9 +297,8 @@ var tags = {
|
|
|
299
297
|
})();
|
|
300
298
|
},
|
|
301
299
|
extract: extract,
|
|
302
|
-
remove: // Blanket clear-then-reinsert (store()
|
|
303
|
-
//
|
|
304
|
-
// per-file NOT IN diffing, which cannot be expressed as one statement shared across files.
|
|
300
|
+
remove: // Blanket clear-then-reinsert (store() always writes the full found list back), so remove()
|
|
301
|
+
// covers vanished and reparsed files without per-file NOT IN diffing, which cannot be one statement shared across files.
|
|
305
302
|
function remove(db, paths) {
|
|
306
303
|
return _async_to_generator(function() {
|
|
307
304
|
return _ts_generator(this, function(_state) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/tags.ts"],"sourcesContent":["import { 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
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/tags.ts"],"sourcesContent":["import { 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 if (rows.length === 0) return;\n await db.runBatch('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"],"mappings":";;;;+BA2DaA;;;eAAAA;;;wBA3De;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG5B,0FAA0F;AAC1F,kJAAkJ;AAElJ,+DAA+D;AAC/D,IAAMC,cAAc,gBAAgB,6DAA6D;AACjG,iDAAiD;AACjD,IAAMC,cAAc,uBAAuB,6DAA6D;AACxG,iGAAiG;AACjG,IAAMC,gBAAgB;AACtB,4FAA4F;AAC5F,IAAMC,eAAe,gCAAgC,oFAAoF;AAEzI,sFAAsF;AACtF,oEAAoE;AACpE,SAASC,aAAaC,GAAW;IAC/B,IAAMC,WAAWD,IAAIE,OAAO,CAAC,MAAM,IAAIA,OAAO,CAAC,QAAQ;IACvD,IAAI,CAACD,YAAY,QAAQE,IAAI,CAACF,WAAW,OAAO;IAChD,OAAOA;AACT;AAEA,4FAA4F;AAC5F,6EAA6E;AAC7E,SAASG,gBAAgBC,IAA8B;IACrD,IAAML,MAAMK,iBAAAA,2BAAAA,KAAMX,IAAI;IACtB,IAAMY,OAAOC,MAAMC,OAAO,CAACR,OAAOA,MAAM,OAAOA,QAAQ,WAAW;QAACA;KAAI,GAAG,EAAE;IAC5E,IAAMS,QAAkB,EAAE;QACrB,kCAAA,2BAAA;;QAAL,QAAK,YAAcH,yBAAd,SAAA,6BAAA,QAAA,yBAAA,iCAAoB;YAApB,IAAMI,OAAN;YACH,IAAI,OAAOA,SAAS,UAAU;YAC9B,IAAMC,MAAMZ,aAAaW;YACzB,IAAIC,KAAKF,MAAMG,IAAI,CAACD;QACtB;;QAJK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAKL,OAAOF;AACT;AAEA,4FAA4F;AAC5F,6EAA6E;AAC7E,SAASI,WAAWC,IAAY;IAC9B,IAAML,QAAkB,EAAE;QACrB,kCAAA,2BAAA;;QAAL,QAAK,YAAcM,IAAAA,qBAAW,EAACD,MAAME,KAAK,CAAC,0BAAtC,SAAA,6BAAA,QAAA,yBAAA,iCAA6C;YAA7C,IAAMC,OAAN;YACH,IAAI,CAACA,KAAKC,QAAQ,CAAC,MAAM,UAAU,kCAAkC;YACrE,IAAIC,UAAUF;YACd,IAAIE,QAAQD,QAAQ,CAAC,OAAOC,UAAUA,QAAQjB,OAAO,CAACP,aAAa,SAACyB;uBAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;;YAC7F,IAAIH,QAAQD,QAAQ,CAAC,OAAOC,UAAUA,QAAQjB,OAAO,CAACJ,cAAc,SAACsB;uBAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;;YAC9F,IAAIH,QAAQD,QAAQ,CAAC,MAAMC,UAAUA,QAAQjB,OAAO,CAACN,aAAa,SAACwB;uBAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;;gBACvF,mCAAA,4BAAA;;gBAAL,QAAK,aAAWH,QAAQI,QAAQ,CAAC1B,mCAA5B,UAAA,8BAAA,SAAA,0BAAA,kCAA4C;oBAA5C,IAAMuB,IAAN;oBACH,IAAMT,MAAMZ,aAAaqB,CAAC,CAAC,EAAE;oBAC7B,IAAIT,KAAKF,MAAMG,IAAI,CAACD;gBACtB;;gBAHK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAIP;;QAVK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAWL,OAAOF;AACT;AAEA,SAASe,QAAQC,IAAY,EAAEX,IAAY,EAAEY,OAA4C,EAAErB,IAA8B;IACvH,OAAO,AAAC,qBAAG,IAAIsB,IAAI,AAAC,qBAAGvB,gBAAgBC,cAAO,qBAAGQ,WAAWC,UAASc,IAAI;AAC3E;AAEO,IAAMlC,OAAgB;IAC3BmC,MAAM;IACAC,QAAN,SAAMA,OAAOC,EAAE;;;;;wBACb;;4BAAMA,GAAGC,IAAI,CAAC;;;wBAAd;wBACA;;4BAAMD,GAAGC,IAAI,CAAC;;;wBAAd;;;;;;QACF;;IACAR,SAAAA;IAGMS,QAFN,4FAA4F;IAC5F,yHAAyH;IACzH,SAAMA,OAAOF,EAAE,EAAEG,KAAK;;;;;wBACpB,IAAIA,MAAMZ,MAAM,KAAK,GAAG;;;wBACxB;;4BAAMS,GAAGI,QAAQ,CACf,qCACAD,MAAME,GAAG,CAAC,SAACC;uCAAM;oCAACA;iCAAE;;;;wBAFtB;;;;;;QAIF;;IACMC,OAAN,SAAMA,MAAMP,EAAE,EAAEQ,IAAI;;gBACZC,MACuC,2BAAA,mBAAA,gBAAxC,4BAAA,oBAAA,iBAAA,WAAA,oBAAQC,MAAMC,WAA0B,YAAA,QAAM/B;;;;wBAD7C6B;wBACuC,kCAAA,2BAAA,4BAAxC,mCAAA,4BAAA;;4BAAL,IAAK,YAA6BD,2BAA7B,8BAAA,QAAA,yBAAA;8CAAA,aAAQE,mBAAAA,MAAMC,wBAAAA;;oCAAqB,IAAK,aAAaA,gCAAb,6BAAA,SAAA,0BAAA;wCAAM/B,MAAN;wCAAoC6B,KAAK5B,IAAI;4CAAE6B;4CAAM9B;;;;oCAArD;oCAAA;;;6CAAA,6BAAA;4CAAA;;;4CAAA;kDAAA;;;;;;4BAAxC;4BAAA;;;qCAAA,8BAAA;oCAAA;;;oCAAA;0CAAA;;;;wBACL,IAAI6B,KAAKlB,MAAM,KAAK,GAAG;;;wBACvB;;4BAAMS,GAAGI,QAAQ,CAAC,0DAA0DK;;;wBAA5E;;;;;;QACF;;AACF"}
|
|
@@ -234,8 +234,7 @@ function candidateSelect(direction) {
|
|
|
234
234
|
return "".concat(forward, " UNION ALL ").concat(reverse);
|
|
235
235
|
}
|
|
236
236
|
// One ring: candidates adjacent to the previous ring's frontier (?1), anti-joined against
|
|
237
|
-
// everything already visited, optionally filtered to the allowed set,
|
|
238
|
-
// new depth (?2). RETURNING hands back exactly what this ring newly reached.
|
|
237
|
+
// everything already visited, optionally filtered to the allowed set, inserted at the new depth (?2); RETURNING gives what this ring newly reached.
|
|
239
238
|
function ringSql(direction, hasAllowed) {
|
|
240
239
|
return "\nINSERT INTO visited (path, depth, pred)\nSELECT cand.path, ?2, MIN(cand.pred)\nFROM (".concat(candidateSelect(direction), ") cand\nWHERE NOT EXISTS (SELECT 1 FROM visited v2 WHERE v2.path = cand.path)\n").concat(hasAllowed ? 'AND EXISTS (SELECT 1 FROM allowed_nodes a WHERE a.path = cand.path)' : '', "\nGROUP BY cand.path\nORDER BY cand.path\nRETURNING path");
|
|
241
240
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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.\nimport type { Store } from '../store/types.ts';\n\ntype Direction = 'forward' | 'reverse' | 'both';\n\ninterface 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,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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.\nimport type { Store } from '../store/types.ts';\n\ntype Direction = 'forward' | 'reverse' | 'both';\n\ninterface 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 async function findPath(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","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","maxDepth","insertStart","stmt","ring","rows","directed","Infinity","run","length","some"],"mappings":"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"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands/index.js';
|
|
2
2
|
export { mapTree, peek, presetCoverage, search } from './commands/index.js';
|
|
3
3
|
export type { Config, EmbedConfig, FeatureName, InitOverrides, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.js';
|
|
4
|
-
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
4
|
+
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
5
5
|
export type { SenseErrorCode } from './errors.js';
|
|
6
6
|
export { SenseError } from './errors.js';
|
|
7
7
|
export type { Format, Row, RowFormat } from './output/output.js';
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands/index.js';
|
|
2
2
|
export { mapTree, peek, presetCoverage, search } from './commands/index.js';
|
|
3
3
|
export type { Config, EmbedConfig, FeatureName, InitOverrides, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.js';
|
|
4
|
-
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
4
|
+
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
5
5
|
export type { SenseErrorCode } from './errors.js';
|
|
6
6
|
export { SenseError } from './errors.js';
|
|
7
7
|
export type { Format, Row, RowFormat } from './output/output.js';
|
package/dist/cjs/index.js
CHANGED
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands/index.ts';\nexport { mapTree, peek, presetCoverage, search } from './commands/index.ts';\nexport type { Config, EmbedConfig, FeatureName, InitOverrides, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, 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 { OpenResult } from './store/index.ts';\nexport { 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":["CONFIG_FILENAME","SIGNAL_NAMES","STATE_DIR","SUPPORTED_CONFIG_VERSION","SenseError","clearCache","initConfig","loadConfig","mapTree","migrateConfig","open","openStore","peek","presetCoverage","printRows","runWatch","search"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;;;;;;;;;;;;QAK9DA;eAAAA,yBAAe;;QAAyCC;eAAAA,sBAAY;;QAAEC;eAAAA,mBAAS;;QAAEC;eAAAA,kCAAwB;;
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands/index.ts';\nexport { mapTree, peek, presetCoverage, search } from './commands/index.ts';\nexport type { Config, EmbedConfig, FeatureName, InitOverrides, 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 { OpenResult } from './store/index.ts';\nexport { 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":["CONFIG_FILENAME","SIGNAL_NAMES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION","SenseError","clearCache","initConfig","loadConfig","mapTree","migrateConfig","open","openStore","peek","presetCoverage","printRows","runWatch","search"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;;;;;;;;;;;;QAK9DA;eAAAA,yBAAe;;QAAyCC;eAAAA,sBAAY;;QAAEC;eAAAA,mBAAS;;QAAEC;eAAAA,qBAAW;;QAAEC;eAAAA,kCAAwB;;QAEtHC;eAAAA,oBAAU;;QAIVC;eAAAA,oBAAU;;QANOC;eAAAA,oBAAU;;QAAEC;eAAAA,oBAAU;;QAFvCC;eAAAA,gBAAO;;QAEkCC;eAAAA,uBAAa;;QAM7BC;eAAbC,mBAAS;;QARZC;eAAAA,aAAI;;QAAEC;eAAAA,uBAAc;;QAM7BC;eAAAA,mBAAS;;QAMTC;eAAAA,iBAAQ;;QAZuBC;eAAAA,eAAM;;;uBAAQ;wBAEiF;wBAE5G;wBAED;wBAEoB;uBAIrB"}
|
|
@@ -36,9 +36,7 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
36
36
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
37
37
|
}
|
|
38
38
|
// A frontmatter key with punctuation (`plugin-id`, `a.b`) is a real column, but unquoted in SQL
|
|
39
|
-
// it parses as an expression
|
|
40
|
-
// (`no such column: plugin`), DuckDB names the fragment or the table (`Referenced column/table
|
|
41
|
-
// "..." not found`); this maps either back to the real column so the error names the fix.
|
|
39
|
+
// it parses as an expression; this maps SQLite's/DuckDB's fragment error back to the real column.
|
|
42
40
|
function startsWithBoundary(name, prefix) {
|
|
43
41
|
return name.length > prefix.length && name.startsWith(prefix) && /\W/.test(name[prefix.length]);
|
|
44
42
|
}
|
|
@@ -47,9 +45,8 @@ function columnHint(columns, err) {
|
|
|
47
45
|
var match = /no such column: (\S+)|Referenced column "([^"]+)" not found in FROM clause|Referenced table "([^"]+)" not found/.exec(err.message);
|
|
48
46
|
if (!match) return err;
|
|
49
47
|
var token = (_ref = (_match_ = match[1]) !== null && _match_ !== void 0 ? _match_ : match[2]) !== null && _ref !== void 0 ? _ref : match[3];
|
|
50
|
-
// `f.plugin` -> `plugin`; left as-is when there's no leading alias segment,
|
|
51
|
-
//
|
|
52
|
-
// directly, so stripping here never needs to special-case it.
|
|
48
|
+
// `f.plugin` -> `plugin`; left as-is when there's no leading alias segment, so a column
|
|
49
|
+
// literally named `a.b` still matches via the full-token check below.
|
|
53
50
|
var aliasStripped = token.replace(/^[A-Za-z_]\w*\./, '');
|
|
54
51
|
var forms = new Set([
|
|
55
52
|
token,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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"}
|
|
@@ -278,13 +278,12 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
278
278
|
}
|
|
279
279
|
// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.
|
|
280
280
|
var OVERSIZE_BYTES = 50000;
|
|
281
|
-
// Flatten embedded newlines so they can't break table column alignment; JSON output
|
|
281
|
+
// Flatten embedded newlines so they can't break table column alignment; JSON output keeps them as-is.
|
|
282
282
|
function cell(value) {
|
|
283
283
|
return String(value !== null && value !== void 0 ? value : '').replace(/\s*\n\s*/g, ' ');
|
|
284
284
|
}
|
|
285
|
-
// RFC 4180,
|
|
286
|
-
//
|
|
287
|
-
// NULL vs empty string, or a value's type -- that is what json is for.
|
|
285
|
+
// RFC 4180, deliberately not cell(): csv is the redirect-to-file format, so it keeps every
|
|
286
|
+
// character, newlines included; what it cannot carry (NULL vs empty, types) is what json is for.
|
|
288
287
|
function csvField(value) {
|
|
289
288
|
var text = value === null || value === undefined ? '' : String(value);
|
|
290
289
|
return /["\r\n,]/.test(text) ? '"'.concat(text.replace(/"/g, '""'), '"') : text;
|
|
@@ -296,14 +295,8 @@ function warnOversize(bytes, rowCount) {
|
|
|
296
295
|
if (bytes <= OVERSIZE_BYTES) return;
|
|
297
296
|
console.warn("warning: result is ".concat(Math.round(bytes / 1000), " KB across ").concat(rowCount, " row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file"));
|
|
298
297
|
}
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with
|
|
302
|
-
// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --
|
|
303
|
-
// a bare newline would read to a csv parser as one empty record.
|
|
304
|
-
// JSON.stringify throws on BigInt, and stores return int64 as BigInt (DuckDB does). A value
|
|
305
|
-
// that fits a safe integer stays a number; a larger one becomes its decimal string, since a
|
|
306
|
-
// JSON number cannot carry it losslessly.
|
|
298
|
+
// JSON.stringify throws on BigInt, and stores return int64 as BigInt (DuckDB does): a value
|
|
299
|
+
// that fits a safe integer stays a number, a larger one becomes its decimal string.
|
|
307
300
|
var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
308
301
|
var bigintSafe = function bigintSafe(_key, value) {
|
|
309
302
|
return (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'bigint' ? value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString() : value;
|
|
@@ -313,8 +306,8 @@ function stringifyJson(value, indent) {
|
|
|
313
306
|
}
|
|
314
307
|
function printRows(rows, format, columns) {
|
|
315
308
|
if (format === 'csv') {
|
|
316
|
-
//
|
|
317
|
-
//
|
|
309
|
+
// Names from a row wherever there is one: the statement's column list keeps duplicates the
|
|
310
|
+
// row collapsed. Nothing at all with no row and no columns -- a bare newline is an empty record.
|
|
318
311
|
var names = rows.length > 0 ? Object.keys(rows[0]) : _to_consumable_array(new Set(columns !== null && columns !== void 0 ? columns : []));
|
|
319
312
|
if (names.length === 0) return;
|
|
320
313
|
var rendered = [
|