sensemaking 0.17.0 → 0.18.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 +15 -13
- package/dist/cjs/cli/map.js +147 -6
- package/dist/cjs/cli/map.js.map +1 -1
- package/dist/cjs/cli/named.js +20 -12
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/path.js +190 -29
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/peek.js +148 -7
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js +5 -5
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/cli/search.js +5 -5
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/cli/shared.d.cts +3 -3
- package/dist/cjs/cli/shared.d.ts +3 -3
- package/dist/cjs/cli/shared.js +156 -58
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/sql.js +151 -10
- package/dist/cjs/cli/sql.js.map +1 -1
- package/dist/cjs/cli/status.js +187 -62
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/map.d.cts +2 -2
- package/dist/cjs/commands/map.d.ts +2 -2
- package/dist/cjs/commands/map.js +373 -67
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/peek.d.cts +2 -2
- package/dist/cjs/commands/peek.d.ts +2 -2
- package/dist/cjs/commands/peek.js +321 -79
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.d.cts +2 -2
- package/dist/cjs/commands/related.d.ts +2 -2
- package/dist/cjs/commands/related.js +55 -10
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.d.cts +7 -7
- package/dist/cjs/commands/scope.d.ts +7 -7
- package/dist/cjs/commands/scope.js +382 -45
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.d.cts +2 -2
- package/dist/cjs/commands/search.d.ts +2 -2
- package/dist/cjs/commands/search.js +292 -99
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +4 -10
- package/dist/cjs/commands/signals.d.ts +4 -10
- package/dist/cjs/commands/signals.js +91 -45
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/commands/status.d.cts +2 -2
- package/dist/cjs/commands/status.d.ts +2 -2
- package/dist/cjs/commands/status.js +247 -10
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config/access.d.cts +1 -0
- package/dist/cjs/config/access.d.ts +1 -0
- package/dist/cjs/config/access.js +7 -0
- 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/types.d.cts +1 -0
- package/dist/cjs/config/types.d.ts +1 -0
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js +10 -1
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/distribution.d.cts +4 -0
- package/dist/cjs/embed/distribution.d.ts +4 -0
- package/dist/cjs/embed/distribution.js +186 -0
- package/dist/cjs/embed/distribution.js.map +1 -0
- package/dist/cjs/embed/langfit.d.cts +2 -5
- package/dist/cjs/embed/langfit.d.ts +2 -5
- package/dist/cjs/embed/langfit.js +73 -63
- package/dist/cjs/embed/langfit.js.map +1 -1
- package/dist/cjs/embed/query.d.cts +6 -13
- package/dist/cjs/embed/query.d.ts +6 -13
- package/dist/cjs/embed/query.js +56 -168
- package/dist/cjs/embed/query.js.map +1 -1
- package/dist/cjs/embed/static.js +13 -3
- package/dist/cjs/embed/static.js.map +1 -1
- package/dist/cjs/embed/types.d.cts +1 -0
- package/dist/cjs/embed/types.d.ts +1 -0
- package/dist/cjs/embed/types.js +11 -2
- 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 +218 -11
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/index.d.cts +1 -1
- package/dist/cjs/features/index.d.ts +1 -1
- package/dist/cjs/features/index.js +6 -0
- package/dist/cjs/features/index.js.map +1 -1
- package/dist/cjs/features/links.d.cts +7 -2
- package/dist/cjs/features/links.d.ts +7 -2
- package/dist/cjs/features/links.js +710 -198
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/rank.js +231 -31
- package/dist/cjs/features/rank.js.map +1 -1
- package/dist/cjs/features/sections.js +218 -8
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/features/tags.js +236 -40
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/features/types.d.cts +9 -5
- package/dist/cjs/features/types.d.ts +9 -5
- package/dist/cjs/graph/traverse.d.cts +2 -2
- package/dist/cjs/graph/traverse.d.ts +2 -2
- package/dist/cjs/graph/traverse.js +321 -42
- package/dist/cjs/graph/traverse.js.map +1 -1
- package/dist/cjs/index.d.cts +3 -2
- package/dist/cjs/index.d.ts +3 -2
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/guarded-tick.d.cts +1 -0
- package/dist/cjs/lib/guarded-tick.d.ts +1 -0
- package/dist/cjs/lib/guarded-tick.js +19 -0
- package/dist/cjs/lib/guarded-tick.js.map +1 -0
- package/dist/cjs/output/column-hint.d.cts +1 -2
- package/dist/cjs/output/column-hint.d.ts +1 -2
- package/dist/cjs/output/column-hint.js +1 -4
- package/dist/cjs/output/column-hint.js.map +1 -1
- package/dist/cjs/output/output.d.cts +2 -1
- package/dist/cjs/output/output.d.ts +2 -1
- package/dist/cjs/output/output.js +515 -97
- package/dist/cjs/output/output.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/reparse.d.cts +10 -0
- package/dist/cjs/scan/reparse.d.ts +10 -0
- package/dist/cjs/scan/reparse.js +104 -0
- package/dist/cjs/scan/reparse.js.map +1 -0
- package/dist/cjs/store/duckdb/batch.d.cts +16 -0
- package/dist/cjs/store/duckdb/batch.d.ts +16 -0
- package/dist/cjs/store/duckdb/batch.js +208 -0
- package/dist/cjs/store/duckdb/batch.js.map +1 -0
- package/dist/cjs/store/duckdb/connection.d.cts +5 -0
- package/dist/cjs/store/duckdb/connection.d.ts +5 -0
- package/dist/cjs/store/duckdb/connection.js +772 -0
- package/dist/cjs/store/duckdb/connection.js.map +1 -0
- package/dist/cjs/store/duckdb/lexical.d.cts +10 -0
- package/dist/cjs/store/duckdb/lexical.d.ts +10 -0
- package/dist/cjs/store/duckdb/lexical.js +502 -0
- package/dist/cjs/store/duckdb/lexical.js.map +1 -0
- package/dist/cjs/store/duckdb/native.d.cts +3 -0
- package/dist/cjs/store/duckdb/native.d.ts +3 -0
- package/dist/cjs/store/duckdb/native.js +360 -0
- package/dist/cjs/store/duckdb/native.js.map +1 -0
- package/dist/cjs/store/duckdb/open.d.cts +12 -0
- package/dist/cjs/store/duckdb/open.d.ts +12 -0
- package/dist/cjs/store/duckdb/open.js +501 -0
- package/dist/cjs/store/duckdb/open.js.map +1 -0
- package/dist/cjs/store/duckdb/reconcile.d.cts +6 -0
- package/dist/cjs/store/duckdb/reconcile.d.ts +6 -0
- package/dist/cjs/store/duckdb/reconcile.js +753 -0
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -0
- package/dist/cjs/store/duckdb/sql-functions.d.cts +2 -0
- package/dist/cjs/store/duckdb/sql-functions.d.ts +2 -0
- package/dist/cjs/store/duckdb/sql-functions.js +203 -0
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -0
- package/dist/cjs/store/duckdb/store.d.cts +5 -0
- package/dist/cjs/store/duckdb/store.d.ts +5 -0
- package/dist/cjs/store/duckdb/store.js +504 -0
- package/dist/cjs/store/duckdb/store.js.map +1 -0
- package/dist/cjs/store/duckdb/vectors.d.cts +9 -0
- package/dist/cjs/store/duckdb/vectors.d.ts +9 -0
- package/dist/cjs/store/duckdb/vectors.js +502 -0
- package/dist/cjs/store/duckdb/vectors.js.map +1 -0
- package/dist/cjs/store/index.d.cts +7 -0
- package/dist/cjs/store/index.d.ts +7 -0
- package/dist/cjs/store/index.js +201 -0
- package/dist/cjs/store/index.js.map +1 -0
- package/dist/cjs/store/meta.d.cts +3 -0
- package/dist/cjs/store/meta.d.ts +3 -0
- package/dist/cjs/store/meta.js +215 -0
- package/dist/cjs/store/meta.js.map +1 -0
- package/dist/cjs/store/shared.d.cts +5 -0
- package/dist/cjs/store/shared.d.ts +5 -0
- package/dist/cjs/store/shared.js +252 -0
- package/dist/cjs/store/shared.js.map +1 -0
- package/dist/cjs/store/sql-functions.d.cts +2 -0
- package/dist/cjs/store/sql-functions.d.ts +2 -0
- package/dist/cjs/store/sql-functions.js +48 -0
- package/dist/cjs/store/sql-functions.js.map +1 -0
- package/dist/cjs/store/sqlite/connection.d.cts +3 -0
- package/dist/cjs/store/sqlite/connection.d.ts +3 -0
- package/dist/cjs/store/sqlite/connection.js +516 -0
- package/dist/cjs/store/sqlite/connection.js.map +1 -0
- package/dist/cjs/store/sqlite/lexical.d.cts +2 -0
- package/dist/cjs/store/sqlite/lexical.d.ts +2 -0
- package/dist/cjs/store/sqlite/lexical.js +177 -0
- package/dist/cjs/store/sqlite/lexical.js.map +1 -0
- package/dist/cjs/{db → store/sqlite}/open.d.cts +5 -5
- package/dist/cjs/{db → store/sqlite}/open.d.ts +5 -5
- package/dist/cjs/store/sqlite/open.js +604 -0
- package/dist/cjs/store/sqlite/open.js.map +1 -0
- package/dist/cjs/store/sqlite/reconcile.d.cts +10 -0
- package/dist/cjs/store/sqlite/reconcile.d.ts +10 -0
- package/dist/cjs/store/sqlite/reconcile.js +1020 -0
- package/dist/cjs/store/sqlite/reconcile.js.map +1 -0
- package/dist/cjs/store/sqlite/sql-functions.js +34 -0
- package/dist/cjs/store/sqlite/sql-functions.js.map +1 -0
- package/dist/cjs/store/sqlite/store.d.cts +5 -0
- package/dist/cjs/store/sqlite/store.d.ts +5 -0
- package/dist/cjs/store/sqlite/store.js +588 -0
- package/dist/cjs/store/sqlite/store.js.map +1 -0
- package/dist/cjs/store/sqlite/vectors.d.cts +13 -0
- package/dist/cjs/store/sqlite/vectors.d.ts +13 -0
- package/dist/cjs/store/sqlite/vectors.js +470 -0
- package/dist/cjs/store/sqlite/vectors.js.map +1 -0
- package/dist/cjs/store/transaction.d.cts +5 -0
- package/dist/cjs/store/transaction.d.ts +5 -0
- package/dist/cjs/store/transaction.js +297 -0
- package/dist/cjs/store/transaction.js.map +1 -0
- package/dist/cjs/store/types.d.cts +91 -0
- package/dist/cjs/store/types.d.ts +91 -0
- package/dist/cjs/store/types.js +15 -0
- package/dist/cjs/store/types.js.map +1 -0
- package/dist/cjs/watch.d.cts +3 -0
- package/dist/cjs/watch.d.ts +3 -0
- package/dist/cjs/watch.js +215 -73
- package/dist/cjs/watch.js.map +1 -1
- package/dist/esm/cli/map.js +5 -5
- package/dist/esm/cli/map.js.map +1 -1
- package/dist/esm/cli/named.js +3 -3
- package/dist/esm/cli/named.js.map +1 -1
- package/dist/esm/cli/path.js +6 -5
- package/dist/esm/cli/path.js.map +1 -1
- package/dist/esm/cli/peek.js +5 -5
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/related.js +3 -3
- package/dist/esm/cli/related.js.map +1 -1
- package/dist/esm/cli/search.js +2 -2
- package/dist/esm/cli/search.js.map +1 -1
- package/dist/esm/cli/shared.d.ts +3 -3
- package/dist/esm/cli/shared.js +17 -17
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/sql.js +2 -2
- package/dist/esm/cli/sql.js.map +1 -1
- package/dist/esm/cli/status.js +25 -24
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/map.d.ts +2 -2
- package/dist/esm/commands/map.js +51 -41
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/peek.d.ts +2 -2
- package/dist/esm/commands/peek.js +58 -50
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.d.ts +2 -2
- package/dist/esm/commands/related.js +9 -9
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.d.ts +7 -7
- package/dist/esm/commands/scope.js +28 -17
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.d.ts +2 -2
- package/dist/esm/commands/search.js +42 -35
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +4 -10
- package/dist/esm/commands/signals.js +17 -13
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/commands/status.d.ts +2 -2
- package/dist/esm/commands/status.js +13 -7
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config/access.d.ts +1 -0
- package/dist/esm/config/access.js +5 -0
- 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/types.d.ts +1 -0
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js +10 -1
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/distribution.d.ts +4 -0
- package/dist/esm/embed/distribution.js +11 -0
- package/dist/esm/embed/distribution.js.map +1 -0
- package/dist/esm/embed/langfit.d.ts +2 -5
- package/dist/esm/embed/langfit.js +13 -13
- package/dist/esm/embed/langfit.js.map +1 -1
- package/dist/esm/embed/query.d.ts +6 -13
- package/dist/esm/embed/query.js +23 -84
- package/dist/esm/embed/query.js.map +1 -1
- package/dist/esm/embed/static.js +6 -1
- package/dist/esm/embed/static.js.map +1 -1
- package/dist/esm/embed/types.d.ts +1 -0
- package/dist/esm/embed/types.js +5 -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 +22 -10
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/features/index.d.ts +1 -1
- package/dist/esm/features/index.js +1 -1
- package/dist/esm/features/index.js.map +1 -1
- package/dist/esm/features/links.d.ts +7 -2
- package/dist/esm/features/links.js +124 -97
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/rank.js +15 -8
- package/dist/esm/features/rank.js.map +1 -1
- package/dist/esm/features/sections.js +20 -7
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/features/tags.js +19 -18
- package/dist/esm/features/tags.js.map +1 -1
- package/dist/esm/features/types.d.ts +9 -5
- package/dist/esm/features/types.js +1 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/graph/traverse.d.ts +2 -2
- package/dist/esm/graph/traverse.js +26 -23
- package/dist/esm/graph/traverse.js.map +1 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/guarded-tick.d.ts +1 -0
- package/dist/esm/lib/guarded-tick.js +8 -0
- package/dist/esm/lib/guarded-tick.js.map +1 -0
- package/dist/esm/output/column-hint.d.ts +1 -2
- package/dist/esm/output/column-hint.js +3 -2
- package/dist/esm/output/column-hint.js.map +1 -1
- package/dist/esm/output/output.d.ts +2 -1
- package/dist/esm/output/output.js +27 -23
- package/dist/esm/output/output.js.map +1 -1
- package/dist/esm/scan/frontmatter.js +1 -1
- package/dist/esm/scan/frontmatter.js.map +1 -1
- package/dist/esm/scan/index.js +1 -1
- package/dist/esm/scan/index.js.map +1 -1
- package/dist/esm/scan/reparse.d.ts +10 -0
- package/dist/esm/scan/reparse.js +30 -0
- package/dist/esm/scan/reparse.js.map +1 -0
- package/dist/esm/store/duckdb/batch.d.ts +16 -0
- package/dist/esm/store/duckdb/batch.js +96 -0
- package/dist/esm/store/duckdb/batch.js.map +1 -0
- package/dist/esm/store/duckdb/connection.d.ts +5 -0
- package/dist/esm/store/duckdb/connection.js +97 -0
- package/dist/esm/store/duckdb/connection.js.map +1 -0
- package/dist/esm/store/duckdb/lexical.d.ts +10 -0
- package/dist/esm/store/duckdb/lexical.js +163 -0
- package/dist/esm/store/duckdb/lexical.js.map +1 -0
- package/dist/esm/store/duckdb/native.d.ts +3 -0
- package/dist/esm/store/duckdb/native.js +96 -0
- package/dist/esm/store/duckdb/native.js.map +1 -0
- package/dist/esm/store/duckdb/open.d.ts +12 -0
- package/dist/esm/store/duckdb/open.js +127 -0
- package/dist/esm/store/duckdb/open.js.map +1 -0
- package/dist/esm/store/duckdb/reconcile.d.ts +6 -0
- package/dist/esm/store/duckdb/reconcile.js +141 -0
- package/dist/esm/store/duckdb/reconcile.js.map +1 -0
- package/dist/esm/store/duckdb/sql-functions.d.ts +2 -0
- package/dist/esm/store/duckdb/sql-functions.js +56 -0
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -0
- package/dist/esm/store/duckdb/store.d.ts +5 -0
- package/dist/esm/store/duckdb/store.js +104 -0
- package/dist/esm/store/duckdb/store.js.map +1 -0
- package/dist/esm/store/duckdb/vectors.d.ts +9 -0
- package/dist/esm/store/duckdb/vectors.js +171 -0
- package/dist/esm/store/duckdb/vectors.js.map +1 -0
- package/dist/esm/store/index.d.ts +7 -0
- package/dist/esm/store/index.js +35 -0
- package/dist/esm/store/index.js.map +1 -0
- package/dist/esm/store/meta.d.ts +3 -0
- package/dist/esm/store/meta.js +17 -0
- package/dist/esm/store/meta.js.map +1 -0
- package/dist/esm/store/shared.d.ts +5 -0
- package/dist/esm/store/shared.js +24 -0
- package/dist/esm/store/shared.js.map +1 -0
- package/dist/esm/store/sql-functions.d.ts +2 -0
- package/dist/esm/store/sql-functions.js +29 -0
- package/dist/esm/store/sql-functions.js.map +1 -0
- package/dist/esm/store/sqlite/connection.d.ts +3 -0
- package/dist/esm/store/sqlite/connection.js +50 -0
- package/dist/esm/store/sqlite/connection.js.map +1 -0
- package/dist/esm/store/sqlite/lexical.d.ts +2 -0
- package/dist/esm/store/sqlite/lexical.js +21 -0
- package/dist/esm/store/sqlite/lexical.js.map +1 -0
- package/dist/esm/{db → store/sqlite}/open.d.ts +5 -5
- package/dist/esm/store/sqlite/open.js +193 -0
- package/dist/esm/store/sqlite/open.js.map +1 -0
- package/dist/esm/store/sqlite/reconcile.d.ts +10 -0
- package/dist/esm/{db → store/sqlite}/reconcile.js +101 -99
- package/dist/esm/store/sqlite/reconcile.js.map +1 -0
- package/dist/esm/store/sqlite/sql-functions.js +23 -0
- package/dist/esm/store/sqlite/sql-functions.js.map +1 -0
- package/dist/esm/store/sqlite/store.d.ts +5 -0
- package/dist/esm/store/sqlite/store.js +82 -0
- package/dist/esm/store/sqlite/store.js.map +1 -0
- package/dist/esm/store/sqlite/vectors.d.ts +13 -0
- package/dist/esm/store/sqlite/vectors.js +90 -0
- package/dist/esm/store/sqlite/vectors.js.map +1 -0
- package/dist/esm/store/transaction.d.ts +5 -0
- package/dist/esm/store/transaction.js +57 -0
- package/dist/esm/store/transaction.js.map +1 -0
- package/dist/esm/store/types.d.ts +91 -0
- package/dist/esm/store/types.js +11 -0
- package/dist/esm/store/types.js.map +1 -0
- package/dist/esm/watch.d.ts +3 -0
- package/dist/esm/watch.js +39 -22
- package/dist/esm/watch.js.map +1 -1
- package/package.json +3 -1
- package/schema.json +5 -0
- package/skills/sense/EXAMPLES.md +3 -3
- package/skills/sense/SKILL.md +16 -14
- package/skills/sense-bases/EXAMPLES.md +2 -2
- package/skills/sense-bases/SKILL.md +6 -6
- package/skills/sense-setup/EXAMPLES.md +1 -1
- package/skills/sense-setup/SKILL.md +5 -4
- package/dist/cjs/db/index.d.cts +0 -4
- package/dist/cjs/db/index.d.ts +0 -4
- package/dist/cjs/db/index.js +0 -42
- package/dist/cjs/db/index.js.map +0 -1
- package/dist/cjs/db/open.js +0 -230
- package/dist/cjs/db/open.js.map +0 -1
- package/dist/cjs/db/reconcile.d.cts +0 -10
- package/dist/cjs/db/reconcile.d.ts +0 -10
- package/dist/cjs/db/reconcile.js +0 -579
- package/dist/cjs/db/reconcile.js.map +0 -1
- package/dist/cjs/db/shared.d.cts +0 -5
- package/dist/cjs/db/shared.d.ts +0 -5
- package/dist/cjs/db/shared.js +0 -45
- package/dist/cjs/db/shared.js.map +0 -1
- package/dist/cjs/db/sql-functions.js +0 -64
- package/dist/cjs/db/sql-functions.js.map +0 -1
- package/dist/esm/db/index.d.ts +0 -4
- package/dist/esm/db/index.js +0 -5
- package/dist/esm/db/index.js.map +0 -1
- package/dist/esm/db/open.js +0 -165
- package/dist/esm/db/open.js.map +0 -1
- package/dist/esm/db/reconcile.d.ts +0 -10
- package/dist/esm/db/reconcile.js.map +0 -1
- package/dist/esm/db/shared.d.ts +0 -5
- package/dist/esm/db/shared.js +0 -20
- package/dist/esm/db/shared.js.map +0 -1
- package/dist/esm/db/sql-functions.js +0 -47
- package/dist/esm/db/sql-functions.js.map +0 -1
- /package/dist/cjs/{db → store/sqlite}/sql-functions.d.cts +0 -0
- /package/dist/cjs/{db → store/sqlite}/sql-functions.d.ts +0 -0
- /package/dist/esm/{db → store/sqlite}/sql-functions.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 schema(db) {\n const
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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":["pagerank","linkEdges","rank","name","schema","db","stmt","prepare","columns","all","some","c","exec","afterReconcile","delta","linksChanged","added","length","vanished","pathsStmt","nodes","map","r","path","ranks","size","runBatch","value"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,oBAAoB;AAC7C,SAASC,SAAS,QAAQ,aAAa;AAGvC,wFAAwF;AACxF,qEAAqE;AAErE,OAAO,MAAMC,OAAgB;IAC3BC,MAAM;IACN,MAAMC,QAAOC,EAAE;QACb,MAAMC,OAAO,MAAMD,GAAGE,OAAO,CAAC;QAC9B,MAAMC,UAAW,MAAMF,KAAKG,GAAG;QAC/B,IAAI,CAACD,QAAQE,IAAI,CAAC,CAACC,IAAMA,EAAER,IAAI,KAAK,UAAU,MAAME,GAAGO,IAAI,CAAC;IAC9D;IACA,MAAMC,gBAAeR,EAAE,EAAES,KAAK;QAC5B,uFAAuF;QACvF,8EAA8E;QAC9E,IAAIA,MAAMC,YAAY,KAAK,SAASD,MAAME,KAAK,CAACC,MAAM,KAAK,KAAKH,MAAMI,QAAQ,CAACD,MAAM,KAAK,GAAG;QAC7F,MAAME,YAAY,MAAMd,GAAGE,OAAO,CAAC;QACnC,MAAMa,QAAQ,AAAE,CAAA,MAAMD,UAAUV,GAAG,EAAC,EAA+BY,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;QACpF,MAAMC,QAAQxB,SAASoB,OAAO,MAAMnB,UAAUI;QAC9C,IAAImB,MAAMC,IAAI,KAAK,GAAG;QACtB,MAAMpB,GAAGqB,QAAQ,CACf,uDACA;eAAIF;SAAM,CAACH,GAAG,CAAC,CAAC,CAACE,MAAMI,MAAM,GAAK;gBAACA;gBAAOJ;aAAK;IAEnD;AACF,EAAE"}
|
|
@@ -26,15 +26,28 @@ function extract(raw) {
|
|
|
26
26
|
}
|
|
27
27
|
export const sections = {
|
|
28
28
|
name: 'sections',
|
|
29
|
-
schema (db) {
|
|
30
|
-
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))`);
|
|
29
|
+
async schema (db) {
|
|
30
|
+
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))`);
|
|
31
31
|
},
|
|
32
32
|
extract,
|
|
33
|
-
remove (db,
|
|
34
|
-
|
|
33
|
+
async remove (db, paths) {
|
|
34
|
+
if (paths.length === 0) return;
|
|
35
|
+
await db.runBatch('DELETE FROM sections WHERE "path" = ?', paths.map((p)=>[
|
|
36
|
+
p
|
|
37
|
+
]));
|
|
35
38
|
},
|
|
36
|
-
store (db,
|
|
37
|
-
const
|
|
38
|
-
extracted.forEach((s, idx)=>
|
|
39
|
+
async store (db, docs) {
|
|
40
|
+
const rows = [];
|
|
41
|
+
for (const { path, extracted } of docs)extracted.forEach((s, idx)=>rows.push([
|
|
42
|
+
path,
|
|
43
|
+
idx,
|
|
44
|
+
s.level,
|
|
45
|
+
s.heading,
|
|
46
|
+
s.startLine,
|
|
47
|
+
s.endLine,
|
|
48
|
+
s.tokens
|
|
49
|
+
]));
|
|
50
|
+
if (rows.length === 0) return;
|
|
51
|
+
await db.runBatch('INSERT INTO sections ("path", idx, level, heading, start_line, end_line, tokens) VALUES (?, ?, ?, ?, ?, ?, ?)', rows);
|
|
39
52
|
}
|
|
40
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/sections.ts"],"sourcesContent":["import { estimateTokens } from '../chunk/index.ts';\nimport { fenceTracker } from './fences.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),\n// CJK-aware rather than a flat chars/4.\n\nexport interface Section {\n level: number;\n heading: string;\n startLine: number;\n endLine: number;\n tokens: number;\n}\n\n// Headings outside fenced code blocks.\nfunction extract(raw: string): Section[] {\n const lines = raw.split('\\n');\n const found: Section[] = [];\n const fence = fenceTracker();\n for (let i = 0; i < lines.length; i++) {\n if (fence.feed(lines[i])) continue;\n if (fence.inFence) continue;\n const m = lines[i].match(/^(#{1,6}) +(.*)/);\n if (m) found.push({ level: m[1].length, heading: m[2].trim(), startLine: i + 1, endLine: lines.length, tokens: 0 });\n }\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 = lines.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 schema(db) {\n 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,\n remove(db,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/sections.ts"],"sourcesContent":["import { estimateTokens } from '../chunk/index.ts';\nimport { fenceTracker } from './fences.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),\n// CJK-aware rather than a flat chars/4.\n\nexport interface Section {\n level: number;\n heading: string;\n startLine: number;\n endLine: number;\n tokens: number;\n}\n\n// Headings outside fenced code blocks.\nfunction extract(raw: string): Section[] {\n const lines = raw.split('\\n');\n const found: Section[] = [];\n const fence = fenceTracker();\n for (let i = 0; i < lines.length; i++) {\n if (fence.feed(lines[i])) continue;\n if (fence.inFence) continue;\n const m = lines[i].match(/^(#{1,6}) +(.*)/);\n if (m) found.push({ level: m[1].length, heading: m[2].trim(), startLine: i + 1, endLine: lines.length, tokens: 0 });\n }\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 = lines.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,\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":["estimateTokens","fenceTracker","extract","raw","lines","split","found","fence","i","length","feed","inFence","m","match","push","level","heading","trim","startLine","endLine","tokens","s","text","slice","join","Math","ceil","sections","name","schema","db","exec","remove","paths","runBatch","map","p","store","docs","rows","path","extracted","forEach","idx"],"mappings":"AAAA,SAASA,cAAc,QAAQ,oBAAoB;AACnD,SAASC,YAAY,QAAQ,cAAc;AAe3C,uCAAuC;AACvC,SAASC,QAAQC,GAAW;IAC1B,MAAMC,QAAQD,IAAIE,KAAK,CAAC;IACxB,MAAMC,QAAmB,EAAE;IAC3B,MAAMC,QAAQN;IACd,IAAK,IAAIO,IAAI,GAAGA,IAAIJ,MAAMK,MAAM,EAAED,IAAK;QACrC,IAAID,MAAMG,IAAI,CAACN,KAAK,CAACI,EAAE,GAAG;QAC1B,IAAID,MAAMI,OAAO,EAAE;QACnB,MAAMC,IAAIR,KAAK,CAACI,EAAE,CAACK,KAAK,CAAC;QACzB,IAAID,GAAGN,MAAMQ,IAAI,CAAC;YAAEC,OAAOH,CAAC,CAAC,EAAE,CAACH,MAAM;YAAEO,SAASJ,CAAC,CAAC,EAAE,CAACK,IAAI;YAAIC,WAAWV,IAAI;YAAGW,SAASf,MAAMK,MAAM;YAAEW,QAAQ;QAAE;IACnH;IACA,IAAK,IAAIC,IAAI,GAAGA,IAAIf,MAAMG,MAAM,EAAEY,IAAK;QACrC,IAAIA,IAAI,IAAIf,MAAMG,MAAM,EAAEH,KAAK,CAACe,EAAE,CAACF,OAAO,GAAGb,KAAK,CAACe,IAAI,EAAE,CAACH,SAAS,GAAG;QACtE,MAAMI,OAAOlB,MAAMmB,KAAK,CAACjB,KAAK,CAACe,EAAE,CAACH,SAAS,GAAG,GAAGZ,KAAK,CAACe,EAAE,CAACF,OAAO,EAAEK,IAAI,CAAC;QACxElB,KAAK,CAACe,EAAE,CAACD,MAAM,GAAGK,KAAKC,IAAI,CAAC1B,eAAesB;IAC7C;IACA,OAAOhB;AACT;AAEA,OAAO,MAAMqB,WAAoB;IAC/BC,MAAM;IACN,MAAMC,QAAOC,EAAE;QACb,MAAMA,GAAGC,IAAI,CAAC,CAAC,4KAA4K,CAAC;IAC9L;IACA7B;IACA,MAAM8B,QAAOF,EAAE,EAAEG,KAAK;QACpB,IAAIA,MAAMxB,MAAM,KAAK,GAAG;QACxB,MAAMqB,GAAGI,QAAQ,CACf,yCACAD,MAAME,GAAG,CAAC,CAACC,IAAM;gBAACA;aAAE;IAExB;IACA,MAAMC,OAAMP,EAAE,EAAEQ,IAAI;QAClB,MAAMC,OAAoB,EAAE;QAC5B,KAAK,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAE,IAAIH,KAAM,AAACG,UAAwBC,OAAO,CAAC,CAACrB,GAAGsB,MAAQJ,KAAKzB,IAAI,CAAC;gBAAC0B;gBAAMG;gBAAKtB,EAAEN,KAAK;gBAAEM,EAAEL,OAAO;gBAAEK,EAAEH,SAAS;gBAAEG,EAAEF,OAAO;gBAAEE,EAAED,MAAM;aAAC;QAChK,IAAImB,KAAK9B,MAAM,KAAK,GAAG;QACvB,MAAMqB,GAAGI,QAAQ,CAAC,iHAAiHK;IACrI;AACF,EAAE"}
|
|
@@ -60,26 +60,27 @@ function extract(_raw, body, _search, data) {
|
|
|
60
60
|
}
|
|
61
61
|
export const tags = {
|
|
62
62
|
name: 'tags',
|
|
63
|
-
schema (db) {
|
|
64
|
-
db.exec('CREATE TABLE IF NOT EXISTS tags ("path" TEXT, tag TEXT, PRIMARY KEY ("path", tag))');
|
|
65
|
-
db.exec('CREATE INDEX IF NOT EXISTS tags_tag ON tags(tag)');
|
|
63
|
+
async schema (db) {
|
|
64
|
+
await db.exec('CREATE TABLE IF NOT EXISTS tags ("path" TEXT, tag TEXT, PRIMARY KEY ("path", tag))');
|
|
65
|
+
await db.exec('CREATE INDEX IF NOT EXISTS tags_tag ON tags(tag)');
|
|
66
66
|
},
|
|
67
67
|
extract,
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
// Blanket clear-then-reinsert (store() below always writes the full found list back), so
|
|
69
|
+
// remove() covers both a vanished file and a reparsed one that already had rows -- no
|
|
70
|
+
// per-file NOT IN diffing, which cannot be expressed as one statement shared across files.
|
|
71
|
+
async remove (db, paths) {
|
|
72
|
+
if (paths.length === 0) return;
|
|
73
|
+
await db.runBatch('DELETE FROM tags WHERE "path" = ?', paths.map((p)=>[
|
|
74
|
+
p
|
|
75
|
+
]));
|
|
73
76
|
},
|
|
74
|
-
store (db,
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const insert = db.prepare('INSERT OR IGNORE INTO tags ("path", tag) VALUES (?, ?)');
|
|
83
|
-
for (const tag of found)insert.run(path, tag);
|
|
77
|
+
async store (db, docs) {
|
|
78
|
+
const rows = [];
|
|
79
|
+
for (const { path, extracted } of docs)for (const tag of extracted)rows.push([
|
|
80
|
+
path,
|
|
81
|
+
tag
|
|
82
|
+
]);
|
|
83
|
+
if (rows.length === 0) return;
|
|
84
|
+
await db.runBatch('INSERT OR IGNORE INTO tags ("path", tag) VALUES (?, ?)', rows);
|
|
84
85
|
}
|
|
85
86
|
};
|
|
@@ -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 from the prose, deduplicated, source not distinguished. Nested tags store full\n// (book/scifi); `tag = 'book' OR tag LIKE 'book/%'` is how a caller 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 fenced code blocks, inline code spans, wikilinks, HTML tags, HTML blocks,\n// <!-- --> comments, and link destinations. maskRegions() handles all of those region-level\n// concerns (and code spans, masked once there); 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 schema(db) {\n db.exec('CREATE TABLE IF NOT EXISTS tags (\"path\" TEXT, tag TEXT, PRIMARY KEY (\"path\", tag))');\n db.exec('CREATE INDEX IF NOT EXISTS tags_tag ON tags(tag)');\n },\n extract,\n //
|
|
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 from the prose, deduplicated, source not distinguished. Nested tags store full\n// (book/scifi); `tag = 'book' OR tag LIKE 'book/%'` is how a caller 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 fenced code blocks, inline code spans, wikilinks, HTML tags, HTML blocks,\n// <!-- --> comments, and link destinations. maskRegions() handles all of those region-level\n// concerns (and code spans, masked once there); 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() below always writes the full found list back), so\n // remove() covers both a vanished file and a reparsed one that already had rows -- no\n // per-file NOT IN diffing, which cannot be expressed as 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":["maskRegions","WIKILINK_RE","HTML_TAG_RE","INLINE_TAG_RE","LINK_DEST_RE","normalizeTag","raw","stripped","replace","test","frontmatterTags","data","tags","list","Array","isArray","found","item","tag","push","inlineTags","body","line","split","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":"AAAA,SAASA,WAAW,QAAQ,cAAc;AAG1C,0FAA0F;AAC1F,uFAAuF;AACvF,4FAA4F;AAE5F,+DAA+D;AAC/D,MAAMC,cAAc,gBAAgB,6DAA6D;AACjG,iDAAiD;AACjD,MAAMC,cAAc,uBAAuB,6DAA6D;AACxG,iGAAiG;AACjG,MAAMC,gBAAgB;AACtB,4FAA4F;AAC5F,MAAMC,eAAe,gCAAgC,oFAAoF;AAEzI,sFAAsF;AACtF,oEAAoE;AACpE,SAASC,aAAaC,GAAW;IAC/B,MAAMC,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,MAAML,MAAMK,iBAAAA,2BAAAA,KAAMC,IAAI;IACtB,MAAMC,OAAOC,MAAMC,OAAO,CAACT,OAAOA,MAAM,OAAOA,QAAQ,WAAW;QAACA;KAAI,GAAG,EAAE;IAC5E,MAAMU,QAAkB,EAAE;IAC1B,KAAK,MAAMC,QAAQJ,KAAM;QACvB,IAAI,OAAOI,SAAS,UAAU;QAC9B,MAAMC,MAAMb,aAAaY;QACzB,IAAIC,KAAKF,MAAMG,IAAI,CAACD;IACtB;IACA,OAAOF;AACT;AAEA,gGAAgG;AAChG,4FAA4F;AAC5F,6FAA6F;AAC7F,SAASI,WAAWC,IAAY;IAC9B,MAAML,QAAkB,EAAE;IAC1B,KAAK,MAAMM,QAAQtB,YAAYqB,MAAME,KAAK,CAAC,MAAO;QAChD,IAAI,CAACD,KAAKE,QAAQ,CAAC,MAAM,UAAU,kCAAkC;QACrE,IAAIC,UAAUH;QACd,IAAIG,QAAQD,QAAQ,CAAC,OAAOC,UAAUA,QAAQjB,OAAO,CAACP,aAAa,CAACyB,IAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;QAC7F,IAAIH,QAAQD,QAAQ,CAAC,OAAOC,UAAUA,QAAQjB,OAAO,CAACJ,cAAc,CAACsB,IAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;QAC9F,IAAIH,QAAQD,QAAQ,CAAC,MAAMC,UAAUA,QAAQjB,OAAO,CAACN,aAAa,CAACwB,IAAM,IAAIC,MAAM,CAACD,EAAEE,MAAM;QAC5F,KAAK,MAAMF,KAAKD,QAAQI,QAAQ,CAAC1B,eAAgB;YAC/C,MAAMe,MAAMb,aAAaqB,CAAC,CAAC,EAAE;YAC7B,IAAIR,KAAKF,MAAMG,IAAI,CAACD;QACtB;IACF;IACA,OAAOF;AACT;AAEA,SAASc,QAAQC,IAAY,EAAEV,IAAY,EAAEW,OAA4C,EAAErB,IAA8B;IACvH,OAAO;WAAI,IAAIsB,IAAI;eAAIvB,gBAAgBC;eAAUS,WAAWC;SAAM;KAAE,CAACa,IAAI;AAC3E;AAEA,OAAO,MAAMtB,OAAgB;IAC3BuB,MAAM;IACN,MAAMC,QAAOC,EAAE;QACb,MAAMA,GAAGC,IAAI,CAAC;QACd,MAAMD,GAAGC,IAAI,CAAC;IAChB;IACAR;IACA,yFAAyF;IACzF,sFAAsF;IACtF,2FAA2F;IAC3F,MAAMS,QAAOF,EAAE,EAAEG,KAAK;QACpB,IAAIA,MAAMZ,MAAM,KAAK,GAAG;QACxB,MAAMS,GAAGI,QAAQ,CACf,qCACAD,MAAME,GAAG,CAAC,CAACC,IAAM;gBAACA;aAAE;IAExB;IACA,MAAMC,OAAMP,EAAE,EAAEQ,IAAI;QAClB,MAAMC,OAAoB,EAAE;QAC5B,KAAK,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAE,IAAIH,KAAM,KAAK,MAAM3B,OAAO8B,UAAuBF,KAAK3B,IAAI,CAAC;YAAC4B;YAAM7B;SAAI;QACtG,IAAI4B,KAAKlB,MAAM,KAAK,GAAG;QACvB,MAAMS,GAAGI,QAAQ,CAAC,0DAA0DK;IAC9E;AACF,EAAE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { DatabaseSync } from 'node:sqlite';
|
|
2
1
|
import type { Block } from '../chunk/index.js';
|
|
3
2
|
import type { Config, FeatureName } from '../config/index.js';
|
|
4
3
|
import type { FileStat } from '../scan/index.js';
|
|
4
|
+
import type { Connection } from '../store/types.js';
|
|
5
5
|
export interface ReconcileDelta {
|
|
6
6
|
files: FileStat[];
|
|
7
7
|
reparsed: string[];
|
|
@@ -9,16 +9,20 @@ export interface ReconcileDelta {
|
|
|
9
9
|
vanished: string[];
|
|
10
10
|
linksChanged?: boolean;
|
|
11
11
|
}
|
|
12
|
+
export interface ExtractedDoc {
|
|
13
|
+
path: string;
|
|
14
|
+
extracted: unknown;
|
|
15
|
+
}
|
|
12
16
|
export interface Feature {
|
|
13
17
|
name: FeatureName;
|
|
14
|
-
schema(db:
|
|
18
|
+
schema(db: Connection): Promise<void>;
|
|
15
19
|
extract?(raw: string, body: string, search?: {
|
|
16
20
|
title: string;
|
|
17
21
|
summary: string;
|
|
18
22
|
}, data?: Record<string, unknown>, cfg?: Config, blocks?: Block[]): unknown;
|
|
19
|
-
remove?(db:
|
|
20
|
-
store?(db:
|
|
21
|
-
afterReconcile?(db:
|
|
23
|
+
remove?(db: Connection, paths: string[], delta: ReconcileDelta): Promise<void>;
|
|
24
|
+
store?(db: Connection, docs: ExtractedDoc[], delta: ReconcileDelta): Promise<void>;
|
|
25
|
+
afterReconcile?(db: Connection, delta: ReconcileDelta): Promise<void>;
|
|
22
26
|
enabledForFile?(cfg: Config, file: FileStat): boolean;
|
|
23
27
|
signature?(cfg: Config): string | undefined;
|
|
24
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/types.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/types.ts"],"sourcesContent":["import type { Block } from '../chunk/index.ts';\nimport type { Config, FeatureName } from '../config/index.ts';\nimport type { FileStat } from '../scan/index.ts';\nimport type { Connection } from '../store/types.ts';\n\n// What changed this reconcile, so hooks act on the delta rather than re-reading the tree.\n// `added` is the brand-new subset of `reparsed`. Hooks communicate through this one object.\nexport interface ReconcileDelta {\n files: FileStat[];\n reparsed: string[];\n added: string[];\n vanished: string[];\n // Set by the links feature: the resolved edge set may differ from before this reconcile.\n linksChanged?: boolean;\n}\n\n// One doc's per-feature extracted value, as store()/remove() see it (reconcile.ts assembles\n// these from ParsedDoc.extracted before calling a feature, once for the whole batch).\nexport interface ExtractedDoc {\n path: string;\n extracted: unknown;\n}\n\n// A feature owns its schema, per-file extraction, batched storage, and any whole-tree pass.\n// Adding a feature = one module here + one entry in the registry (index.ts).\nexport interface Feature {\n name: FeatureName;\n schema(db: Connection): Promise<void>;\n // Pure, per file: raw is the full file, body the prose after frontmatter, search the\n // normalized title/summary strings, data the parsed frontmatter, cfg the resolved config\n // (mirrors enabledForFile's own cfg argument, for a feature whose extraction is config-tunable),\n // blocks the body already parsed once by parseFile, shared with a feature needing a parse tree.\n extract?(raw: string, body: string, search?: { title: string; summary: string }, data?: Record<string, unknown>, cfg?: Config, blocks?: Block[]): unknown;\n // Called once per reconcile (not per file) with every path whose rows need clearing: vanished\n // files, plus reparsed files that already had rows (a feature that diffs its own stale rows\n // in store() instead, e.g. links/tags, filters this list down to just delta.vanished itself).\n remove?(db: Connection, paths: string[], delta: ReconcileDelta): Promise<void>;\n // Called once per reconcile with every freshly parsed doc's extracted value, so a feature\n // writes its rows through one Connection.runBatch call instead of looping per file.\n store?(db: Connection, docs: ExtractedDoc[], delta: ReconcileDelta): Promise<void>;\n // After all rows are current, inside the reconcile transaction (resolution, rank).\n // Hooks run in registry order and communicate through fields on `delta`.\n afterReconcile?(db: Connection, delta: ReconcileDelta): Promise<void>;\n // Per-file opt-out (currently only embed, via FileStat.embed): absent means the feature\n // applies to every file it's otherwise on for. Checked per file before extract/store so a\n // doc in a tree with no embedding model gets no rows for it at all.\n enabledForFile?(cfg: Config, file: FileStat): boolean;\n // This feature's cache-identity segment for config.featureSignature, or undefined to\n // contribute nothing. Composed by access.ts in registry order (features/index.ts's FEATURES).\n signature?(cfg: Config): string | undefined;\n}\n"],"names":[],"mappings":"AAuBA,4FAA4F;AAC5F,6EAA6E;AAC7E,WAyBC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Store } from '../store/types.js';
|
|
2
2
|
interface FindPathOptions {
|
|
3
3
|
directed?: boolean;
|
|
4
4
|
maxDepth?: number;
|
|
5
5
|
allowed?: Set<string>;
|
|
6
6
|
}
|
|
7
|
-
export declare function findPath(
|
|
7
|
+
export declare function findPath(store: Store, from: string, to: string, opts?: FindPathOptions): Promise<string[] | null>;
|
|
8
8
|
export {};
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
// Frontier-by-frontier BFS through a temp visited table, one indexed anti-join per ring: a
|
|
2
2
|
// local question touches a neighborhood, never the whole edge list.
|
|
3
|
-
function resetVisited(
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
async function resetVisited(store) {
|
|
4
|
+
await store.exec('DROP TABLE IF EXISTS temp.visited');
|
|
5
|
+
await store.exec('CREATE TEMP TABLE visited (path TEXT PRIMARY KEY, depth INTEGER NOT NULL, pred TEXT)');
|
|
6
6
|
}
|
|
7
7
|
// Materializes the caller-resolved scope Set into a temp table so it joins like any other
|
|
8
8
|
// indexed column. `extra`, when given, is always in scope -- findPath's `to` endpoint.
|
|
9
|
-
function setupAllowed(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
async function setupAllowed(store, allowed, extra) {
|
|
10
|
+
const all = new Set(allowed);
|
|
11
|
+
if (extra !== undefined) all.add(extra);
|
|
12
|
+
await store.exec('DROP TABLE IF EXISTS temp.allowed_nodes');
|
|
13
|
+
await store.exec('CREATE TEMP TABLE allowed_nodes (path TEXT PRIMARY KEY)');
|
|
14
|
+
await store.runBatch('INSERT INTO allowed_nodes (path) VALUES (?)', [
|
|
15
|
+
...all
|
|
16
|
+
].map((p)=>[
|
|
17
|
+
p
|
|
18
|
+
]));
|
|
16
19
|
}
|
|
17
20
|
// Only resolved links (dst IS NOT NULL) are followed, in either direction.
|
|
18
21
|
function candidateSelect(direction) {
|
|
@@ -23,8 +26,8 @@ function candidateSelect(direction) {
|
|
|
23
26
|
return `${forward} UNION ALL ${reverse}`;
|
|
24
27
|
}
|
|
25
28
|
// One ring: candidates adjacent to the previous ring's frontier (?1), anti-joined against
|
|
26
|
-
// everything already visited, optionally filtered to the allowed set,
|
|
27
|
-
//
|
|
29
|
+
// everything already visited, optionally filtered to the allowed set, and inserted at the
|
|
30
|
+
// new depth (?2). RETURNING hands back exactly what this ring newly reached.
|
|
28
31
|
function ringSql(direction, hasAllowed) {
|
|
29
32
|
return `
|
|
30
33
|
INSERT INTO visited (path, depth, pred)
|
|
@@ -34,23 +37,22 @@ WHERE NOT EXISTS (SELECT 1 FROM visited v2 WHERE v2.path = cand.path)
|
|
|
34
37
|
${hasAllowed ? 'AND EXISTS (SELECT 1 FROM allowed_nodes a WHERE a.path = cand.path)' : ''}
|
|
35
38
|
GROUP BY cand.path
|
|
36
39
|
ORDER BY cand.path
|
|
37
|
-
LIMIT ?3
|
|
38
40
|
RETURNING path`;
|
|
39
41
|
}
|
|
40
|
-
function reconstructPath(
|
|
41
|
-
const lookup =
|
|
42
|
+
async function reconstructPath(store, to) {
|
|
43
|
+
const lookup = await store.prepare('SELECT pred FROM visited WHERE path = ?');
|
|
42
44
|
const path = [];
|
|
43
45
|
let cur = to;
|
|
44
46
|
while(cur !== null){
|
|
45
47
|
path.push(cur);
|
|
46
|
-
const row = lookup.get(cur);
|
|
48
|
+
const row = await lookup.get(cur);
|
|
47
49
|
cur = row ? row.pred : null;
|
|
48
50
|
}
|
|
49
51
|
return path.reverse();
|
|
50
52
|
}
|
|
51
53
|
// One BFS from `from`, tracking a predecessor per node. Undirected by default, matching
|
|
52
54
|
// personalizedRank; null when `to` is unreached within `maxDepth`.
|
|
53
|
-
export function findPath(
|
|
55
|
+
export async function findPath(store, from, to, opts = {}) {
|
|
54
56
|
var _opts_maxDepth;
|
|
55
57
|
if (from === to) return [
|
|
56
58
|
from
|
|
@@ -58,14 +60,15 @@ export function findPath(db, from, to, opts = {}) {
|
|
|
58
60
|
const direction = opts.directed ? 'forward' : 'both';
|
|
59
61
|
const maxDepth = (_opts_maxDepth = opts.maxDepth) !== null && _opts_maxDepth !== void 0 ? _opts_maxDepth : Infinity;
|
|
60
62
|
if (maxDepth <= 0) return null;
|
|
61
|
-
resetVisited(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
await resetVisited(store);
|
|
64
|
+
const insertStart = await store.prepare('INSERT INTO visited (path, depth, pred) VALUES (?, 0, NULL)');
|
|
65
|
+
await insertStart.run(from);
|
|
66
|
+
if (opts.allowed) await setupAllowed(store, opts.allowed, to);
|
|
67
|
+
const stmt = await store.prepare(ringSql(direction, !!opts.allowed));
|
|
65
68
|
for(let ring = 1; ring <= maxDepth; ring++){
|
|
66
|
-
const rows = stmt.all(ring - 1, ring
|
|
69
|
+
const rows = await stmt.all(ring - 1, ring);
|
|
67
70
|
if (rows.length === 0) break;
|
|
68
|
-
if (rows.some((row)=>row.path === to)) return reconstructPath(
|
|
71
|
+
if (rows.some((row)=>row.path === to)) return reconstructPath(store, to);
|
|
69
72
|
}
|
|
70
73
|
return null;
|
|
71
74
|
}
|
|
@@ -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 {
|
|
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, and inserted at the\n// new depth (?2). RETURNING hands back exactly 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":["resetVisited","store","exec","setupAllowed","allowed","extra","all","Set","undefined","add","runBatch","map","p","candidateSelect","direction","forward","reverse","ringSql","hasAllowed","reconstructPath","to","lookup","prepare","path","cur","push","row","get","pred","findPath","from","opts","directed","maxDepth","Infinity","insertStart","run","stmt","ring","rows","length","some"],"mappings":"AAAA,2FAA2F;AAC3F,oEAAoE;AAWpE,eAAeA,aAAaC,KAAY;IACtC,MAAMA,MAAMC,IAAI,CAAC;IACjB,MAAMD,MAAMC,IAAI,CAAC;AACnB;AAEA,0FAA0F;AAC1F,uFAAuF;AACvF,eAAeC,aAAaF,KAAY,EAAEG,OAAoB,EAAEC,KAAc;IAC5E,MAAMC,MAAM,IAAIC,IAAIH;IACpB,IAAIC,UAAUG,WAAWF,IAAIG,GAAG,CAACJ;IACjC,MAAMJ,MAAMC,IAAI,CAAC;IACjB,MAAMD,MAAMC,IAAI,CAAC;IACjB,MAAMD,MAAMS,QAAQ,CAClB,+CACA;WAAIJ;KAAI,CAACK,GAAG,CAAC,CAACC,IAAM;YAACA;SAAE;AAE3B;AAEA,2EAA2E;AAC3E,SAASC,gBAAgBC,SAAoB;IAC3C,MAAMC,UAAU;IAChB,MAAMC,UAAU;IAChB,IAAIF,cAAc,WAAW,OAAOC;IACpC,IAAID,cAAc,WAAW,OAAOE;IACpC,OAAO,GAAGD,QAAQ,WAAW,EAAEC,SAAS;AAC1C;AAEA,0FAA0F;AAC1F,0FAA0F;AAC1F,6EAA6E;AAC7E,SAASC,QAAQH,SAAoB,EAAEI,UAAmB;IACxD,OAAO,CAAC;;;MAGJ,EAAEL,gBAAgBC,WAAW;;AAEnC,EAAEI,aAAa,wEAAwE,GAAG;;;cAG5E,CAAC;AACf;AAEA,eAAeC,gBAAgBlB,KAAY,EAAEmB,EAAU;IACrD,MAAMC,SAAS,MAAMpB,MAAMqB,OAAO,CAAC;IACnC,MAAMC,OAAiB,EAAE;IACzB,IAAIC,MAAqBJ;IACzB,MAAOI,QAAQ,KAAM;QACnBD,KAAKE,IAAI,CAACD;QACV,MAAME,MAAO,MAAML,OAAOM,GAAG,CAACH;QAC9BA,MAAME,MAAMA,IAAIE,IAAI,GAAG;IACzB;IACA,OAAOL,KAAKP,OAAO;AACrB;AAEA,wFAAwF;AACxF,mEAAmE;AACnE,OAAO,eAAea,SAAS5B,KAAY,EAAE6B,IAAY,EAAEV,EAAU,EAAEW,OAAwB,CAAC,CAAC;QAI9EA;IAHjB,IAAID,SAASV,IAAI,OAAO;QAACU;KAAK;IAE9B,MAAMhB,YAAuBiB,KAAKC,QAAQ,GAAG,YAAY;IACzD,MAAMC,YAAWF,iBAAAA,KAAKE,QAAQ,cAAbF,4BAAAA,iBAAiBG;IAClC,IAAID,YAAY,GAAG,OAAO;IAE1B,MAAMjC,aAAaC;IACnB,MAAMkC,cAAc,MAAMlC,MAAMqB,OAAO,CAAC;IACxC,MAAMa,YAAYC,GAAG,CAACN;IACtB,IAAIC,KAAK3B,OAAO,EAAE,MAAMD,aAAaF,OAAO8B,KAAK3B,OAAO,EAAEgB;IAE1D,MAAMiB,OAAO,MAAMpC,MAAMqB,OAAO,CAACL,QAAQH,WAAW,CAAC,CAACiB,KAAK3B,OAAO;IAClE,IAAK,IAAIkC,OAAO,GAAGA,QAAQL,UAAUK,OAAQ;QAC3C,MAAMC,OAAQ,MAAMF,KAAK/B,GAAG,CAACgC,OAAO,GAAGA;QACvC,IAAIC,KAAKC,MAAM,KAAK,GAAG;QACvB,IAAID,KAAKE,IAAI,CAAC,CAACf,MAAQA,IAAIH,IAAI,KAAKH,KAAK,OAAOD,gBAAgBlB,OAAOmB;IACzE;IACA,OAAO;AACT"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@ export type { Peek, PresetCoverage, SearchOptions, TreeMap } from './commands/in
|
|
|
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 } from './config/index.js';
|
|
4
4
|
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
5
|
-
export type { OpenResult } from './db/index.js';
|
|
6
|
-
export { clearCache, open } from './db/index.js';
|
|
7
5
|
export type { SenseErrorCode } from './errors.js';
|
|
8
6
|
export { SenseError } from './errors.js';
|
|
9
7
|
export type { Format, Row, RowFormat } from './output/output.js';
|
|
10
8
|
export { printRows } from './output/output.js';
|
|
9
|
+
export type { OpenResult } from './store/index.js';
|
|
10
|
+
export { clearCache, openStore as open } from './store/index.js';
|
|
11
|
+
export type { Capability, DocumentStore, LexicalHit, LexicalIndex, LexicalQueryOptions, RawStatement, RunResult, SqlSession, Statement, Store, VectorCandidate, VectorSimilar, VectorStore, VectorWriteRow } from './store/types.js';
|
|
11
12
|
export type { WatchEvent, WatchOptions } from './watch.js';
|
|
12
13
|
export { runWatch } from './watch.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// internals (feature registry, graph, scan, meta) stay module-private.
|
|
3
3
|
export { mapTree, peek, presetCoverage, search } from './commands/index.js';
|
|
4
4
|
export { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config/index.js';
|
|
5
|
-
export { clearCache, open } from './db/index.js';
|
|
6
5
|
export { SenseError } from './errors.js';
|
|
7
6
|
export { printRows } from './output/output.js';
|
|
7
|
+
export { clearCache, openStore as open } from './store/index.js';
|
|
8
8
|
export { runWatch } from './watch.js';
|
package/dist/esm/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 } from './config/index.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, SUPPORTED_CONFIG_VERSION } from './config/index.ts';\nexport type {
|
|
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 } 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, 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":["mapTree","peek","presetCoverage","search","CONFIG_FILENAME","initConfig","loadConfig","migrateConfig","SIGNAL_NAMES","STATE_DIR","SUPPORTED_CONFIG_VERSION","SenseError","printRows","clearCache","openStore","open","runWatch"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;AAGvE,SAASA,OAAO,EAAEC,IAAI,EAAEC,cAAc,EAAEC,MAAM,QAAQ,sBAAsB;AAE5E,SAASC,eAAe,EAAEC,UAAU,EAAEC,UAAU,EAAEC,aAAa,EAAEC,YAAY,EAAEC,SAAS,EAAEC,wBAAwB,QAAQ,oBAAoB;AAE9I,SAASC,UAAU,QAAQ,cAAc;AAEzC,SAASC,SAAS,QAAQ,qBAAqB;AAE/C,SAASC,UAAU,EAAEC,aAAaC,IAAI,QAAQ,mBAAmB;AAIjE,SAASC,QAAQ,QAAQ,aAAa"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function guardedTick(fn: () => Promise<void>, skip: () => boolean): () => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Wraps an async interval tick so a rejection (e.g. a store closed mid-await) never
|
|
2
|
+
// escapes as an unhandled rejection, and so a skip() guard can suppress the call entirely.
|
|
3
|
+
export function guardedTick(fn, skip) {
|
|
4
|
+
return ()=>{
|
|
5
|
+
if (skip()) return;
|
|
6
|
+
fn().catch(()=>{});
|
|
7
|
+
};
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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;AAC3F,OAAO,SAASA,YAAYC,EAAuB,EAAEC,IAAmB;IACtE,OAAO;QACL,IAAIA,QAAQ;QACZD,KAAKE,KAAK,CAAC,KAAO;IACpB;AACF"}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function columnHint(db: DatabaseSync, err: Error): Error;
|
|
1
|
+
export declare function columnHint(columns: string[], err: Error): Error;
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
function startsWithBoundary(name, prefix) {
|
|
6
6
|
return name.length > prefix.length && name.startsWith(prefix) && /\W/.test(name[prefix.length]);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
// columns: the tree's frontmatter columns (store.docs.columns()), read by the caller so this
|
|
9
|
+
// stays a pure function rather than a store dependency.
|
|
10
|
+
export function columnHint(columns, err) {
|
|
9
11
|
const match = /no such column: (\S+)/.exec(err.message);
|
|
10
12
|
if (!match) return err;
|
|
11
13
|
const token = match[1];
|
|
@@ -17,7 +19,6 @@ export function columnHint(db, err) {
|
|
|
17
19
|
token,
|
|
18
20
|
aliasStripped
|
|
19
21
|
]);
|
|
20
|
-
const columns = db.prepare('PRAGMA table_info(frontmatter)').all().map((c)=>c.name);
|
|
21
22
|
const candidates = new Set();
|
|
22
23
|
for (const name of columns){
|
|
23
24
|
for (const form of forms){
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output/column-hint.ts"],"sourcesContent":["
|
|
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 naming it\n// unquoted in SQL parses as an expression: `plugin-id` is `plugin - id`, and SQLite's error\n// names a fragment (`plugin`) the user never wrote. This maps that fragment back to the\n// columns it could have come from, so the error names the actual fix instead.\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+)/.exec(err.message);\n if (!match) return err;\n const token = match[1];\n // `f.plugin` -> `plugin`; left as-is when there's no leading alias segment, which also\n // covers a column literally named `a.b` -- the full-token check below matches that case\n // directly, so stripping here never needs to special-case it.\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, SQLite parses the punctuation as an operator instead of column syntax.`);\n}\n"],"names":["startsWithBoundary","name","prefix","length","startsWith","test","columnHint","columns","err","match","exec","message","token","aliasStripped","replace","forms","Set","candidates","form","add","size","quoted","map","split","join","Error"],"mappings":"AAAA,0FAA0F;AAC1F,4FAA4F;AAC5F,wFAAwF;AACxF,8EAA8E;AAE9E,SAASA,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;AAEA,6FAA6F;AAC7F,wDAAwD;AACxD,OAAO,SAASG,WAAWC,OAAiB,EAAEC,GAAU;IACtD,MAAMC,QAAQ,wBAAwBC,IAAI,CAACF,IAAIG,OAAO;IACtD,IAAI,CAACF,OAAO,OAAOD;IACnB,MAAMI,QAAQH,KAAK,CAAC,EAAE;IACtB,uFAAuF;IACvF,wFAAwF;IACxF,8DAA8D;IAC9D,MAAMI,gBAAgBD,MAAME,OAAO,CAAC,mBAAmB;IACvD,MAAMC,QAAQ,IAAIC,IAAI;QAACJ;QAAOC;KAAc;IAC5C,MAAMI,aAAa,IAAID;IACvB,KAAK,MAAMf,QAAQM,QAAS;QAC1B,KAAK,MAAMW,QAAQH,MAAO;YACxB,IAAId,SAASiB,QAAQlB,mBAAmBC,MAAMiB,OAAOD,WAAWE,GAAG,CAAClB;QACtE;IACF;IACA,IAAIgB,WAAWG,IAAI,KAAK,GAAG,OAAOZ;IAClC,MAAMa,SAAS;WAAIJ;KAAW,CAACK,GAAG,CAAC,CAACrB,OAAS,CAAC,CAAC,EAAEA,KAAKsB,KAAK,CAAC,KAAKC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAEA,IAAI,CAAC;IACrF,OAAO,IAAIC,MAAM,GAAGjB,IAAIG,OAAO,CAAC,IAAI,EAAEU,OAAO,6GAA6G,CAAC;AAC7J"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export type Row = Record<string, unknown>;
|
|
2
2
|
export type Format = 'table' | 'json';
|
|
3
3
|
export type RowFormat = Format | 'csv';
|
|
4
|
+
export declare function stringifyJson(value: unknown, indent?: number): string;
|
|
4
5
|
export declare function printRows(rows: Row[], format: RowFormat, columns?: string[]): void;
|
|
5
|
-
export declare function printRowStream(rows:
|
|
6
|
+
export declare function printRowStream(rows: AsyncIterable<Row>, format: RowFormat, columns: string[]): Promise<void>;
|
|
6
7
|
export declare function featureOffHint(name: string): string;
|
|
7
8
|
export declare function featuresLine(features: {
|
|
8
9
|
on: string[];
|
|
@@ -24,6 +24,14 @@ function warnOversize(bytes, rowCount) {
|
|
|
24
24
|
// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with
|
|
25
25
|
// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --
|
|
26
26
|
// a bare newline would read to a csv parser as one empty record.
|
|
27
|
+
// JSON.stringify throws on BigInt, and stores return int64 as BigInt (DuckDB does). A value
|
|
28
|
+
// that fits a safe integer stays a number; a larger one becomes its decimal string, since a
|
|
29
|
+
// JSON number cannot carry it losslessly.
|
|
30
|
+
const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
31
|
+
const bigintSafe = (_key, value)=>typeof value === 'bigint' ? value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString() : value;
|
|
32
|
+
export function stringifyJson(value, indent) {
|
|
33
|
+
return JSON.stringify(value, bigintSafe, indent);
|
|
34
|
+
}
|
|
27
35
|
export function printRows(rows, format, columns) {
|
|
28
36
|
if (format === 'csv') {
|
|
29
37
|
// Collapsed the same way a row object collapses them, so a statement naming a column
|
|
@@ -45,25 +53,26 @@ export function printRows(rows, format, columns) {
|
|
|
45
53
|
console.log(rendered);
|
|
46
54
|
warnOversize(Buffer.byteLength(rendered), rows.length);
|
|
47
55
|
}
|
|
48
|
-
// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an
|
|
49
|
-
// iterator,
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
// the operating system's.
|
|
54
|
-
export function printRowStream(rows, format, columns) {
|
|
55
|
-
const iterator = rows[Symbol.
|
|
56
|
+
// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an async
|
|
57
|
+
// iterator (raw.prepare().iterate(), one microtask for the whole statement, not per row), so a
|
|
58
|
+
// large result is never held here as rows and again as a rendered string. Table buffers by
|
|
59
|
+
// necessity (a column is as wide as its widest cell, which the last row can change); json and
|
|
60
|
+
// csv write row by row. The writes are synchronous, so when stdout is a pipe Node buffers what
|
|
61
|
+
// the reader has not taken yet -- the saving is this module's copies, not the operating system's.
|
|
62
|
+
export async function printRowStream(rows, format, columns) {
|
|
63
|
+
const iterator = rows[Symbol.asyncIterator]();
|
|
56
64
|
// One step before any write. FTS5 parses a MATCH expression at step time rather than at
|
|
57
65
|
// prepare time, so a bad search string throws here, with stdout still clean for the error.
|
|
58
|
-
const first = iterator.next();
|
|
66
|
+
const first = await iterator.next();
|
|
59
67
|
const rest = {
|
|
60
|
-
[Symbol.
|
|
68
|
+
[Symbol.asyncIterator]: ()=>iterator
|
|
61
69
|
};
|
|
62
70
|
if (format === 'table') {
|
|
63
|
-
|
|
64
|
-
first.value
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
const collected = first.done ? [] : [
|
|
72
|
+
first.value
|
|
73
|
+
];
|
|
74
|
+
for await (const row of rest)collected.push(row);
|
|
75
|
+
printRows(collected, format, columns);
|
|
67
76
|
return;
|
|
68
77
|
}
|
|
69
78
|
let bytes = 0;
|
|
@@ -76,19 +85,14 @@ export function printRowStream(rows, format, columns) {
|
|
|
76
85
|
if (format === 'json') {
|
|
77
86
|
// Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one
|
|
78
87
|
// level, comma-joined, inside the array brackets written here.
|
|
79
|
-
|
|
80
|
-
// converted via the replacer: a value that fits a safe integer stays a number, a larger one
|
|
81
|
-
// becomes its decimal string, since a JSON number cannot carry it losslessly.
|
|
82
|
-
const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
83
|
-
const bigintSafe = (_key, value)=>typeof value === 'bigint' ? value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString() : value;
|
|
84
|
-
const indent = (row)=>JSON.stringify(row, bigintSafe, 2).split('\n').map((line)=>` ${line}`).join('\n');
|
|
88
|
+
const indent = (row)=>stringifyJson(row, 2).split('\n').map((line)=>` ${line}`).join('\n');
|
|
85
89
|
if (first.done) {
|
|
86
90
|
write('[]\n');
|
|
87
91
|
} else {
|
|
88
92
|
write('[\n');
|
|
89
93
|
write(indent(first.value));
|
|
90
94
|
rowCount = 1;
|
|
91
|
-
for (const row of rest){
|
|
95
|
+
for await (const row of rest){
|
|
92
96
|
write(',\n');
|
|
93
97
|
write(indent(row));
|
|
94
98
|
rowCount++;
|
|
@@ -105,7 +109,7 @@ export function printRowStream(rows, format, columns) {
|
|
|
105
109
|
write(`${csvLine(names)}\n`);
|
|
106
110
|
write(`${csvLine(names.map((name)=>first.value[name]))}\n`);
|
|
107
111
|
rowCount = 1;
|
|
108
|
-
for (const row of rest){
|
|
112
|
+
for await (const row of rest){
|
|
109
113
|
write(`${csvLine(names.map((name)=>row[name]))}\n`);
|
|
110
114
|
rowCount++;
|
|
111
115
|
}
|
|
@@ -130,7 +134,7 @@ function fitWidths(widths, limit) {
|
|
|
130
134
|
}
|
|
131
135
|
}
|
|
132
136
|
function renderRows(rows, format, width = process.stdout.columns) {
|
|
133
|
-
if (format === 'json') return
|
|
137
|
+
if (format === 'json') return stringifyJson(rows, 2);
|
|
134
138
|
if (rows.length === 0) return '(0 rows)';
|
|
135
139
|
const columns = Object.keys(rows[0]);
|
|
136
140
|
const cells = rows.map((row)=>columns.map((col)=>cell(row[col])));
|