sensemaking 0.15.4 → 0.17.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 +33 -5
- package/dist/cjs/chunk/extract.d.cts +2 -0
- package/dist/cjs/chunk/extract.d.ts +2 -0
- package/dist/cjs/chunk/extract.js +139 -0
- package/dist/cjs/chunk/extract.js.map +1 -0
- package/dist/cjs/chunk/group.d.cts +4 -0
- package/dist/cjs/chunk/group.d.ts +4 -0
- package/dist/cjs/chunk/group.js +489 -0
- package/dist/cjs/chunk/group.js.map +1 -0
- package/dist/cjs/chunk/index.d.cts +8 -0
- package/dist/cjs/chunk/index.d.ts +8 -0
- package/dist/cjs/chunk/index.js +44 -0
- package/dist/cjs/chunk/index.js.map +1 -0
- package/dist/cjs/chunk/parse.d.cts +2 -0
- package/dist/cjs/chunk/parse.d.ts +2 -0
- package/dist/cjs/chunk/parse.js +71 -0
- package/dist/cjs/chunk/parse.js.map +1 -0
- package/dist/cjs/chunk/types.d.cts +19 -0
- package/dist/cjs/chunk/types.d.ts +19 -0
- package/dist/cjs/chunk/types.js +5 -0
- package/dist/cjs/chunk/types.js.map +1 -0
- package/dist/cjs/chunk/version.d.cts +1 -0
- package/dist/cjs/chunk/version.d.ts +1 -0
- package/dist/cjs/chunk/version.js +14 -0
- package/dist/cjs/chunk/version.js.map +1 -0
- package/dist/cjs/cli/download.js +12 -11
- package/dist/cjs/cli/download.js.map +1 -1
- package/dist/cjs/cli/index.d.cts +1 -1
- package/dist/cjs/cli/index.d.ts +1 -1
- package/dist/cjs/cli/index.js +1 -1
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/init.js +31 -5
- package/dist/cjs/cli/init.js.map +1 -1
- package/dist/cjs/cli/map.js +1 -1
- package/dist/cjs/cli/map.js.map +1 -1
- package/dist/cjs/cli/named.js +1 -1
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/path.js +2 -2
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/peek.js +1 -1
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js +1 -1
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/cli/search.js +1 -1
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/cli/shared.d.cts +1 -1
- package/dist/cjs/cli/shared.d.ts +1 -1
- package/dist/cjs/cli/shared.js +3 -3
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/status.js +344 -100
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/map.d.cts +1 -1
- package/dist/cjs/commands/map.d.ts +1 -1
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/peek.d.cts +1 -1
- package/dist/cjs/commands/peek.d.ts +1 -1
- package/dist/cjs/commands/peek.js +13 -6
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.js +17 -13
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.js +1 -1
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.d.cts +1 -1
- package/dist/cjs/commands/search.d.ts +1 -1
- package/dist/cjs/commands/search.js +28 -99
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +18 -0
- package/dist/cjs/commands/signals.d.ts +18 -0
- package/dist/cjs/commands/signals.js +299 -0
- package/dist/cjs/commands/signals.js.map +1 -0
- package/dist/cjs/commands/status.d.cts +2 -2
- package/dist/cjs/commands/status.d.ts +2 -2
- package/dist/cjs/commands/status.js +1 -1
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config/access.d.cts +8 -3
- package/dist/cjs/config/access.d.ts +8 -3
- package/dist/cjs/config/access.js +35 -17
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +5 -1
- package/dist/cjs/config/index.d.ts +5 -1
- package/dist/cjs/config/index.js +16 -2
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.d.cts +6 -1
- package/dist/cjs/config/load.d.ts +6 -1
- package/dist/cjs/config/load.js +83 -8
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/resolve.js +1 -1
- package/dist/cjs/config/resolve.js.map +1 -1
- package/dist/cjs/config/signals.d.cts +4 -0
- package/dist/cjs/config/signals.d.ts +4 -0
- package/dist/cjs/config/signals.js +30 -0
- package/dist/cjs/config/signals.js.map +1 -0
- package/dist/cjs/config/types.d.cts +7 -4
- package/dist/cjs/config/types.d.ts +7 -4
- package/dist/cjs/config/types.js +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.d.cts +1 -0
- package/dist/cjs/config/validate.d.ts +1 -0
- package/dist/cjs/config/validate.js +127 -11
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/db/open.d.cts +1 -1
- package/dist/cjs/db/open.d.ts +1 -1
- package/dist/cjs/db/open.js +9 -4
- package/dist/cjs/db/open.js.map +1 -1
- package/dist/cjs/db/reconcile.d.cts +1 -0
- package/dist/cjs/db/reconcile.d.ts +1 -0
- package/dist/cjs/db/reconcile.js +23 -8
- package/dist/cjs/db/reconcile.js.map +1 -1
- package/dist/cjs/{sql-functions.js → db/sql-functions.js} +1 -1
- package/dist/cjs/db/sql-functions.js.map +1 -0
- package/dist/cjs/embed/cohere.d.cts +2 -0
- package/dist/cjs/embed/cohere.d.ts +2 -0
- package/dist/cjs/embed/cohere.js +238 -0
- package/dist/cjs/embed/cohere.js.map +1 -0
- package/dist/cjs/embed/http.d.cts +2 -0
- package/dist/cjs/embed/http.d.ts +2 -0
- package/dist/cjs/embed/http.js +258 -0
- package/dist/cjs/embed/http.js.map +1 -0
- package/dist/cjs/embed/identity.d.cts +13 -0
- package/dist/cjs/embed/identity.d.ts +13 -0
- package/dist/cjs/embed/identity.js +194 -0
- package/dist/cjs/embed/identity.js.map +1 -0
- package/dist/cjs/embed/langfit.d.cts +6 -0
- package/dist/cjs/embed/langfit.d.ts +6 -0
- package/dist/cjs/embed/langfit.js +286 -0
- package/dist/cjs/embed/langfit.js.map +1 -0
- package/dist/cjs/embed/languages.d.cts +3 -0
- package/dist/cjs/embed/languages.d.ts +3 -0
- package/dist/cjs/embed/languages.js +98 -0
- package/dist/cjs/embed/languages.js.map +1 -0
- package/dist/cjs/embed/openai.d.cts +2 -0
- package/dist/cjs/embed/openai.d.ts +2 -0
- package/dist/cjs/embed/openai.js +268 -0
- package/dist/cjs/embed/openai.js.map +1 -0
- package/dist/cjs/embed/query.d.cts +21 -0
- package/dist/cjs/embed/query.d.ts +21 -0
- package/dist/cjs/embed/query.js +610 -0
- package/dist/cjs/embed/query.js.map +1 -0
- package/dist/cjs/embed/registry.d.cts +3 -0
- package/dist/cjs/embed/registry.d.ts +3 -0
- package/dist/cjs/embed/registry.js +114 -0
- package/dist/cjs/embed/registry.js.map +1 -0
- package/dist/cjs/embed/static.d.cts +2 -0
- package/dist/cjs/embed/static.d.ts +2 -0
- package/dist/cjs/embed/static.js +330 -0
- package/dist/cjs/embed/static.js.map +1 -0
- package/dist/cjs/embed/store.d.cts +8 -0
- package/dist/cjs/embed/store.d.ts +8 -0
- package/dist/cjs/embed/store.js +498 -0
- package/dist/cjs/embed/store.js.map +1 -0
- package/dist/cjs/embed/types.d.cts +8 -0
- package/dist/cjs/embed/types.d.ts +8 -0
- package/dist/cjs/embed/types.js +7 -0
- package/dist/cjs/embed/types.js.map +1 -0
- 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.d.cts +2 -28
- package/dist/cjs/features/embed.d.ts +2 -28
- package/dist/cjs/features/embed.js +39 -1027
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/{fences.js → features/fences.js} +1 -1
- package/dist/cjs/features/fences.js.map +1 -0
- package/dist/cjs/features/links.js +1 -1
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/rank.js +1 -1
- package/dist/cjs/features/rank.js.map +1 -1
- package/dist/cjs/features/sections.js +4 -3
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/features/tags.js +1 -1
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/features/types.d.cts +4 -2
- package/dist/cjs/features/types.d.ts +4 -2
- package/dist/cjs/graph/graph.js.map +1 -0
- package/dist/cjs/graph/traverse.js.map +1 -0
- package/dist/cjs/index.d.cts +4 -4
- package/dist/cjs/index.d.ts +4 -4
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output/column-hint.js.map +1 -0
- package/dist/cjs/{output.d.cts → output/output.d.cts} +2 -2
- package/dist/cjs/{output.d.ts → output/output.d.ts} +2 -2
- package/dist/cjs/{output.js → output/output.js} +9 -2
- package/dist/cjs/output/output.js.map +1 -0
- package/dist/cjs/output/progress.js.map +1 -0
- package/dist/cjs/{search-error.js → output/search-error.js} +1 -1
- package/dist/cjs/output/search-error.js.map +1 -0
- package/dist/cjs/scan/frontmatter.d.cts +13 -0
- package/dist/cjs/scan/frontmatter.d.ts +13 -0
- package/dist/cjs/scan/frontmatter.js +229 -0
- package/dist/cjs/scan/frontmatter.js.map +1 -0
- package/dist/cjs/scan/index.d.cts +25 -0
- package/dist/cjs/scan/index.d.ts +25 -0
- package/dist/cjs/scan/index.js +107 -0
- package/dist/cjs/scan/index.js.map +1 -0
- package/dist/cjs/scan/list.d.cts +12 -0
- package/dist/cjs/scan/list.d.ts +12 -0
- package/dist/cjs/scan/list.js +154 -0
- package/dist/cjs/scan/list.js.map +1 -0
- package/dist/cjs/text/segment.d.cts +3 -0
- package/dist/cjs/text/segment.d.ts +3 -0
- package/dist/cjs/text/segment.js +154 -0
- package/dist/cjs/text/segment.js.map +1 -0
- package/dist/cjs/text/strip.d.cts +3 -0
- package/dist/cjs/text/strip.d.ts +3 -0
- package/dist/cjs/text/strip.js +32 -0
- package/dist/cjs/text/strip.js.map +1 -0
- package/dist/esm/chunk/extract.d.ts +2 -0
- package/dist/esm/chunk/extract.js +114 -0
- package/dist/esm/chunk/extract.js.map +1 -0
- package/dist/esm/chunk/group.d.ts +4 -0
- package/dist/esm/chunk/group.js +253 -0
- package/dist/esm/chunk/group.js.map +1 -0
- package/dist/esm/chunk/index.d.ts +8 -0
- package/dist/esm/chunk/index.js +16 -0
- package/dist/esm/chunk/index.js.map +1 -0
- package/dist/esm/chunk/parse.d.ts +2 -0
- package/dist/esm/chunk/parse.js +63 -0
- package/dist/esm/chunk/parse.js.map +1 -0
- package/dist/esm/chunk/types.d.ts +19 -0
- package/dist/esm/chunk/types.js +2 -0
- package/dist/esm/chunk/types.js.map +1 -0
- package/dist/esm/chunk/version.d.ts +1 -0
- package/dist/esm/chunk/version.js +3 -0
- package/dist/esm/chunk/version.js.map +1 -0
- package/dist/esm/cli/download.js +9 -8
- package/dist/esm/cli/download.js.map +1 -1
- package/dist/esm/cli/index.d.ts +1 -1
- package/dist/esm/cli/index.js +1 -1
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/init.js +32 -6
- package/dist/esm/cli/init.js.map +1 -1
- package/dist/esm/cli/map.js +1 -1
- package/dist/esm/cli/map.js.map +1 -1
- package/dist/esm/cli/named.js +1 -1
- package/dist/esm/cli/named.js.map +1 -1
- package/dist/esm/cli/path.js +2 -2
- package/dist/esm/cli/path.js.map +1 -1
- package/dist/esm/cli/peek.js +1 -1
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/related.js +1 -1
- package/dist/esm/cli/related.js.map +1 -1
- package/dist/esm/cli/search.js +1 -1
- package/dist/esm/cli/search.js.map +1 -1
- package/dist/esm/cli/shared.d.ts +1 -1
- package/dist/esm/cli/shared.js +3 -3
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/status.js +37 -9
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/map.d.ts +1 -1
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/peek.d.ts +1 -1
- package/dist/esm/commands/peek.js +8 -1
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.js +14 -10
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.js +1 -1
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.d.ts +1 -1
- package/dist/esm/commands/search.js +30 -81
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +18 -0
- package/dist/esm/commands/signals.js +78 -0
- package/dist/esm/commands/signals.js.map +1 -0
- package/dist/esm/commands/status.d.ts +2 -2
- package/dist/esm/commands/status.js +2 -2
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config/access.d.ts +8 -3
- package/dist/esm/config/access.js +34 -15
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +5 -1
- package/dist/esm/config/index.js +3 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.d.ts +6 -1
- package/dist/esm/config/load.js +67 -9
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/resolve.js +2 -2
- package/dist/esm/config/resolve.js.map +1 -1
- package/dist/esm/config/signals.d.ts +4 -0
- package/dist/esm/config/signals.js +14 -0
- package/dist/esm/config/signals.js.map +1 -0
- package/dist/esm/config/types.d.ts +7 -4
- package/dist/esm/config/types.js +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.d.ts +1 -0
- package/dist/esm/config/validate.js +65 -12
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/db/open.d.ts +1 -1
- package/dist/esm/db/open.js +11 -6
- package/dist/esm/db/open.js.map +1 -1
- package/dist/esm/db/reconcile.d.ts +1 -0
- package/dist/esm/db/reconcile.js +14 -4
- package/dist/esm/db/reconcile.js.map +1 -1
- package/dist/esm/{sql-functions.js → db/sql-functions.js} +1 -1
- package/dist/esm/db/sql-functions.js.map +1 -0
- package/dist/esm/embed/cohere.d.ts +2 -0
- package/dist/esm/embed/cohere.js +46 -0
- package/dist/esm/embed/cohere.js.map +1 -0
- package/dist/esm/embed/http.d.ts +2 -0
- package/dist/esm/embed/http.js +33 -0
- package/dist/esm/embed/http.js.map +1 -0
- package/dist/esm/embed/identity.d.ts +13 -0
- package/dist/esm/embed/identity.js +92 -0
- package/dist/esm/embed/identity.js.map +1 -0
- package/dist/esm/embed/langfit.d.ts +6 -0
- package/dist/esm/embed/langfit.js +44 -0
- package/dist/esm/embed/langfit.js.map +1 -0
- package/dist/esm/embed/languages.d.ts +3 -0
- package/dist/esm/embed/languages.js +80 -0
- package/dist/esm/embed/languages.js.map +1 -0
- package/dist/esm/embed/openai.d.ts +2 -0
- package/dist/esm/embed/openai.js +49 -0
- package/dist/esm/embed/openai.js.map +1 -0
- package/dist/esm/embed/query.d.ts +21 -0
- package/dist/esm/embed/query.js +181 -0
- package/dist/esm/embed/query.js.map +1 -0
- package/dist/esm/embed/registry.d.ts +3 -0
- package/dist/esm/embed/registry.js +45 -0
- package/dist/esm/embed/registry.js.map +1 -0
- package/dist/esm/embed/static.d.ts +2 -0
- package/dist/esm/embed/static.js +71 -0
- package/dist/esm/embed/static.js.map +1 -0
- package/dist/esm/embed/store.d.ts +8 -0
- package/dist/esm/embed/store.js +123 -0
- package/dist/esm/embed/store.js.map +1 -0
- package/dist/esm/embed/types.d.ts +8 -0
- package/dist/esm/embed/types.js +3 -0
- package/dist/esm/embed/types.js.map +1 -0
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.d.ts +2 -28
- package/dist/esm/features/embed.js +33 -377
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/{fences.js → features/fences.js} +1 -1
- package/dist/esm/features/fences.js.map +1 -0
- package/dist/esm/features/links.js +1 -1
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/rank.js +1 -1
- package/dist/esm/features/rank.js.map +1 -1
- package/dist/esm/features/sections.js +4 -3
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/features/tags.js +1 -1
- package/dist/esm/features/tags.js.map +1 -1
- package/dist/esm/features/types.d.ts +4 -2
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/graph/graph.js.map +1 -0
- package/dist/esm/graph/traverse.js.map +1 -0
- package/dist/esm/index.d.ts +4 -4
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output/column-hint.js.map +1 -0
- package/dist/esm/{output.d.ts → output/output.d.ts} +2 -2
- package/dist/esm/{output.js → output/output.js} +6 -2
- package/dist/esm/output/output.js.map +1 -0
- package/dist/esm/output/progress.js.map +1 -0
- package/dist/esm/{search-error.js → output/search-error.js} +1 -1
- package/dist/esm/output/search-error.js.map +1 -0
- package/dist/esm/scan/frontmatter.d.ts +13 -0
- package/dist/esm/{scan.js → scan/frontmatter.js} +4 -120
- package/dist/esm/scan/frontmatter.js.map +1 -0
- package/dist/esm/scan/index.d.ts +25 -0
- package/dist/esm/scan/index.js +58 -0
- package/dist/esm/scan/index.js.map +1 -0
- package/dist/esm/scan/list.d.ts +12 -0
- package/dist/esm/scan/list.js +58 -0
- package/dist/esm/scan/list.js.map +1 -0
- package/dist/esm/text/segment.d.ts +3 -0
- package/dist/esm/text/segment.js +95 -0
- package/dist/esm/text/segment.js.map +1 -0
- package/dist/esm/text/strip.d.ts +3 -0
- package/dist/esm/text/strip.js +12 -0
- package/dist/esm/text/strip.js.map +1 -0
- package/package.json +23 -2
- package/schema.json +22 -8
- package/skills/sense/SKILL.md +21 -5
- package/skills/sense-setup/EXAMPLES.md +6 -6
- package/skills/sense-setup/SKILL.md +7 -5
- package/dist/cjs/column-hint.js.map +0 -1
- package/dist/cjs/fences.js.map +0 -1
- package/dist/cjs/graph.js.map +0 -1
- package/dist/cjs/output.js.map +0 -1
- package/dist/cjs/progress.js.map +0 -1
- package/dist/cjs/scan.d.cts +0 -35
- package/dist/cjs/scan.d.ts +0 -35
- package/dist/cjs/scan.js +0 -433
- package/dist/cjs/scan.js.map +0 -1
- package/dist/cjs/search-error.js.map +0 -1
- package/dist/cjs/segment.d.cts +0 -2
- package/dist/cjs/segment.d.ts +0 -2
- package/dist/cjs/segment.js +0 -98
- package/dist/cjs/segment.js.map +0 -1
- package/dist/cjs/sql-functions.js.map +0 -1
- package/dist/cjs/traverse.js.map +0 -1
- package/dist/esm/column-hint.js.map +0 -1
- package/dist/esm/fences.js.map +0 -1
- package/dist/esm/graph.js.map +0 -1
- package/dist/esm/output.js.map +0 -1
- package/dist/esm/progress.js.map +0 -1
- package/dist/esm/scan.d.ts +0 -35
- package/dist/esm/scan.js.map +0 -1
- package/dist/esm/search-error.js.map +0 -1
- package/dist/esm/segment.d.ts +0 -2
- package/dist/esm/segment.js +0 -65
- package/dist/esm/segment.js.map +0 -1
- package/dist/esm/sql-functions.js.map +0 -1
- package/dist/esm/traverse.js.map +0 -1
- /package/dist/cjs/{sql-functions.d.cts → db/sql-functions.d.cts} +0 -0
- /package/dist/cjs/{sql-functions.d.ts → db/sql-functions.d.ts} +0 -0
- /package/dist/cjs/{fences.d.cts → features/fences.d.cts} +0 -0
- /package/dist/cjs/{fences.d.ts → features/fences.d.ts} +0 -0
- /package/dist/cjs/{graph.d.cts → graph/graph.d.cts} +0 -0
- /package/dist/cjs/{graph.d.ts → graph/graph.d.ts} +0 -0
- /package/dist/cjs/{graph.js → graph/graph.js} +0 -0
- /package/dist/cjs/{traverse.d.cts → graph/traverse.d.cts} +0 -0
- /package/dist/cjs/{traverse.d.ts → graph/traverse.d.ts} +0 -0
- /package/dist/cjs/{traverse.js → graph/traverse.js} +0 -0
- /package/dist/cjs/{column-hint.d.cts → output/column-hint.d.cts} +0 -0
- /package/dist/cjs/{column-hint.d.ts → output/column-hint.d.ts} +0 -0
- /package/dist/cjs/{column-hint.js → output/column-hint.js} +0 -0
- /package/dist/cjs/{progress.d.cts → output/progress.d.cts} +0 -0
- /package/dist/cjs/{progress.d.ts → output/progress.d.ts} +0 -0
- /package/dist/cjs/{progress.js → output/progress.js} +0 -0
- /package/dist/cjs/{search-error.d.cts → output/search-error.d.cts} +0 -0
- /package/dist/cjs/{search-error.d.ts → output/search-error.d.ts} +0 -0
- /package/dist/esm/{sql-functions.d.ts → db/sql-functions.d.ts} +0 -0
- /package/dist/esm/{fences.d.ts → features/fences.d.ts} +0 -0
- /package/dist/esm/{graph.d.ts → graph/graph.d.ts} +0 -0
- /package/dist/esm/{graph.js → graph/graph.js} +0 -0
- /package/dist/esm/{traverse.d.ts → graph/traverse.d.ts} +0 -0
- /package/dist/esm/{traverse.js → graph/traverse.js} +0 -0
- /package/dist/esm/{column-hint.d.ts → output/column-hint.d.ts} +0 -0
- /package/dist/esm/{column-hint.js → output/column-hint.js} +0 -0
- /package/dist/esm/{progress.d.ts → output/progress.d.ts} +0 -0
- /package/dist/esm/{progress.js → output/progress.js} +0 -0
- /package/dist/esm/{search-error.d.ts → output/search-error.d.ts} +0 -0
package/schema.json
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
},
|
|
13
13
|
"version": {
|
|
14
14
|
"type": "integer",
|
|
15
|
-
"enum": [1, 2, 3, 4],
|
|
15
|
+
"enum": [1, 2, 3, 4, 5],
|
|
16
16
|
"description": "Config format version. Older versions are auto-migrated (and the file rewritten) on load; a version newer than this sense build supports makes it exit with an error rather than misinterpret the file. Omit to default to 1."
|
|
17
17
|
},
|
|
18
18
|
"presets": {
|
|
19
19
|
"type": "object",
|
|
20
|
-
"description": "File selection, index-time, and named search defaults. A preset is self-contained: no inheritance between presets, and no ordering -- presets may overlap freely (they are views, not partitions), and a preset whose globs match nothing is valid. A file is indexed iff any preset's include/exclude covers it (union across presets); `default` is used when a command names no preset, and must be declared. A file is embedded when the top-level `embed` block names a model and some covering preset
|
|
20
|
+
"description": "File selection, index-time, and named search defaults. A preset is self-contained: no inheritance between presets, and no ordering -- presets may overlap freely (they are views, not partitions), and a preset whose globs match nothing is valid. A file is indexed iff any preset's include/exclude covers it (union across presets); `default` is used when a command names no preset, and must be declared. A file is embedded when the top-level `embed` block names a model and some covering preset's `signals` include `vectors`. `sense init` generates `default` plus one `large` example.",
|
|
21
21
|
"minProperties": 1,
|
|
22
22
|
"additionalProperties": {
|
|
23
23
|
"type": "object",
|
|
@@ -36,9 +36,16 @@
|
|
|
36
36
|
"minItems": 1,
|
|
37
37
|
"description": "Glob patterns excluded from this preset's `include`, tsconfig-standard semantics."
|
|
38
38
|
},
|
|
39
|
-
"
|
|
40
|
-
"type": "
|
|
41
|
-
"
|
|
39
|
+
"signals": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"minProperties": 1,
|
|
43
|
+
"properties": {
|
|
44
|
+
"words": { "type": "number", "exclusiveMinimum": 0 },
|
|
45
|
+
"links": { "type": "number", "exclusiveMinimum": 0 },
|
|
46
|
+
"vectors": { "type": "number", "exclusiveMinimum": 0 }
|
|
47
|
+
},
|
|
48
|
+
"description": "Exhaustive when present: every signal this preset's searches compose, each mapped to its RRF weight (a finite number > 0; presence is enablement -- words = BM25 match, links = link-graph expansion, vectors = embedding similarity). A signal's RRF contribution is `weight / (RRF_K + rank)`; weight 1 (the default for every signal) reproduces unweighted scores exactly. Absent means every signal whose prerequisite holds, each at weight 1 -- words always, links when the `links` feature is on, vectors when the top-level `embed` block names a model. `links` requires `words` (link expansion is seeded by word matches); `vectors` requires the `embed` block. A layer searched for exact wording (ingested sources, archives, generated output) declares `{\"words\": 1, \"links\": 1}`: its files cost no embedding, and searches under it run on words and links only."
|
|
42
49
|
},
|
|
43
50
|
"k": {
|
|
44
51
|
"type": "integer",
|
|
@@ -78,13 +85,20 @@
|
|
|
78
85
|
"embed": {
|
|
79
86
|
"type": "object",
|
|
80
87
|
"additionalProperties": false,
|
|
81
|
-
"description": "The vector switch and the model it uses. Present with a `model` means every indexed file gets vectors; omit the block entirely to index without vectors. `model` (required: Hugging Face id or local path), `
|
|
88
|
+
"description": "The vector switch and the model it uses. Present with a `model` means every indexed file gets vectors; omit the block entirely to index without vectors. `model` (required: Hugging Face id or local path), `provider` (`static` = built-in pure-JS Model2Vec loader, default; `openai` = OpenAI-compatible POST /embeddings, covering Ollama, LM Studio, and other compatible endpoints; `cohere` = native Cohere `/v2/embed`), `url` (openai provider base, e.g. http://localhost:11434/v1), `key` (name of the env var holding the bearer token). Nothing downloads the model implicitly -- run `sense download` once per machine. Changing model or provider rebuilds the cache like a feature toggle.",
|
|
82
89
|
"required": ["model"],
|
|
83
90
|
"properties": {
|
|
84
91
|
"model": { "type": "string" },
|
|
85
|
-
"
|
|
92
|
+
"provider": { "type": "string", "enum": ["static", "openai", "cohere"] },
|
|
86
93
|
"url": { "type": "string" },
|
|
87
|
-
"key": { "type": "string" }
|
|
94
|
+
"key": { "type": "string" },
|
|
95
|
+
"languages": {
|
|
96
|
+
"type": "array",
|
|
97
|
+
"items": { "type": "string" },
|
|
98
|
+
"minItems": 1,
|
|
99
|
+
"description": "Languages the model supports, overriding its own card declaration for the language-fit check."
|
|
100
|
+
},
|
|
101
|
+
"chunkTokens": { "type": "integer", "minimum": 1, "description": "Chunk size ceiling in estimated tokens for small-context models; default 500." }
|
|
88
102
|
}
|
|
89
103
|
},
|
|
90
104
|
"content": {
|
package/skills/sense/SKILL.md
CHANGED
|
@@ -12,15 +12,31 @@ SQL over a markdown tree, kept fresh by a filesystem check on every query. Every
|
|
|
12
12
|
Every result is a reference (path, metadata, excerpt), never file contents; prose enters context only when you Read it. Costs: `map` is fixed-size, a `search` row is tens of tokens, and a `peek` stays flat however large the note is. Which tool fits is a property of the question:
|
|
13
13
|
|
|
14
14
|
- A deterministic, factual answer over known fields (counts, filters, "which notes have X") is SQL: `sense sql`, a saved `{ sql }` entry, or `search --where`. Enumerates every match; same result regardless of phrasing.
|
|
15
|
-
- Locating notes about something is `search`, one text through every engine the scope has: word match (bare words AND-join, one absent word = zero lexical rows; write `a OR b OR c` for any-word), link-graph expansion, and vector similarity, fused into one ranked list. Read `via` per row: `match` rows contained your words; `vector`-only rows did not. A `vector`-only row means the search words don't appear in that note; it showed up because the model judged it semantically related. Vector rows are conceptual similarity, not typo-tolerance; false positives are expected, labeled, and bounded by `--k
|
|
15
|
+
- Locating notes about something is `search`, one text through every engine the scope has: word match (bare words AND-join, one absent word = zero lexical rows; write `a OR b OR c` for any-word), link-graph expansion, and vector similarity, fused into one ranked list. Read `via` per row: `match` rows contained your words; `vector`-only rows did not. A `vector`-only row means the search words don't appear in that note; it showed up because the model judged it semantically related. Vector rows are conceptual similarity, not typo-tolerance; false positives are expected, labeled, and bounded by `--k` -- and they are the only rows a search can produce when note and query share no vocabulary at all, the paraphrase and category-for-instance cases words cannot reach. A scope searches with vectors when its preset's `signals` include `vectors` (on by default whenever the tree names an `embed` model); a preset that declares `"signals": {"words": 1, "links": 1}` searches on words and links only. A preset that asks for vectors when the model is not downloaded is an error naming `sense download`, not a quieter result: the same search must not answer differently before and after a download.
|
|
16
16
|
- `map` answers "what is this tree" (fields, hub notes, recent changes) when the tree is unfamiliar.
|
|
17
17
|
- `peek <path>` prices a file before you pay for it: outline with `[L143-162, ~380t]` ranges and links both ways. Every list shows its first 20 with the true total; the `sections` and `links` tables hold the rest, so a peek costs a few hundred tokens on any note. Its link totals count distinct notes: "links out" dedupes written targets by resolved note and lists unresolved targets separately, while `COUNT(*) FROM links WHERE src = ?` counts every written target, resolved or not, so the raw count can read higher without either number being wrong.
|
|
18
18
|
- `path <a> <b>` walks the link graph for a chain connecting two notes, or reports none within the depth bound: it answers how they connect, not just that both exist.
|
|
19
|
-
- `related <note>` ranks notes near in meaning to one note that it does not already link to: the links it is missing. It reads the meaning-vectors, so it needs vectors on for the scope and scans them, costing about what a
|
|
19
|
+
- `related <note>` ranks notes near in meaning to one note that it does not already link to: the links it is missing. It reads the meaning-vectors, so it needs the `vectors` signal on for the scope and scans them, costing about what a vector `search` does, not what a `peek` does. The model named in the config fetches once per machine at the first vector search (progress on stderr; `sense download` prefetches where that timing matters). A `model` pointing at a local directory with missing files is an error naming it, for `search` and `related` alike, not a quieter result.
|
|
20
20
|
- When you know the file and need its contents, `Read` it. sense adds nothing there. On large files peek's ranges let you read just one section; small files are often cheaper whole.
|
|
21
21
|
|
|
22
22
|
Output defaults to a table, built for humans; `--format json` returns the same rows machine-parseable, and `--format csv` returns one row per line for `grep` and `awk`. csv keeps every character a value holds, embedded newlines included, but cannot express NULL versus an empty string or a value's type, which json can. The commands that emit rows (`sql`, `search`, `related`, saved queries) take all three; `map`, `peek`, `status`, and `path` render a structure rather than a row set and take table or json. That also makes a saved query usable as a CI/hook gate with zero added mechanism: `[ "$(sense <name> --format json)" = "[]" ]` is true exactly when it returned no rows.
|
|
23
23
|
|
|
24
|
+
## Three signals
|
|
25
|
+
|
|
26
|
+
`search` composes up to three engines; which ones run is the preset's `signals` (every signal whose prerequisites hold, by default). Each exists because it reads evidence the others cannot:
|
|
27
|
+
|
|
28
|
+
| signal | reads | uniquely finds | blind to |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| `words` | the text itself (BM25) | every literal occurrence: identifiers, error strings, names, exact phrases; deterministic | anything phrased differently -- a note saying "compensation floor" for the query "minimum pay" |
|
|
31
|
+
| `links` | connections authors wrote | what the tree's own structure treats as related: context the matching text never restates | notes nobody linked |
|
|
32
|
+
| `vectors` | per-chunk meaning-vectors | notes sharing no words with the query: paraphrase, the category for an instance, a concept restated | proving presence -- a vector row cannot show the words occur anywhere; `hit` can |
|
|
33
|
+
|
|
34
|
+
Each signal in the map carries a weight (`{"words": 1, "links": 1, "vectors": 1}` is the default when the key is omitted entirely); presence turns a signal on, and the number scales its share of the fused ranking. Equal weight (1 for everything) is what every number elsewhere in this doc describes. A weight above 1 pulls the fused ranking toward that signal's own ordering: measured on nfcorpus with the default static model and on MIRACL zh with an HTTP encoder, equal-weight fusion helps English nfcorpus but ranks the encoder's MIRACL-zh results below its own cosine-only ranking (benchmark/reports/2026-08-27-embedding-model-selection.md, weight-sweep table) -- there is no single weight that is right for both, so a preset that leans on a strong encoder is a candidate for a higher `vectors` weight, checked against that table rather than assumed.
|
|
35
|
+
|
|
36
|
+
Which signal carries a search is a property of the query, and the ends of the range are measured (BENCHMARKING.md, "Retrieval quality"): on the vocabulary-gap corpus, 31% of queries have no relevant lexical row in their top 10 and vector rows are the only recall; on a corpus whose queries quote their documents, words alone hit 99.7% and vectors add nothing. Real trees sit between. An exact identifier is words territory; "notes about X" where X could be phrased many ways is where vector rows carry; "how do these connect" is the link graph (`path`, `peek`).
|
|
37
|
+
|
|
38
|
+
Attribution is already per-row: one fused search shows which engines earned each hit (`via`), so reading the labels across a few queries is the cheapest way to learn which signals this tree rewards. To isolate a signal harder, declare presets differing only in `signals` and run the same text through both; the row diff is the excluded signal's contribution. The labels also matter downstream: relayed to a human, they distinguish "contains these words" from "related by meaning", which is the difference between a citation and a lead.
|
|
39
|
+
|
|
24
40
|
## Commands
|
|
25
41
|
|
|
26
42
|
```
|
|
@@ -36,13 +52,13 @@ sense --list | status | download
|
|
|
36
52
|
```
|
|
37
53
|
|
|
38
54
|
- Terms pass verbatim to FTS5 MATCH. Bare words AND-join (one absent word means zero rows), so write `OR` yourself when you want any-word matching; double-quote punctuated terms (`"customer-facing"`, `"founder's"`); invalid syntax is an error, not a rewrite. The same rules apply to search commands you write into subagent briefs.
|
|
39
|
-
- When a search misses,
|
|
55
|
+
- When a search misses, both sides have levers. Lexical: OR-in synonyms and concrete instances (the index only knows the words in the files; a note about a specific tool rarely names its category), raise `--k` (a row costs tens of tokens), widen the scope (`--preset`, or `--include` for an ad-hoc glob). Vector: restate the concept in different words -- vectors rank the meaning of the whole query text, so a rephrase moves them even when every literal word still misses -- and pivot through the nearest hit with `related <path>` to walk its meaning-neighbourhood. Vector-only rows in a miss are themselves evidence: `similarity` and the snippet say whether the concept exists in the tree under other words. Each widening adds candidates and dilutes ranking, so the noise trade-off runs both ways.
|
|
40
56
|
- A frontmatter query enumerates its matches deterministically; search ranks by term overlap, so results shift as phrasing shifts. Trade-off: a query needs a known field, search doesn't.
|
|
41
57
|
- The `via` column says what produced each row: `match` (words hit), `link` (connected to notes that hit), `vector` (near in meaning), and combinations. The `lines` column, when set, points at the section that earned the row (the best-matching chunk on vector rows, the term cluster's section on large lexical notes) and is a direct `Read` range; null means the whole note is the reference.
|
|
42
58
|
- Scope is one vocabulary shared by `search`, `map`, `peek`, `path`, and `related`: bare command uses the config's `default` preset; `--preset <name>` picks another (unknown names error, listing what's declared); `--include <glob>` and `--exclude <glob>` are ad-hoc globs for one command, each overriding its own side of the preset, so one does not clear the other; `--no-exclude` drops the preset's `exclude` for one command, the only way to widen past it without editing config (it widens the query scope, not the index: a file no preset covers is never indexed). `--where` takes any SQL condition against frontmatter alias `f`, not only field equality: `"f.status = 'active' AND has(f.tags, 'x')"`, `"datetime(f.created) >= datetime(?)"`. There is no whole-index flag: a broad `default` preset, or a declared `all` preset (`include ["**/*"]`), is the whole tree. `sense status` shows every preset with its coverage. `sql` scopes differently: it runs over the whole index by default, and `--preset <name>` *binds* the scope as a temporary `scope(path)` table your statement joins, rather than filtering behind the query's back (`JOIN scope ON scope."path" = f.path`). Naming a preset without joining `scope` is a usage error, since it would return everything while reading as scoped. Without the flag, join `preset_files` directly, which is the same coverage under a preset name you write into the SQL.
|
|
43
59
|
- `score` is a rank-fusion value: it ranks rows within one result set and is not comparable across queries, not a relevance magnitude. It encodes how many signals fired and at what rank, so a perfect lexical hit and a weak vector-only hit can read the same number. With vectors active, rows carry `similarity`: the cosine (-1 to 1) of the query against that file's best-matching chunk (the same chunk the `lines` range points at). It orders vector evidence within a result set; the range it spans depends on the corpus and the embedding model, and compresses on small trees, where even a nonsense query has a moderately near neighbour somewhere. Compare similarities within a result set rather than against a fixed cutoff carried between trees.
|
|
44
60
|
- Vector rankings read the whole chunk, boilerplate included, so on a tree whose notes are mostly one template with a line of unique text (a directory of plugins, people, or assets), the shared scaffolding dominates every vector and `related` returns near-ties at the top of the range for any seed. Two signs, both visible in the output already: the top `similarity` values sit within a hair of each other, and the same few notes come back for unrelated seeds. Compare neighbour lists across two unlike seeds when a tree looks like this; matching lists mean the ranking is reading the template, not the content, and `search` over the distinguishing words is the answer instead.
|
|
45
|
-
- Absence evidence lives in the labels: a `
|
|
61
|
+
- Absence evidence lives in the labels: a preset whose `signals` exclude `vectors` (or a tree with no `embed` block) returns 0 rows when the words are nowhere in it. Default `search` always returns up to `k` rows (nearest-neighbour search has a nearest neighbour for any input), so a result of only `via: vector` rows IS the absence signal for the words themselves; `similarity` and the snippet are the evidence for judging whether a vector row is a real conceptual hit.
|
|
46
62
|
- A `queries` entry names the verb it runs, mirroring the two commands: `"dead-links": { "sql": "SELECT src, target FROM links WHERE dst IS NULL AND lower(target) NOT GLOB '*.[a-z0-9]*'" }` runs as `sense dead-links`, and `"hot": { "search": "pricing OR billing", "preset": "raw", "k": 20 }` runs as `sense hot` with its settings baked in, so repeat runs need no flags. An invocation-level `--preset`, `--k`, or `--where` overrides a saved search's value; `--list` labels each entry `(sql)` or `(search)`.
|
|
47
63
|
- Running an entry is how it is validated: a typo'd column, stale SQL, bad FTS5 syntax or an unknown preset errors and exits nonzero. A parameterised entry validates with any argument, since SQL is prepared before parameters bind (`sense by-tag zzz` reports `no such column` if the column is wrong, `(0 rows)` if it is right). To sweep a whole config after editing it, read the exit code: 0 ran, 2 means it needs parameters (re-run it with any argument to validate the SQL), anything else is broken.
|
|
48
64
|
|
|
@@ -109,7 +125,7 @@ Worked traces: [EXAMPLES.md](EXAMPLES.md).
|
|
|
109
125
|
## Setup and upkeep
|
|
110
126
|
|
|
111
127
|
- Missing CLI: `npm install -g sensemaking`. Missing config: `sense init` at the tree root. Discovery walks up from cwd; `--config <path>` overrides. Setting up or restructuring a tree (presets, frontmatter conventions, note design) is the `sense-setup` skill. Translating an Obsidian Bases `.base` file into equivalent queries is the `sense-bases` skill.
|
|
112
|
-
- `map` and `status` report each preset's coverage (files matched, embedded count). Indexing derives from presets, so the coverage numbers are how you see what a config actually indexes and embeds. A scope with fewer signals just uses fewer (a
|
|
128
|
+
- `map` and `status` report each preset's coverage (files matched, embedded count). Indexing derives from presets, so the coverage numbers are how you see what a config actually indexes and embeds. A scope with fewer signals just uses fewer (a preset without the vectors signal searches lexically); a saved search naming an unknown preset errors when run, listing the declared ones.
|
|
113
129
|
- Save a query into `sense.config.json` only when it will be reused; run ad-hoc otherwise.
|
|
114
130
|
- A one-line `summary:` per note is optional and pays twice: it appears in result rows and is a weighted search field. Date comparisons work for dates written as ISO 8601 (`2026-08-12`, or with time and offset); other formats do not compare. Field names in examples (`status`, `tags`, `created`) are illustrative; your tree defines its own.
|
|
115
131
|
- Reserved frontmatter keys (dropped with a warning): `path`, `_mtime`, `_ctime`, `_size`, `_rank`, `_parse_error`, `content`, `links`, `sections`. The `tags` frontmatter column and the `tags` table coexist, mirroring Obsidian's own split: the column is the raw YAML list one note's frontmatter declares (Obsidian's `tags` property), the table is the merged, deduplicated frontmatter+inline set per note (what Obsidian's tag pane and Bases' `file.tags` read). "What is tagged X" is a table query; the column answers only what a note's frontmatter literally says. Inline tags inside `%%...%%` comments are indexed -- some trees run their whole maintenance-tag system in comments.
|
|
@@ -8,12 +8,12 @@ Four tree shapes, each with its config and the commands an agent actually runs.
|
|
|
8
8
|
|
|
9
9
|
```json
|
|
10
10
|
{
|
|
11
|
-
"version":
|
|
11
|
+
"version": 5,
|
|
12
12
|
"presets": {
|
|
13
13
|
"default": { "include": ["wiki/**/*.md"], "k": 10 },
|
|
14
14
|
"raw": { "include": ["raw/**/*.md"], "k": 5 }
|
|
15
15
|
},
|
|
16
|
-
"embed": { "model": "minishlab/potion-retrieval-32M", "
|
|
16
|
+
"embed": { "model": "minishlab/potion-retrieval-32M", "provider": "static" },
|
|
17
17
|
"queries": {
|
|
18
18
|
"uncompiled": { "sql": "SELECT path, _mtime FROM frontmatter WHERE path LIKE 'raw/%' AND path NOT IN (SELECT dst FROM links WHERE dst IS NOT NULL) ORDER BY _mtime DESC" },
|
|
19
19
|
"stubs": { "sql": "SELECT path, _size FROM frontmatter WHERE path LIKE 'wiki/%' AND _size < 500 ORDER BY _size" },
|
|
@@ -37,12 +37,12 @@ What the shape buys: bare search never ranks raw noise above compiled pages; the
|
|
|
37
37
|
|
|
38
38
|
```json
|
|
39
39
|
{
|
|
40
|
-
"version":
|
|
40
|
+
"version": 5,
|
|
41
41
|
"presets": {
|
|
42
42
|
"default": { "include": ["memory/**/*.md"], "k": 10 },
|
|
43
43
|
"archive": { "include": ["archive/**/*.md"], "k": 10 }
|
|
44
44
|
},
|
|
45
|
-
"embed": { "model": "minishlab/potion-retrieval-32M", "
|
|
45
|
+
"embed": { "model": "minishlab/potion-retrieval-32M", "provider": "static" },
|
|
46
46
|
"queries": {
|
|
47
47
|
"project": { "sql": "SELECT path, kind, created, title FROM frontmatter WHERE project = ? ORDER BY created DESC" },
|
|
48
48
|
"steers": { "sql": "SELECT path, created, title FROM frontmatter WHERE kind = 'steer' AND project = ? ORDER BY created" },
|
|
@@ -73,12 +73,12 @@ Presets are structural (live vs archived); per-project filtering is metadata (`p
|
|
|
73
73
|
|
|
74
74
|
```json
|
|
75
75
|
{
|
|
76
|
-
"version":
|
|
76
|
+
"version": 5,
|
|
77
77
|
"presets": {
|
|
78
78
|
"default": { "include": ["reviews/**/*.md", "notes/**/*.md"], "k": 10 },
|
|
79
79
|
"source": { "include": ["sources/**/*.md"], "k": 5 }
|
|
80
80
|
},
|
|
81
|
-
"embed": { "model": "minishlab/potion-retrieval-32M", "
|
|
81
|
+
"embed": { "model": "minishlab/potion-retrieval-32M", "provider": "static" },
|
|
82
82
|
"queries": {
|
|
83
83
|
"unsupported": { "sql": "SELECT path, title FROM frontmatter WHERE path LIKE 'reviews/%' AND path NOT IN (SELECT src FROM links WHERE dst LIKE 'notes/%')" },
|
|
84
84
|
"unread": { "sql": "SELECT path FROM frontmatter WHERE path LIKE 'sources/%' AND path NOT IN (SELECT dst FROM links WHERE dst IS NOT NULL)" },
|
|
@@ -9,7 +9,7 @@ Querying an existing tree is the `sense` skill. This one covers making a tree: i
|
|
|
9
9
|
|
|
10
10
|
## Setup
|
|
11
11
|
|
|
12
|
-
- `npm install -g sensemaking`, then `sense init` at the tree root writes `sense.config.json`: two presets (`default`, and `large` showing what a big tree tunes) and an `embed` block naming the model.
|
|
12
|
+
- `npm install -g sensemaking`, then `sense init` at the tree root writes `sense.config.json`: two presets (`default`, and `large` showing what a big tree tunes) and an `embed` block naming the model. The model fetches once per machine at the first vector search (progress on stderr); `sense download` prefetches it instead where that timing matters (CI, air-gapped setup). Config discovery walks up from cwd; `--config <path>` overrides.
|
|
13
13
|
- Globs resolve relative to the config file, never the cwd.
|
|
14
14
|
- `sense status` and `sense map` show each preset's coverage (files matched, embedded count), so what a config actually indexes is always visible in output. A config edit that changes coverage rebuilds the cache and names the preset that caused it on stderr.
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ A preset is a named, self-contained bundle of settings. `default` (required) is
|
|
|
21
21
|
|---|---|---|
|
|
22
22
|
| `include` / `exclude` | which files this preset covers (globs) | required |
|
|
23
23
|
| `k` | how many results a search returns | 10 |
|
|
24
|
-
| `
|
|
24
|
+
| `signals` | which engines this preset's searches compose, each mapped to its RRF weight (`{"words": 1, "links": 1, "vectors": 1}`) | every signal whose prerequisites hold, each at weight 1 |
|
|
25
25
|
| `where` | a standing SQL filter on frontmatter | none |
|
|
26
26
|
|
|
27
27
|
**Indexing derives from presets.** A file is indexed if any preset includes it. Consequences worth designing around:
|
|
@@ -30,9 +30,11 @@ A preset is a named, self-contained bundle of settings. `default` (required) is
|
|
|
30
30
|
- Presets may overlap; they are views, not partitions.
|
|
31
31
|
- Global `features` (`links`, `sections`, `rank`) still toggle tree-wide; most trees never touch them.
|
|
32
32
|
|
|
33
|
-
**Vectors take two decisions, in two places.** The top-level `"embed": { "model", "
|
|
33
|
+
**Vectors take two decisions, in two places.** The top-level `"embed": { "model", "provider": "static"|"openai"|"cohere", "url", "key", "chunkTokens" }` block names the model and says whether the tree has vectors at all. `chunkTokens` is a chunk size ceiling in estimated tokens for small-context models; default 500. A preset's `signals` says which engines that scope uses: a layer searched for exact wording (ingested sources, archives, generated output) declares `"signals": {"words": 1, "links": 1}`, costs no embedding, and its searches run on words and links. That is the main scale lever, and it is the llm-wiki split: compiled pages searched by meaning, raw sources searched for the phrasing you are citing. Each named signal's number is its RRF weight, not a toggle -- 1 is the default and reproduces equal-weight fusion; a preset can instead raise one signal's number, e.g. `{"words": 1, "vectors": 4}`, to shift the fused ranking toward that signal without dropping the others. Whether that helps is corpus- and model-contingent, not a fixed rule: benchmark/reports/2026-08-27-embedding-model-selection.md's weight-sweep table measures equal weight against {0.5, 1, 2, 4} and vectors-only on nfcorpus and on MIRACL zh with an HTTP encoder, and the two corpora do not agree on which weight wins. `static` is the built-in pure-JS Model2Vec loader and handles paraphrase and reworded concepts; tight domain jargon ("heart attack" for "myocardial infarction") is where an `openai`- or `cohere`-shaped encoder model tends to do better, measured in the same report's encoder-tier tables. Naming the model in the config is the consent to fetch it: the first vector search downloads it once per machine into `~/.sense/models` (or `sense download` prefetches) (huggingface_hub's cache layout, one snapshot directory per resolved revision), so several models coexist and switching between them rebuilds the index rather than mixing vector spaces. A `model` holding a path instead of a Hugging Face id points at a local directory, which `sense download` reports as nothing to fetch. The first search after that embeds the tree (progress on stderr; minutes on tens of thousands of notes, seconds on small trees). A config edit that changes coverage or features rebuilds the cache, vectors included, so settle presets before the first vector search on a large tree or that embedding run is paid twice.
|
|
34
34
|
|
|
35
|
-
**
|
|
35
|
+
**Finding a model.** The default, `potion-retrieval-32M`, is English only. A tree whose text is mostly a language the model does not declare fails loudly at embed time (`EMBED_MODEL_MISMATCH`, naming the fix), and `sense status` shows the detected language mix beside the model's declared languages. A model whose card declares no languages leaves that check off, and a mismatched pairing then degrades silently -- nearest-neighbour search always returns a neighbour regardless of fit -- so check the card's languages yourself when the tree is not English. Picking a model is a lookup against the source, not a name to memorize: for a static model, filter Hugging Face's model2vec library for the target language and read the card for its declared languages, its safetensors shape, and F32 weights (an int8 republish fails the loader's dtype check by design). For an encoder reached over HTTP, Ollama's embedding-model library and LM Studio's catalog list each model's languages and context length; both serve an OpenAI-shaped endpoint, so `provider: "openai"` with `url` pointing at the local port reaches either with no other config. Cohere's hosted models are reached with `provider: "cohere"` instead. One dated measurement stands in for a name table that would go stale: `potion-retrieval-32M` was the best-measured static English retrieval model as of 2026-08, per benchmark/reports/2026-08-27-embedding-model-selection.md's static-ladder table.
|
|
36
|
+
|
|
37
|
+
**Large vaults**: everything except the vector build is measured linear to 100k notes with no tuning (BENCHMARKING.md). The knobs that matter are `k` (more, smaller results; rows carry `lines` section ranges, so agents read sections, not files) and `"signals": {"words": 1, "links": 1}` on the layers that do not earn vectors.
|
|
36
38
|
|
|
37
39
|
## Tree design decisions
|
|
38
40
|
|
|
@@ -45,6 +47,6 @@ These belong to the tree's owner. sense works with any of them and reads no inst
|
|
|
45
47
|
- **Language.** No decision needed. A language written without word spaces (Chinese, Japanese, Thai, Khmer, Lao, Burmese) is indexed per grapheme and searched as an ordered grapheme phrase, so `sense search "全文"` finds what it should. This is substring semantics, what `grep` gives: a query matches wherever its exact text occurs, including inside a longer run, and needs no minimum length. A language written with spaces is left exactly as it was, storing nothing extra, and its stemming is unaffected. The one place this does not reach is a hand-written `content MATCH '...'`, which cannot be rewritten for its author: pass the terms through `segment()` there. `content.tokenize` is a separate lever with a different purpose, substring matching inside a Latin word (`trigram`) or keeping hyphenated terms whole (`unicode61 tokenchars '-_'`); naming one turns the grapheme-phrase scheme off, since the tree has then chosen its own scheme. Changing it rebuilds the text index only; vectors, links, and sections are kept.
|
|
46
48
|
- **Summaries.** A one-line `summary:` is optional and pays twice: it shows in every result row (often answering a question with no file read) and is a weighted search field ranked above body text. The cost is writing and maintaining the line as notes change.
|
|
47
49
|
- **Folder shape.** Globs find the files, paths are queryable text, links resolve by basename at any depth, but presets make folders meaningful: a folder is the natural unit that gets its own coverage and settings.
|
|
48
|
-
- **Note size.** Many small notes: precise search hits, whole-file reads stay cheap, more links to maintain. Fewer large notes: `sections`, `peek`, and the `lines` column carry the cost down to line-range reads. Both work.
|
|
50
|
+
- **Note size.** Many small notes: precise search hits, whole-file reads stay cheap, more links to maintain. Fewer large notes: `sections`, `peek`, and the `lines` column carry the cost down to line-range reads. Both work. A long section no longer becomes one oversized vector either: chunking splits at headings and caps each chunk around 500 estimated tokens (CJK counted 1:1, spaced scripts ~4:1), so an oversized note degrades to more, smaller chunks rather than one truncated one; `embed.chunkTokens` lowers that cap further for a small-context model.
|
|
49
51
|
- **Recurring questions.** Save a scenario an agent will repeat under `queries`, naming the verb it runs: `{ "sql": "..." }` for filters and reports, or `{ "search": "...", "preset": "raw", "k": 5 }` for a ranked search. Either runs as `sense <name>`, and running one is how it is validated: a typo'd column or an unknown preset errors and exits nonzero. A parameterised entry validates with any argument, since SQL is prepared before parameters bind.
|
|
50
52
|
- **Where decisions live.** Choices that should outlive one conversation can be recorded in the agent's own instruction or skill files, or in a note in the tree itself; a one-off search over an existing corpus needs none of that.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/column-hint.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite';\n\n// 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\nexport function columnHint(db: DatabaseSync, 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 columns = (db.prepare('PRAGMA table_info(frontmatter)').all() as Array<{ name: string }>).map((c) => c.name);\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":["columnHint","startsWithBoundary","name","prefix","length","startsWith","test","db","err","match","exec","message","token","aliasStripped","replace","forms","Set","columns","prepare","all","map","c","candidates","form","add","size","quoted","split","join","Error"],"mappings":";;;;+BAWgBA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAThB,0FAA0F;AAC1F,4FAA4F;AAC5F,wFAAwF;AACxF,8EAA8E;AAE9E,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;AAEO,SAASJ,WAAWO,EAAgB,EAAEC,GAAU;IACrD,IAAMC,QAAQ,wBAAwBC,IAAI,CAACF,IAAIG,OAAO;IACtD,IAAI,CAACF,OAAO,OAAOD;IACnB,IAAMI,QAAQH,KAAK,CAAC,EAAE;IACtB,uFAAuF;IACvF,wFAAwF;IACxF,8DAA8D;IAC9D,IAAMI,gBAAgBD,MAAME,OAAO,CAAC,mBAAmB;IACvD,IAAMC,QAAQ,IAAIC,IAAI;QAACJ;QAAOC;KAAc;IAC5C,IAAMI,UAAU,AAACV,GAAGW,OAAO,CAAC,kCAAkCC,GAAG,GAA+BC,GAAG,CAAC,SAACC;eAAMA,EAAEnB,IAAI;;IACjH,IAAMoB,aAAa,IAAIN;QAClB,kCAAA,2BAAA;;QAAL,QAAK,YAAcC,4BAAd,SAAA,6BAAA,QAAA,yBAAA,iCAAuB;YAAvB,IAAMf,OAAN;gBACE,mCAAA,4BAAA;;gBAAL,QAAK,aAAca,0BAAd,UAAA,8BAAA,SAAA,0BAAA,kCAAqB;oBAArB,IAAMQ,OAAN;oBACH,IAAIrB,SAASqB,QAAQtB,mBAAmBC,MAAMqB,OAAOD,WAAWE,GAAG,CAACtB;gBACtE;;gBAFK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAGP;;QAJK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAKL,IAAIoB,WAAWG,IAAI,KAAK,GAAG,OAAOjB;IAClC,IAAMkB,SAAS,AAAC,qBAAGJ,YAAYF,GAAG,CAAC,SAAClB;eAAS,AAAC,IAA8B,OAA3BA,KAAKyB,KAAK,CAAC,KAAKC,IAAI,CAAC,OAAM;OAAIA,IAAI,CAAC;IACrF,OAAO,IAAIC,MAAM,AAAC,GAAoBH,OAAlBlB,IAAIG,OAAO,EAAC,QAAa,OAAPe,QAAO;AAC/C"}
|
package/dist/cjs/fences.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/fences.ts"],"sourcesContent":["// Shared line-fence tracker for tags/sections/embed. Opener: >=3 backticks or tildes at column\n// 0 -- no indent allowance, a deliberate divergence from CommonMark's up-to-3-space rule (see\n// test/unit/fences.test.ts DIVERGENCES table). A backtick opener's info string must not itself\n// contain a backtick (spec rule). A closer is a run of the SAME character, length >= the\n// opener's, holding nothing but trailing spaces after the run.\n\nexport interface FenceTracker {\n feed(line: string): boolean; // true iff this line is a fence delimiter (open or close)\n readonly inFence: boolean;\n}\n\nconst BACKTICK_OPEN = /^(`{3,})(.*)$/;\nconst TILDE_OPEN = /^(~{3,})(.*)$/;\n\nexport function fenceTracker(): FenceTracker {\n let inFence = false;\n let fenceChar = '';\n let fenceLen = 0;\n return {\n feed(line: string): boolean {\n if (!inFence) {\n const bt = BACKTICK_OPEN.exec(line);\n if (bt && !bt[2].includes('`')) {\n inFence = true;\n fenceChar = '`';\n fenceLen = bt[1].length;\n return true;\n }\n const td = TILDE_OPEN.exec(line);\n if (td) {\n inFence = true;\n fenceChar = '~';\n fenceLen = td[1].length;\n return true;\n }\n return false;\n }\n const run = fenceChar === '`' ? /^(`+)(.*)$/ : /^(~+)(.*)$/;\n const m = run.exec(line);\n if (m && m[1].length >= fenceLen && m[2].trim() === '') {\n inFence = false;\n return true;\n }\n return false;\n },\n get inFence() {\n return inFence;\n },\n };\n}\n\n// Masks <!-- ... --> spans that may cross line boundaries, one line at a time so callers can\n// interleave it with their own per-line state. In isolation an unclosed <!-- stays open forever\n// (mask() has no notion of a line boundary that should kill it); maskRegions() below is what\n// calls close() at the point an unclosed comment actually dies -- a blank line at paragraph\n// level, or its enclosing HTML block's end.\nexport interface CommentTracker {\n mask(line: string): string;\n close(): void; // force-ends an unclosed comment (paragraph blank line, or its HTML block ending)\n readonly inComment: boolean;\n}\n\nexport function commentTracker(): CommentTracker {\n let inComment = false;\n return {\n mask(line: string): string {\n let out = '';\n let i = 0;\n while (i < line.length) {\n if (inComment) {\n const end = line.indexOf('-->', i);\n if (end === -1) {\n out += ' '.repeat(line.length - i);\n i = line.length;\n } else {\n out += ' '.repeat(end + 3 - i);\n i = end + 3;\n inComment = false;\n }\n continue;\n }\n const start = line.indexOf('<!--', i);\n if (start === -1) {\n out += line.slice(i);\n i = line.length;\n } else {\n out += `${line.slice(i, start)} `;\n i = start + 4;\n inComment = true;\n }\n }\n return out;\n },\n close() {\n inComment = false;\n },\n get inComment() {\n return inComment;\n },\n };\n}\n\n// CommonMark's HTML-block type-6 list (fixed by the spec, not a drifting enumeration): a line\n// starting with an open or close tag of one of these, at column 0 (leading whitespace/`>`\n// blockquote markers tolerated), opens a block that swallows following lines -- tags, links,\n// and comments alike -- until a blank line closes it.\nconst HTML_BLOCK_TAGS = new Set([\n 'address',\n 'article',\n 'aside',\n 'base',\n 'basefont',\n 'blockquote',\n 'body',\n 'caption',\n 'center',\n 'col',\n 'colgroup',\n 'dd',\n 'details',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'frame',\n 'frameset',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hr',\n 'html',\n 'iframe',\n 'legend',\n 'li',\n 'link',\n 'main',\n 'menu',\n 'menuitem',\n 'nav',\n 'noframes',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'param',\n 'search',\n 'section',\n 'summary',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'title',\n 'tr',\n 'track',\n 'ul',\n]);\n// Type-1 blocks (script/pre/style/textarea): closes on the line holding the matching end tag,\n// not on a blank line, and that line is the last one swallowed.\nconst HTML_PRE_TAGS = new Set(['script', 'pre', 'style', 'textarea']);\nconst HTML_PRE_CLOSE_RE = /<\\/(?:script|pre|style|textarea)>/i; // any of the four closers ends the block, not only the tag that opened it\n// An opening or closing tag at column 0, tag name captured for the lookups above.\nconst HTML_BLOCK_OPEN_RE = /^<\\/?([a-zA-Z][a-zA-Z0-9]*)(?:[ \\t]|\\/?>|$)/;\nconst BLANK_LINE_RE = /^[ \\t>]*$/; // whitespace/blockquote-markers only -- a paragraph break, and what ends a type-6 block\n\n// Body with fenced-code, HTML-block, and <!-- --> comment regions replaced by spaces (newlines\n// preserved, so line numbers and offsets survive) plus inline code spans masked. The single\n// region masker for tags/links: fence and HTML-block delimiter+content lines are opaque, an\n// unclosed comment dies at its containing block's end (or the next blank line at paragraph\n// level -- never silently to end of file), and a closed comment masks exactly its span.\n// Bodies without a backtick/tilde/`<` fast-path out untouched.\nexport function maskRegions(body: string): string {\n if (!/[`~<]/.test(body)) return body;\n const fence = fenceTracker();\n const comment = commentTracker();\n let inHtmlBlock = false;\n let htmlBlockClose: RegExp | null = null; // set while inside a type-1 (script/pre/style/textarea) block\n return body\n .split('\\n')\n .map((line) => {\n if (inHtmlBlock) {\n if (htmlBlockClose) {\n if (htmlBlockClose.test(line)) {\n inHtmlBlock = false;\n htmlBlockClose = null;\n }\n return ' '.repeat(line.length);\n }\n if (BLANK_LINE_RE.test(line)) {\n // Block content never feeds the comment tracker, so an inner <!-- was only ever\n // masked text; nothing to close here.\n inHtmlBlock = false;\n return line;\n }\n return ' '.repeat(line.length);\n }\n if (!comment.inComment) {\n const isDelim = fence.feed(line);\n if (isDelim || fence.inFence) return ' '.repeat(line.length);\n }\n const uncommented = comment.inComment || line.includes('<!--') ? comment.mask(line) : line;\n if (comment.inComment && BLANK_LINE_RE.test(line)) comment.close(); // paragraph-level: dies at the next blank line\n // Indented or blockquoted HTML blocks still swallow their content in Obsidian, so the\n // opener test runs after stripping leading whitespace and > markers.\n const stripped = uncommented.replace(/^[ \\t>]*/, '');\n if (stripped[0] === '<') {\n const openMatch = HTML_BLOCK_OPEN_RE.exec(stripped);\n if (openMatch) {\n const tagName = openMatch[1].toLowerCase();\n const isClosingTag = stripped[1] === '/';\n if (!isClosingTag && HTML_PRE_TAGS.has(tagName)) {\n // The end condition can be met on the opening line itself: <script>x</script>\n // is a one-line block and the next line parses (Obsidian-verified).\n if (!HTML_PRE_CLOSE_RE.test(stripped.slice(openMatch[0].length))) {\n inHtmlBlock = true;\n htmlBlockClose = HTML_PRE_CLOSE_RE;\n }\n return ' '.repeat(line.length);\n }\n if (HTML_BLOCK_TAGS.has(tagName)) {\n inHtmlBlock = true;\n return ' '.repeat(line.length);\n }\n }\n }\n // Inline code spans hide their content too: `[[x]]` in prose is not a link.\n return uncommented.includes('`') ? maskCodeSpans(uncommented) : uncommented;\n })\n .join('\\n');\n}\n\n// A code span opens on a run of N backticks and closes at the next run of exactly N -- a\n// shorter or longer run in between is literal text, not a delimiter (CommonMark code spans).\n// Masked with spaces so column positions and tag-boundary whitespace are unaffected.\nexport function maskCodeSpans(line: string): string {\n let out = '';\n let i = 0;\n while (i < line.length) {\n if (line[i] !== '`') {\n out += line[i];\n i++;\n continue;\n }\n let j = i;\n while (line[j] === '`') j++;\n const n = j - i;\n let k = j;\n let closeStart = -1;\n let closeEnd = -1;\n while (k < line.length) {\n if (line[k] !== '`') {\n k++;\n continue;\n }\n let m = k;\n while (line[m] === '`') m++;\n if (m - k === n) {\n closeStart = k;\n closeEnd = m;\n break;\n }\n k = m;\n }\n if (closeStart >= 0) {\n out += ' '.repeat(closeEnd - i);\n i = closeEnd;\n } else {\n out += line.slice(i, j);\n i = j;\n }\n }\n return out;\n}\n"],"names":["commentTracker","fenceTracker","maskCodeSpans","maskRegions","BACKTICK_OPEN","TILDE_OPEN","inFence","fenceChar","fenceLen","feed","line","bt","exec","includes","length","td","run","m","trim","inComment","mask","out","i","end","indexOf","repeat","start","slice","close","HTML_BLOCK_TAGS","Set","HTML_PRE_TAGS","HTML_PRE_CLOSE_RE","HTML_BLOCK_OPEN_RE","BLANK_LINE_RE","body","test","fence","comment","inHtmlBlock","htmlBlockClose","split","map","isDelim","uncommented","stripped","replace","openMatch","tagName","toLowerCase","isClosingTag","has","join","j","n","k","closeStart","closeEnd"],"mappings":"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"}
|
package/dist/cjs/graph.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/graph.ts"],"sourcesContent":["// Link-graph math: PageRank at reconcile, personalized PageRank at query time. Pure JS, no deps.\n\nexport type Edge = [src: string, dst: string];\n\n// Power iteration. `personal` biases both teleport and dangling mass toward seed nodes;\n// without it this is plain PageRank (uniform base). Returns scores summing to ~1.\nexport function pagerank(nodes: string[], edges: Edge[], opts: { damping?: number; iterations?: number; personal?: Map<string, number> } = {}): Map<string, number> {\n const damping = opts.damping ?? 0.85;\n const iterations = opts.iterations ?? 30;\n const n = nodes.length;\n if (n === 0) return new Map();\n\n const index = new Map(nodes.map((node, i) => [node, i]));\n const out: number[][] = nodes.map(() => []);\n for (const [src, dst] of edges) {\n const si = index.get(src);\n const di = index.get(dst);\n if (si !== undefined && di !== undefined) out[si].push(di);\n }\n\n let base: number[];\n if (opts.personal) {\n base = nodes.map(() => 0);\n let total = 0;\n for (const [node, weight] of opts.personal) {\n const i = index.get(node);\n if (i !== undefined && weight > 0) {\n base[i] = weight;\n total += weight;\n }\n }\n if (total === 0) return new Map(nodes.map((node) => [node, 0]));\n base = base.map((b) => b / total);\n } else {\n base = nodes.map(() => 1 / n);\n }\n\n let rank = [...base];\n for (let iter = 0; iter < iterations; iter++) {\n const next = base.map((b) => (1 - damping) * b);\n let dangling = 0;\n for (let i = 0; i < n; i++) {\n if (out[i].length === 0) {\n dangling += rank[i];\n continue;\n }\n const share = (damping * rank[i]) / out[i].length;\n for (const j of out[i]) next[j] += share;\n }\n for (let i = 0; i < n; i++) next[i] += damping * dangling * base[i];\n rank = next;\n }\n return new Map(nodes.map((node, i) => [node, rank[i]]));\n}\n\n// Connective expansion: walk the graph (undirected -- backlinks relate as much as links)\n// from a seed result set. Answers \"what is linked to the notes that matched\".\nexport function personalizedRank(nodes: string[], edges: Edge[], seeds: Map<string, number>): Map<string, number> {\n const undirected: Edge[] = [];\n for (const [src, dst] of edges) {\n undirected.push([src, dst], [dst, src]);\n }\n return pagerank(nodes, undirected, { damping: 0.7, iterations: 15, personal: seeds });\n}\n"],"names":["pagerank","personalizedRank","nodes","edges","opts","damping","iterations","n","length","Map","index","map","node","i","out","src","dst","si","get","di","undefined","push","base","personal","total","weight","b","rank","iter","next","dangling","share","j","seeds","undirected"],"mappings":"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"}
|
package/dist/cjs/output.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output.ts"],"sourcesContent":["// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output is left alone.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, and deliberately not cell(): csv is the format for redirecting a result to a\n// file, so it keeps every character, embedded newlines included. What it cannot carry is\n// NULL vs empty string, or a value's type -- that is what json is for.\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// Header names come from a row wherever there is one: a statement's column list keeps\n// duplicates that the row object has already collapsed, so `SELECT a AS x, b AS x` would print\n// b's value under both headers. `columns` is the fallback that labels a 0-row result, and with\n// no rows and no statement (a bounded command that found nothing) csv writes nothing at all --\n// a bare newline would read to a csv parser as one empty record.\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Collapsed the same way a row object collapses them, so a statement naming a column\n // twice describes itself identically whether it matched anything or not.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: rows arrive from an\n// iterator, so a large result is never held here as rows and again as a rendered string.\n// Table buffers by necessity (a column is as wide as its widest cell, which the last row can\n// change); json and csv write row by row. The writes are synchronous, so when stdout is a pipe\n// Node buffers what the reader has not taken yet -- the saving is this module's copies, not\n// the operating system's.\nexport function printRowStream(rows: Iterable<Row>, format: RowFormat, columns: string[]): void {\n const iterator = rows[Symbol.iterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = iterator.next();\n const rest: Iterable<Row> = { [Symbol.iterator]: () => iterator };\n\n if (format === 'table') {\n printRows(first.done ? [] : [first.value, ...rest], format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n // JSON.stringify throws on BigInt, so a row with an int64 past 2^53 (setReadBigInts) is\n // converted via the replacer: a value that fits a safe integer stays a number, a larger one\n // becomes its decimal string, since a JSON number cannot carry it losslessly.\n const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\n const bigintSafe = (_key: string, value: unknown) => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n const indent = (row: Row) =>\n JSON.stringify(row, bigintSafe, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\nfunction renderRows(rows: Row[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return JSON.stringify(rows, null, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const cells = rows.map((row) => columns.map((col) => cell(row[col])));\n const natural = columns.map((col, i) => Math.max(col.length, ...cells.map((row) => row[i].length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...cells.map(formatRow)].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a semantic-off preset says which.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.semantic === false ? ' (semantic: false)' : ''}`)];\n}\n\nexport function renderMap(result: { docs: { count: number; bytes: number }; fields: Row[]; fieldsTotal: number; features: { on: string[]; off: string[] }; presets: Array<{ name: string; files: number; embedded: number; semantic?: boolean }>; hubs: Row[]; recent: Row[]; recentCaveat: string | null }): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:');\n if (result.recentCaveat) parts.push(result.recentCaveat);\n parts.push(renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: { path: string; tokens: number; frontmatter: Row; parseError?: string | null; sections: Row[]; outbound: string[]; backlinks: string[]; unresolved: string[]; sectionsTotal: number; outboundTotal: number; backlinksTotal: number; unresolvedTotal: number; off: string[] }): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level as number)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","test","csvLine","values","map","join","warnOversize","bytes","rowCount","console","warn","Math","round","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","Symbol","first","next","rest","done","write","process","stdout","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","width","cells","col","natural","i","clip","w","padEnd","slice","formatRow","trimEnd","repeat","features","off","on","presets","p","files","embedded","semantic","result","parts","docs","count","fields","fieldsTotal","push","hubs","includes","recentCaveat","recent","lines","path","tokens","parseError","entries","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
|
package/dist/cjs/progress.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/progress.ts"],"sourcesContent":["// Progress on stderr only, so it can never corrupt --format json. A TTY gets one\n// self-overwriting line; a pipe gets a few append-only ones, not redraw frames.\n\nconst NON_TTY_MILESTONES = 4;\n\nexport interface Progress {\n tick(done: number): void;\n finish(): void;\n}\n\n// `total` known upfront; `label` names the work (\"embedding notes\", \"reparsing files\").\n// Silent entirely below `threshold` -- short work needs no narration.\nexport function progress(label: string, total: number, threshold = 200): Progress {\n if (total < threshold) return { tick() {}, finish() {} };\n\n const started = Date.now();\n const isTTY = process.stderr.isTTY === true;\n let lastShown = 0;\n let wrote = false;\n\n const line = (done: number) => {\n const elapsed = (Date.now() - started) / 1000;\n // Estimate from observed rate, only once there is a rate to observe.\n const eta = done > 0 && done < total ? `, ~${Math.max(1, Math.round((elapsed / done) * (total - done)))}s left` : '';\n return `${label}: ${done}/${total}${eta}`;\n };\n\n return {\n tick(done: number) {\n if (isTTY) {\n process.stderr.write(`\\r${line(done)}`);\n wrote = true;\n return;\n }\n // Sparse milestones: first tick, then every 1/NON_TTY_MILESTONES of the total.\n if (done === lastShown) return;\n if (lastShown === 0 || done - lastShown >= total / NON_TTY_MILESTONES) {\n process.stderr.write(`${line(done)}\\n`);\n lastShown = done;\n wrote = true;\n }\n },\n finish() {\n if (!wrote) return;\n if (isTTY) process.stderr.write(`\\r${line(total)}\\n`);\n else if (lastShown < total) process.stderr.write(`${line(total)}\\n`);\n },\n };\n}\n"],"names":["progress","NON_TTY_MILESTONES","label","total","threshold","tick","finish","started","Date","now","isTTY","process","stderr","lastShown","wrote","line","done","elapsed","eta","Math","max","round","write"],"mappings":";;;;+BAYgBA;;;eAAAA;;;AAZhB,iFAAiF;AACjF,gFAAgF;AAEhF,IAAMC,qBAAqB;AASpB,SAASD,SAASE,KAAa,EAAEC,KAAa;QAAEC,YAAAA,iEAAY;IACjE,IAAID,QAAQC,WAAW,OAAO;QAAEC,MAAAA,SAAAA,QAAQ;QAAGC,QAAAA,SAAAA,UAAU;IAAE;IAEvD,IAAMC,UAAUC,KAAKC,GAAG;IACxB,IAAMC,QAAQC,QAAQC,MAAM,CAACF,KAAK,KAAK;IACvC,IAAIG,YAAY;IAChB,IAAIC,QAAQ;IAEZ,IAAMC,OAAO,cAACC;QACZ,IAAMC,UAAU,AAACT,CAAAA,KAAKC,GAAG,KAAKF,OAAM,IAAK;QACzC,qEAAqE;QACrE,IAAMW,MAAMF,OAAO,KAAKA,OAAOb,QAAQ,AAAC,MAAgE,OAA3DgB,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAAC,AAACJ,UAAUD,OAASb,CAAAA,QAAQa,IAAG,KAAK,YAAU;QAClH,OAAO,AAAC,GAAYA,OAAVd,OAAM,MAAYC,OAARa,MAAK,KAAWE,OAARf,OAAY,OAAJe;IACtC;IAEA,OAAO;QACLb,MAAAA,SAAAA,KAAKW,IAAY;YACf,IAAIN,OAAO;gBACTC,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,KAAe,OAAXP,KAAKC;gBAC/BF,QAAQ;gBACR;YACF;YACA,+EAA+E;YAC/E,IAAIE,SAASH,WAAW;YACxB,IAAIA,cAAc,KAAKG,OAAOH,aAAaV,QAAQF,oBAAoB;gBACrEU,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,GAAa,OAAXP,KAAKC,OAAM;gBACnCH,YAAYG;gBACZF,QAAQ;YACV;QACF;QACAR,QAAAA,SAAAA;YACE,IAAI,CAACQ,OAAO;YACZ,IAAIJ,OAAOC,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,KAAgB,OAAZP,KAAKZ,QAAO;iBAC5C,IAAIU,YAAYV,OAAOQ,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,GAAc,OAAZP,KAAKZ,QAAO;QAClE;IACF;AACF"}
|
package/dist/cjs/scan.d.cts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Config } from './config/index.js';
|
|
2
|
-
import type { Feature } from './features/types.js';
|
|
3
|
-
export declare const RESERVED_COLUMNS: Set<string>;
|
|
4
|
-
export interface FileStat {
|
|
5
|
-
relPath: string;
|
|
6
|
-
absPath: string;
|
|
7
|
-
mtimeMs: number;
|
|
8
|
-
ctimeMs: number;
|
|
9
|
-
size: number;
|
|
10
|
-
presets: string[];
|
|
11
|
-
embed: boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare function toPosixPath(relPath: string, separator?: string): string;
|
|
14
|
-
export declare function listFiles(cfg: Config, baseDir: string): FileStat[];
|
|
15
|
-
export interface ParsedDoc {
|
|
16
|
-
relPath: string;
|
|
17
|
-
mtimeMs: number;
|
|
18
|
-
ctimeMs: number;
|
|
19
|
-
size: number;
|
|
20
|
-
presets: string[];
|
|
21
|
-
data: Record<string, string | number | bigint | null>;
|
|
22
|
-
parseError: string | null;
|
|
23
|
-
search: {
|
|
24
|
-
title: string;
|
|
25
|
-
summary: string;
|
|
26
|
-
text: string;
|
|
27
|
-
};
|
|
28
|
-
extracted: Record<string, unknown>;
|
|
29
|
-
}
|
|
30
|
-
export declare function looksLikeDatetime(value: string): boolean;
|
|
31
|
-
export declare function normalizeDate(value: string): string;
|
|
32
|
-
export declare function parseFile(file: FileStat, extractors?: Feature[]): {
|
|
33
|
-
doc: ParsedDoc;
|
|
34
|
-
warnings: string[];
|
|
35
|
-
};
|
package/dist/cjs/scan.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Config } from './config/index.js';
|
|
2
|
-
import type { Feature } from './features/types.js';
|
|
3
|
-
export declare const RESERVED_COLUMNS: Set<string>;
|
|
4
|
-
export interface FileStat {
|
|
5
|
-
relPath: string;
|
|
6
|
-
absPath: string;
|
|
7
|
-
mtimeMs: number;
|
|
8
|
-
ctimeMs: number;
|
|
9
|
-
size: number;
|
|
10
|
-
presets: string[];
|
|
11
|
-
embed: boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare function toPosixPath(relPath: string, separator?: string): string;
|
|
14
|
-
export declare function listFiles(cfg: Config, baseDir: string): FileStat[];
|
|
15
|
-
export interface ParsedDoc {
|
|
16
|
-
relPath: string;
|
|
17
|
-
mtimeMs: number;
|
|
18
|
-
ctimeMs: number;
|
|
19
|
-
size: number;
|
|
20
|
-
presets: string[];
|
|
21
|
-
data: Record<string, string | number | bigint | null>;
|
|
22
|
-
parseError: string | null;
|
|
23
|
-
search: {
|
|
24
|
-
title: string;
|
|
25
|
-
summary: string;
|
|
26
|
-
text: string;
|
|
27
|
-
};
|
|
28
|
-
extracted: Record<string, unknown>;
|
|
29
|
-
}
|
|
30
|
-
export declare function looksLikeDatetime(value: string): boolean;
|
|
31
|
-
export declare function normalizeDate(value: string): string;
|
|
32
|
-
export declare function parseFile(file: FileStat, extractors?: Feature[]): {
|
|
33
|
-
doc: ParsedDoc;
|
|
34
|
-
warnings: string[];
|
|
35
|
-
};
|