sensemaking 0.24.4 → 0.24.6
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 +16 -12
- package/dist/cjs/cli/status.js +14 -24
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/search.js +22 -0
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/config/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/lib/watch-notification.d.cts +1 -0
- package/dist/cjs/lib/watch-notification.d.ts +1 -0
- package/dist/cjs/lib/watch-notification.js +15 -0
- package/dist/cjs/lib/watch-notification.js.map +1 -0
- package/dist/cjs/lib/worker-file.d.cts +1 -0
- package/dist/cjs/lib/worker-file.d.ts +1 -0
- package/dist/cjs/lib/worker-file.js +34 -0
- package/dist/cjs/lib/worker-file.js.map +1 -0
- package/dist/cjs/output/search-error.js +38 -0
- package/dist/cjs/output/search-error.js.map +1 -1
- package/dist/cjs/scan/pool.js +2 -23
- package/dist/cjs/scan/pool.js.map +1 -1
- package/dist/cjs/store/builder.d.cts +2 -1
- package/dist/cjs/store/builder.d.ts +2 -1
- package/dist/cjs/store/builder.js +4 -4
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/duckdb/lexical.d.cts +1 -0
- package/dist/cjs/store/duckdb/lexical.d.ts +1 -0
- package/dist/cjs/store/duckdb/lexical.js +28 -9
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +2 -0
- package/dist/cjs/store/duckdb/native.d.ts +2 -0
- package/dist/cjs/store/duckdb/native.js +11 -1
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/ordered-bm25.d.cts +17 -0
- package/dist/cjs/store/duckdb/ordered-bm25.d.ts +17 -0
- package/dist/cjs/store/duckdb/ordered-bm25.js +238 -0
- package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -0
- package/dist/cjs/store/lock-wait.d.cts +2 -2
- package/dist/cjs/store/lock-wait.d.ts +2 -2
- package/dist/cjs/store/lock-wait.js +14 -11
- package/dist/cjs/store/lock-wait.js.map +1 -1
- package/dist/cjs/store/native.d.cts +4 -0
- package/dist/cjs/store/native.d.ts +4 -0
- package/dist/cjs/store/native.js +64 -9
- package/dist/cjs/store/native.js.map +1 -1
- package/dist/cjs/store/open.js +11 -7
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/reconcile.d.cts +5 -1
- package/dist/cjs/store/reconcile.d.ts +5 -1
- package/dist/cjs/store/reconcile.js +5 -4
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/turso/lexical.js +5 -1
- package/dist/cjs/store/turso/lexical.js.map +1 -1
- package/dist/cjs/text/segment.js +168 -3
- package/dist/cjs/text/segment.js.map +1 -1
- package/dist/cjs/watch-claim.d.cts +39 -0
- package/dist/cjs/watch-claim.d.ts +39 -0
- package/dist/cjs/watch-claim.js +446 -0
- package/dist/cjs/watch-claim.js.map +1 -0
- package/dist/cjs/watch.js +246 -147
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/watch-heartbeat.d.cts +1 -0
- package/dist/cjs/workers/watch-heartbeat.d.ts +1 -0
- package/dist/cjs/workers/watch-heartbeat.js +308 -0
- package/dist/cjs/workers/watch-heartbeat.js.map +1 -0
- package/dist/esm/cli/status.js +6 -5
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/search.js +21 -0
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/lib/watch-notification.d.ts +1 -0
- package/dist/esm/lib/watch-notification.js +4 -0
- package/dist/esm/lib/watch-notification.js.map +1 -0
- package/dist/esm/lib/worker-file.d.ts +1 -0
- package/dist/esm/lib/worker-file.js +24 -0
- package/dist/esm/lib/worker-file.js.map +1 -0
- package/dist/esm/output/search-error.js +21 -0
- package/dist/esm/output/search-error.js.map +1 -1
- package/dist/esm/scan/pool.js +2 -22
- package/dist/esm/scan/pool.js.map +1 -1
- package/dist/esm/store/builder.d.ts +2 -1
- package/dist/esm/store/builder.js +4 -4
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/duckdb/lexical.d.ts +1 -0
- package/dist/esm/store/duckdb/lexical.js +16 -7
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +2 -0
- package/dist/esm/store/duckdb/native.js +5 -1
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/ordered-bm25.d.ts +17 -0
- package/dist/esm/store/duckdb/ordered-bm25.js +56 -0
- package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -0
- package/dist/esm/store/lock-wait.d.ts +2 -2
- package/dist/esm/store/lock-wait.js +17 -14
- package/dist/esm/store/lock-wait.js.map +1 -1
- package/dist/esm/store/native.d.ts +4 -0
- package/dist/esm/store/native.js +60 -6
- package/dist/esm/store/native.js.map +1 -1
- package/dist/esm/store/open.js +9 -6
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/reconcile.d.ts +5 -1
- package/dist/esm/store/reconcile.js +4 -3
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/turso/lexical.js +5 -1
- package/dist/esm/store/turso/lexical.js.map +1 -1
- package/dist/esm/text/segment.js +130 -4
- package/dist/esm/text/segment.js.map +1 -1
- package/dist/esm/watch-claim.d.ts +39 -0
- package/dist/esm/watch-claim.js +176 -0
- package/dist/esm/watch-claim.js.map +1 -0
- package/dist/esm/watch.js +169 -118
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/watch-heartbeat.d.ts +1 -0
- package/dist/esm/workers/watch-heartbeat.js +106 -0
- package/dist/esm/workers/watch-heartbeat.js.map +1 -0
- package/package.json +2 -2
- package/skills/sense/SKILL.md +105 -104
- package/skills/sense/references/search.md +47 -0
- package/skills/sense/references/sql.md +120 -0
- package/skills/sense/references/stores/duckdb.md +35 -0
- package/skills/sense/references/stores/sqlite.md +66 -0
- package/skills/sense/references/stores/turso.md +36 -0
- package/skills/sense-setup/SKILL.md +93 -34
- package/skills/sense-setup/references/embeddings.md +51 -0
- package/skills/sense-setup/references/store-benchmarks.md +16 -0
- package/skills/sense-setup/references/stores/duckdb.md +28 -0
- package/skills/sense-setup/references/stores/sqlite.md +21 -0
- package/skills/sense-setup/references/stores/turso.md +25 -0
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Every file becomes rows in these tables, plus whatever an enabled feature adds o
|
|
|
43
43
|
| table | holds | for |
|
|
44
44
|
|---|---|---|
|
|
45
45
|
| `frontmatter` | one column per key, plus `path`, `_mtime`, `_size`, `_rank`, `_parse_error` | filtering |
|
|
46
|
-
| `content` | `title`, `summary`, `text`, `path
|
|
46
|
+
| `content` | `title`, `summary`, `text`, `path` | text search and ranking |
|
|
47
47
|
| `links` | `src`, `target` as written, `dst` resolved (`NULL` = dead link, but see the skill: a link to an attachment can never resolve) | graph |
|
|
48
48
|
| `tags` | `path`, `tag`; frontmatter and inline `#tags` merged and deduplicated, nested tags stored full | tag filters |
|
|
49
49
|
| `sections` | heading, `level`, `start_line`, `end_line`, `tokens` estimate | structure |
|
|
@@ -51,7 +51,7 @@ Every file becomes rows in these tables, plus whatever an enabled feature adds o
|
|
|
51
51
|
|
|
52
52
|
Results are references (path, title, summary, snippets), never file contents. Reading happens afterward through the filesystem, scoped to the line ranges `peek` returns. This is the [just-in-time context pattern](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents): the agent holds lightweight identifiers and loads payloads only when needed.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
`map` has fixed-size output, a `search` row is tens of tokens, and a `peek` stays flat however large the note is. What it saves over reading grows with the file; a small note is cheaper to read whole.
|
|
55
55
|
|
|
56
56
|
```sql
|
|
57
57
|
-- filter and search compose in one query
|
|
@@ -75,13 +75,13 @@ ORDER BY bm25(content, 10.0, 5.0, 1.0) LIMIT 10
|
|
|
75
75
|
| `init` | write a starter `sense.config.json` |
|
|
76
76
|
| `status` | index location, doc count, per-preset coverage, watcher heartbeat |
|
|
77
77
|
| `download` | fetch the embedding model named in the config (once per machine; the first vector search fetches it otherwise) |
|
|
78
|
-
| `watch` | keep the index warm in the background (optional; see [
|
|
78
|
+
| `watch` | keep the index warm in the background (optional; see [watch coordination](https://github.com/kmalakoff/sensemaking/blob/master/DESIGN.md#watch-coordination)) |
|
|
79
79
|
|
|
80
|
-
`search` runs one text through every engine its scope has: FTS5 word match (BM25-ranked, bare words AND-join, operators are yours on `sqlite`; on `duckdb` and `turso` the FTS5 operators are a named error, see Config), a personalized-PageRank walk over the link graph, and vector similarity, fused into one list. `via` labels each row's evidence (`match`, `link`, `vector`, combinations)
|
|
80
|
+
`search` runs one text through every engine its scope has: FTS5 word match (BM25-ranked, bare words AND-join, operators are yours on `sqlite`; on `duckdb` and `turso` the FTS5 operators are a named error, see Config), a personalized-PageRank walk over the link graph, and vector similarity, fused into one list. `via` labels each row's evidence (`match`, `link`, `vector`, combinations). Within the vector signal, candidates rank by the true cosine against the best-matching canonical chunk before `similarity` is rounded to three decimals for display; a zero-direction vector has similarity `0`, exact cosine ties use bytewise path order, and equal-scoring chunks choose the earliest authored chunk. The public search list ranks the combined word, link, and vector candidates by fused reciprocal-rank score. `lines` points at the section that earned the row (a direct read range). A `vector`-only row means the search words don't appear in that note; it showed up because the model judged it semantically related. `--preset` picks a named settings bundle from the config, `--where` filters on frontmatter. `--format json` on any reporting command returns structured output, and `--format csv` writes the row-returning commands one row per line, for redirecting a large result to a file instead of into context; `--version` and `--help` do what they say.
|
|
81
81
|
|
|
82
82
|
Search rows carry `snippets: string[]`. Each passage is generated around the matched words, marked with `«»`, and limited to 80 characters by default. `--snippet-count-limit` returns more non-overlapping passages from a note, in document order. Link- and vector-only rows have `snippets: []`.
|
|
83
83
|
|
|
84
|
-
Lexical words are case- and accent-insensitive. SQLite and DuckDB use their native English stem tokenizers; Turso's native Tantivy index has no stem tokenizer in the supported release, so it applies the shared Porter normalization to a derived field before native indexing. In every store, `run`, `running`, and `runs` match the same authored notes, while authored bytes are never rewritten. Quoted phrases require adjacent words, with punctuation treated as a separator, and punctuation-only input returns no lexical rows.
|
|
84
|
+
Lexical words are case- and accent-insensitive. SQLite and DuckDB use their native English stem tokenizers; Turso's native Tantivy index has no stem tokenizer in the supported release, so it applies the shared Porter normalization to a derived field before native indexing. In every store, `run`, `running`, and `runs` match the same authored notes, while authored bytes are never rewritten. Quoted phrases require adjacent words, with punctuation treated as a separator, and punctuation-only input returns no lexical rows. SQLite's native caret and `NEAR(...)` expressions over unspaced text use original FTS5 tokens rather than sidecar substring semantics; use an ordinary quoted search when substring findability matters, at the cost of positional filtering.
|
|
85
85
|
|
|
86
86
|
## Config
|
|
87
87
|
|
|
@@ -109,19 +109,25 @@ Lexical words are case- and accent-insensitive. SQLite and DuckDB use their nati
|
|
|
109
109
|
| `root` | optional markdown-tree path. Relative to the config directory; omitted means that directory. Preset globs, filesystem reads, watcher events, and indexed `path` values use this root. `.sense/` state stays beside the config. Changing it rebuilds the index. |
|
|
110
110
|
| `presets` | named bundles of `include`/`exclude` globs, `k` (result count), `signals` (which engines this scope searches with, `words`, `links`, `vectors`; every signal whose prerequisites hold, unless the preset lists them exhaustively), `where` (a standing SQL filter). A file is indexed if any preset includes it, embedded if a model is named and some covering preset's `signals` include `vectors`; `status` shows each preset's coverage. |
|
|
111
111
|
| `embed` | the model vectors are built with. Naming one gives the tree vectors; omitting the block means none at all, whatever the presets say. `sense download` fetches it. |
|
|
112
|
-
| `store` |
|
|
112
|
+
| `store` | `sqlite` by default, or the experimental `duckdb` and `turso`. Each engine uses its own cache file, so changing this setting rebuilds the index. |
|
|
113
113
|
| `queries` | entries runnable as `sense <name>`, each naming the verb it runs: `{ sql }` for SQL (`?` binds positional args) or `{ search }` for a ranked search with its settings baked in, so `sense hot` needs no flags. Running an entry validates it: a typo'd column errors and exits nonzero, and a parameterised entry validates with any argument, since preparing precedes binding. |
|
|
114
114
|
| `version` | schema version; older configs auto-migrate on load, noted on stderr. |
|
|
115
115
|
|
|
116
116
|
Bare commands use the `default` preset; `--preset` names another; flags override single fields. Editing a preset rebuilds the cache and says which preset caused it.
|
|
117
117
|
|
|
118
|
+
### Store choice
|
|
119
|
+
|
|
120
|
+
Choose `sqlite` for the smallest setup, full FTS5 query syntax, and concurrent Sense commands. Choose `duckdb` when the cache should participate in DuckDB analytical work over large datasets or in local/cloud workflows. Choose `turso` for its embedded Rust engine and Tantivy text index. The DuckDB and Turso adapters are experimental, install their native package on first use, and currently serialize Sense commands that open the same cache.
|
|
121
|
+
|
|
122
|
+
The commands and table names are shared. Raw SQL still follows the selected engine's dialect, and advanced FTS5 operators only work on `sqlite`.
|
|
123
|
+
|
|
118
124
|
Vectors need a model. Naming a Hugging Face id in `embed.model` is consent to fetch it: it downloads lazily, on the first vector search, with progress on stderr, into `~/.sense/models` (huggingface_hub's cache layout, one snapshot directory per resolved revision, shared by every tree, 124 MB, never in the package). `sense download` prefetches the same model ahead of time, so the wait happens on your schedule instead of the first query's; it is idempotent and prints the resolved revision. `embed.model` is a Hugging Face id, or a path to a directory holding `model.safetensors` and `tokenizer.json`, which nothing fetches for you. A preset that asks for vectors when a local model path is missing those files is an error naming the fix, rather than a quieter result that would make the same search answer differently before and after; a preset whose `signals` exclude `vectors` never asks, so it is unaffected. An optional top-level `"embed": { "model", "provider", "url", "key" }` block points at any Model2Vec model, local path, or OpenAI-compatible endpoint (Ollama, LM Studio, hosted). Embedding the notes themselves happens on the first vector search, with progress.
|
|
119
125
|
|
|
120
|
-
|
|
126
|
+
Sense adds `has(field, value)` for array membership or string containment and `basename(path)` for path queries on every store. SQLite and DuckDB also provide `segment(terms)` for hand-written matching over text without word spaces. A frontmatter syntax error records `_parse_error` and leaves that file's discovered fields empty; the file's content still enters the index.
|
|
121
127
|
|
|
122
128
|
## Providers
|
|
123
129
|
|
|
124
|
-
`embed.provider` picks the wire protocol; `embed.model` names the model. [
|
|
130
|
+
`embed.provider` picks the wire protocol; `embed.model` names the model. The [verified integrations](https://github.com/kmalakoff/sensemaking/blob/master/INTEGRATIONS.md) record what has actually been run against this codebase. Only those integrations are named as recommendations.
|
|
125
131
|
|
|
126
132
|
**static**. A local, pure-JS Model2Vec model; no network at query time.
|
|
127
133
|
|
|
@@ -153,9 +159,7 @@ Every query starts with a freshness check against the cache in `.sense/`; only c
|
|
|
153
159
|
|
|
154
160
|
- **Work is linear in note count.** Crawl, reconcile, and the freshness check are what every invocation pays; that check is the floor cost of a query and the first thing to watch on a large tree.
|
|
155
161
|
- **Output is flat.** `map`, `peek`, and a search row cost the same on a small tree as a large one: context cost is bounded by what you ask for, not by how much there is.
|
|
156
|
-
- **Bulk changes are paid by whoever queries next.** `sense watch` moves that re-parse into the background ([
|
|
157
|
-
|
|
158
|
-
Release assessments keep these claims measured. The ordinary assessment runs required common behavior and current-store work plus full portable NFCorpus on all three stores. The explicit deep profile adds portable FEVER, pinned corpora spanning a 4x range in note count, a stress tree that packs the worst measured shapes into one place, and legacy SQLite OR-bag continuity. Historical performance, quality, and output bands warn; failed required behavior, invalid or missing required evidence, explicit caller bounds or quality floors, and approved performance guards block. Current figures: [BENCHMARKING.md](BENCHMARKING.md).
|
|
162
|
+
- **Bulk changes are paid by whoever queries next.** `sense watch` moves that re-parse into the background ([watch coordination](https://github.com/kmalakoff/sensemaking/blob/master/DESIGN.md#watch-coordination)): it changes latency, never answers, since every query reconciles for itself. To start the cache over, delete the directory `sense status` prints.
|
|
159
163
|
|
|
160
164
|
## For AI agents
|
|
161
165
|
|
|
@@ -163,7 +167,7 @@ Release assessments keep these claims measured. The ordinary assessment runs req
|
|
|
163
167
|
npx skills add kmalakoff/sensemaking # -g for global, -a claude-code to target
|
|
164
168
|
```
|
|
165
169
|
|
|
166
|
-
Three skills: `sense` for querying a tree
|
|
170
|
+
Three skills: `sense` for querying a tree, including store-specific SQL and search guidance; `sense-setup` for creating one and choosing its store, presets, vectors, and note conventions; and `sense-bases` for translating an Obsidian Bases `.base` file into sense SQL.
|
|
167
171
|
|
|
168
172
|
## Prior art
|
|
169
173
|
|
package/dist/cjs/cli/status.js
CHANGED
|
@@ -24,6 +24,7 @@ var _httpts = require("../embed/http.js");
|
|
|
24
24
|
var _storets = require("../embed/store.js");
|
|
25
25
|
var _outputts = require("../output/output.js");
|
|
26
26
|
var _indexts1 = require("../store/index.js");
|
|
27
|
+
var _watchclaimts = require("../watch-claim.js");
|
|
27
28
|
var _indexts2 = require("./index.js");
|
|
28
29
|
var _sharedts = require("./shared.js");
|
|
29
30
|
function _array_like_to_array(arr, len) {
|
|
@@ -354,7 +355,7 @@ function languagesInfo(e) {
|
|
|
354
355
|
}
|
|
355
356
|
var status = function status(ctx) {
|
|
356
357
|
return _async_to_generator(function() {
|
|
357
|
-
var _ref, _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1,
|
|
358
|
+
var _ref, _ref1, _cfg_configDir, _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1, _cfg_configDir1, _cfg_queries, values, format, cfg, _ref2, store, dbPath, warnings, features, e, hasModel, reachable, _tmp, vectors, _tmp1, presets, _ref3, declaredLanguages, languagesState, languagesSource, detectedLanguages, cacheSchema, engine, watcher, keyEnv, result, _tmp2, migrated, shown, total, breakdown, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, line, pid, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, key, value;
|
|
358
359
|
return _ts_generator(this, function(_state) {
|
|
359
360
|
switch(_state.label){
|
|
360
361
|
case 0:
|
|
@@ -366,7 +367,7 @@ var status = function status(ctx) {
|
|
|
366
367
|
(0, _indexts1.openStore)(cfg)
|
|
367
368
|
];
|
|
368
369
|
case 1:
|
|
369
|
-
|
|
370
|
+
_ref2 = _state.sent(), store = _ref2.store, dbPath = _ref2.dbPath, warnings = _ref2.warnings;
|
|
370
371
|
(0, _sharedts.printWarnings)(warnings);
|
|
371
372
|
features = (0, _indexts.featureStates)(cfg);
|
|
372
373
|
e = (0, _indexts.embedConfig)(cfg);
|
|
@@ -415,35 +416,30 @@ var status = function status(ctx) {
|
|
|
415
416
|
];
|
|
416
417
|
case 8:
|
|
417
418
|
presets = _state.sent();
|
|
418
|
-
|
|
419
|
+
_ref3 = e ? languagesInfo(e) : {
|
|
419
420
|
languages: null,
|
|
420
421
|
state: null,
|
|
421
422
|
source: null
|
|
422
|
-
}, declaredLanguages =
|
|
423
|
+
}, declaredLanguages = _ref3.languages, languagesState = _ref3.state, languagesSource = _ref3.source;
|
|
423
424
|
return [
|
|
424
425
|
4,
|
|
425
426
|
(0, _distributionts.languageDistribution)(store)
|
|
426
427
|
];
|
|
427
428
|
case 9:
|
|
428
429
|
detectedLanguages = (_ref = _state.sent()) !== null && _ref !== void 0 ? _ref : null;
|
|
429
|
-
return [
|
|
430
|
-
4,
|
|
431
|
-
(0, _indexts1.getMeta)(store, 'watch_heartbeat')
|
|
432
|
-
];
|
|
433
|
-
case 10:
|
|
434
|
-
heartbeat = _state.sent();
|
|
435
430
|
return [
|
|
436
431
|
4,
|
|
437
432
|
(0, _indexts1.getMeta)(store, 'schema_version')
|
|
438
433
|
];
|
|
439
|
-
case
|
|
434
|
+
case 10:
|
|
440
435
|
cacheSchema = _state.sent();
|
|
441
436
|
return [
|
|
442
437
|
4,
|
|
443
438
|
store.engineStatus()
|
|
444
439
|
];
|
|
445
|
-
case
|
|
440
|
+
case 11:
|
|
446
441
|
engine = _state.sent();
|
|
442
|
+
watcher = (0, _watchclaimts.readWatchClaim)((_ref1 = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.rootDir) !== null && _ref1 !== void 0 ? _ref1 : cfg.baseDir);
|
|
447
443
|
// The env var holds the token; only its name and whether it is set are ever reported.
|
|
448
444
|
keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
|
|
449
445
|
name: e.key,
|
|
@@ -456,7 +452,7 @@ var status = function status(ctx) {
|
|
|
456
452
|
unknownConfigKeys: (_cfg_unknownKeys = cfg.unknownKeys) !== null && _cfg_unknownKeys !== void 0 ? _cfg_unknownKeys : null,
|
|
457
453
|
tree: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
|
|
458
454
|
treeRoot: (_cfg_rootDir1 = cfg.rootDir) !== null && _cfg_rootDir1 !== void 0 ? _cfg_rootDir1 : cfg.baseDir,
|
|
459
|
-
configDir: (
|
|
455
|
+
configDir: (_cfg_configDir1 = cfg.configDir) !== null && _cfg_configDir1 !== void 0 ? _cfg_configDir1 : cfg.baseDir,
|
|
460
456
|
cache: (0, _nodepath.dirname)(dbPath),
|
|
461
457
|
db: dbPath,
|
|
462
458
|
cacheSchema: cacheSchema
|
|
@@ -465,14 +461,14 @@ var status = function status(ctx) {
|
|
|
465
461
|
4,
|
|
466
462
|
(0, _indexts1.docCount)(store)
|
|
467
463
|
];
|
|
468
|
-
case
|
|
464
|
+
case 12:
|
|
469
465
|
_tmp2.docs = _state.sent();
|
|
470
466
|
return [
|
|
471
467
|
4,
|
|
472
468
|
parseErrorCount(store)
|
|
473
469
|
];
|
|
474
|
-
case
|
|
475
|
-
_tmp2.unparseableFrontmatter = _state.sent(), _tmp2.features = features.on, _tmp2.featuresOff = features.off, _tmp2.embed = e ? _object_spread({
|
|
470
|
+
case 13:
|
|
471
|
+
result = (_tmp2.unparseableFrontmatter = _state.sent(), _tmp2.features = features.on, _tmp2.featuresOff = features.off, _tmp2.embed = e ? _object_spread({
|
|
476
472
|
provider: e.provider,
|
|
477
473
|
model: e.model,
|
|
478
474
|
dir: e.provider === 'static' ? (0, _storets.modelDir)(e.model) : null,
|
|
@@ -483,13 +479,7 @@ var status = function status(ctx) {
|
|
|
483
479
|
languages: declaredLanguages,
|
|
484
480
|
languagesState: languagesState,
|
|
485
481
|
detectedLanguages: detectedLanguages
|
|
486
|
-
}, vectors !== null && vectors !== void 0 ? vectors : {}) : null, _tmp2.presets = presets, _tmp2.queries = Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length;
|
|
487
|
-
return [
|
|
488
|
-
4,
|
|
489
|
-
(0, _indexts1.getMeta)(store, 'watch_pid')
|
|
490
|
-
];
|
|
491
|
-
case 15:
|
|
492
|
-
result = (_tmp2.watcherPid = _state.sent(), _tmp2.watcherHeartbeatSecondsAgo = heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null, _tmp2.engine = engine, _tmp2);
|
|
482
|
+
}, vectors !== null && vectors !== void 0 ? vectors : {}) : null, _tmp2.presets = presets, _tmp2.queries = Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length, _tmp2.watcherPid = watcher ? String(watcher.pid) : null, _tmp2.watcherHeartbeatSecondsAgo = watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null, _tmp2.engine = engine, _tmp2);
|
|
493
483
|
if (format === 'json') {
|
|
494
484
|
console.log((0, _outputts.stringifyJson)(result, 2));
|
|
495
485
|
} else {
|
|
@@ -585,7 +575,7 @@ var status = function status(ctx) {
|
|
|
585
575
|
4,
|
|
586
576
|
store.close()
|
|
587
577
|
];
|
|
588
|
-
case
|
|
578
|
+
case 14:
|
|
589
579
|
_state.sent();
|
|
590
580
|
return [
|
|
591
581
|
2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a semantic-on preset with nothing embedded yet.\n// Reported here because a fast reconcile on such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\ntype LanguagesState = 'declared' | 'none' | 'unresolved' | null;\n\n// Config-declared languages win over the model card, for every provider, as registry.ts does.\n// A local-path model has no card by design, so it is never \"unresolved\": that means an HF id.\nfunction languagesInfo(e: NonNullable<ReturnType<typeof embedConfig>>): { languages: string[] | null; state: LanguagesState; source: 'config' | 'card' | null } {\n if (e.languages) return { languages: e.languages, state: 'declared', source: 'config' };\n if (e.provider !== 'static' || !isDownloadable(e.model)) return { languages: null, state: null, source: null };\n const cardLanguages = readLanguages(e.model);\n if (cardLanguages === undefined) return { languages: null, state: 'unresolved', source: null };\n if (cardLanguages.length === 0) return { languages: null, state: 'none', source: null };\n return { languages: cardLanguages, state: 'declared', source: 'card' };\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : { languages: null, state: null, source: null };\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n const heartbeat = await getMeta(store, 'watch_heartbeat');\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Each store owns what it reports and how it is worded (Store.engineStatus); this command\n // prints entries generically, without branching on any store's name.\n const engine = await store.engineStatus();\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.rootDir ?? cfg.baseDir,\n treeRoot: cfg.rootDir ?? cfg.baseDir,\n configDir: cfg.configDir ?? cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, languagesState, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: await getMeta(store, 'watch_pid'),\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n engine,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree root: ${result.treeRoot}`);\n console.log(`configDir: ${result.configDir}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches automatically at first search, or run \\`${ctx.name} download\\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);\n if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);\n else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n else if (languagesState === 'none') console.log(' languages: none declared by the model card');\n else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \\`${ctx.name} download\\`)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n for (const [key, value] of Object.entries(result.engine)) console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["redactUrl","vectorState","store","stmt","prepare","get","parseErrorCount","n","url","parsed","URL","username","password","toString","replace","embedReachable","e","base","provider","probeReachable","languagesInfo","languages","state","source","isDownloadable","model","cardLanguages","readLanguages","undefined","length","status","ctx","process","cfg","values","format","dbPath","warnings","features","hasModel","reachable","vectors","presets","declaredLanguages","languagesState","languagesSource","detectedLanguages","heartbeat","cacheSchema","engine","keyEnv","result","migrated","shown","total","breakdown","line","pid","key","value","parse","argv","USAGE","name","FORMAT","CONFIG","formatOf","resolveConfig","config","openStore","printWarnings","featureStates","embedConfig","modelPresent","presetCoverage","languageDistribution","getMeta","engineStatus","set","env","configPath","configVersion","SUPPORTED_CONFIG_VERSION","migratedFrom","unknownConfigKeys","unknownKeys","tree","rootDir","baseDir","treeRoot","configDir","cache","dirname","db","docCount","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","modelDir","downloaded","queries","Object","keys","watcherPid","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","stringifyJson","join","featuresLine","MODEL_FILENAMES","embedded","pending","reduce","a","b","entries","sort","map","code","presetsLines","padEnd","close"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { readWatchClaim } from '../watch-claim.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a semantic-on preset with nothing embedded yet.\n// Reported here because a fast reconcile on such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\ntype LanguagesState = 'declared' | 'none' | 'unresolved' | null;\n\n// Config-declared languages win over the model card, for every provider, as registry.ts does.\n// A local-path model has no card by design, so it is never \"unresolved\": that means an HF id.\nfunction languagesInfo(e: NonNullable<ReturnType<typeof embedConfig>>): { languages: string[] | null; state: LanguagesState; source: 'config' | 'card' | null } {\n if (e.languages) return { languages: e.languages, state: 'declared', source: 'config' };\n if (e.provider !== 'static' || !isDownloadable(e.model)) return { languages: null, state: null, source: null };\n const cardLanguages = readLanguages(e.model);\n if (cardLanguages === undefined) return { languages: null, state: 'unresolved', source: null };\n if (cardLanguages.length === 0) return { languages: null, state: 'none', source: null };\n return { languages: cardLanguages, state: 'declared', source: 'card' };\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : { languages: null, state: null, source: null };\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Each store owns what it reports and how it is worded (Store.engineStatus); this command\n // prints entries generically, without branching on any store's name.\n const engine = await store.engineStatus();\n const watcher = readWatchClaim(cfg.configDir ?? cfg.rootDir ?? cfg.baseDir);\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.rootDir ?? cfg.baseDir,\n treeRoot: cfg.rootDir ?? cfg.baseDir,\n configDir: cfg.configDir ?? cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, languagesState, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: watcher ? String(watcher.pid) : null,\n watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null,\n engine,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree root: ${result.treeRoot}`);\n console.log(`configDir: ${result.configDir}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches automatically at first search, or run \\`${ctx.name} download\\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);\n if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);\n else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n else if (languagesState === 'none') console.log(' languages: none declared by the model card');\n else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \\`${ctx.name} download\\`)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n for (const [key, value] of Object.entries(result.engine)) console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["redactUrl","vectorState","store","stmt","prepare","get","parseErrorCount","n","url","parsed","URL","username","password","toString","replace","embedReachable","e","base","provider","probeReachable","languagesInfo","languages","state","source","isDownloadable","model","cardLanguages","readLanguages","undefined","length","status","ctx","cfg","process","values","format","dbPath","warnings","features","hasModel","reachable","vectors","presets","declaredLanguages","languagesState","languagesSource","detectedLanguages","cacheSchema","engine","watcher","keyEnv","result","migrated","shown","total","breakdown","line","pid","key","value","parse","argv","USAGE","name","FORMAT","CONFIG","formatOf","resolveConfig","config","openStore","printWarnings","featureStates","embedConfig","modelPresent","presetCoverage","languageDistribution","getMeta","engineStatus","readWatchClaim","configDir","rootDir","baseDir","set","env","configPath","configVersion","SUPPORTED_CONFIG_VERSION","migratedFrom","unknownConfigKeys","unknownKeys","tree","treeRoot","cache","dirname","db","docCount","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","modelDir","downloaded","queries","Object","keys","watcherPid","String","watcherHeartbeatSecondsAgo","Math","round","Date","now","heartbeatMs","console","log","stringifyJson","join","featuresLine","MODEL_FILENAMES","embedded","pending","reduce","a","b","entries","sort","map","code","presetsLines","padEnd","close"],"mappings":"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"}
|
|
@@ -627,6 +627,27 @@ function lineRangeFor(store, path, line) {
|
|
|
627
627
|
});
|
|
628
628
|
})();
|
|
629
629
|
}
|
|
630
|
+
function validateSearchOptions(opts) {
|
|
631
|
+
for(var _i = 0, _iter = [
|
|
632
|
+
[
|
|
633
|
+
'k',
|
|
634
|
+
opts.k
|
|
635
|
+
],
|
|
636
|
+
[
|
|
637
|
+
'snippetCharLimit',
|
|
638
|
+
opts.snippetCharLimit
|
|
639
|
+
],
|
|
640
|
+
[
|
|
641
|
+
'snippetCountLimit',
|
|
642
|
+
opts.snippetCountLimit
|
|
643
|
+
]
|
|
644
|
+
]; _i < _iter.length; _i++){
|
|
645
|
+
var _iter__i = _sliced_to_array(_iter[_i], 2), name = _iter__i[0], value = _iter__i[1];
|
|
646
|
+
if (value !== undefined && (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0)) {
|
|
647
|
+
throw new _errorsts.SenseError('SEARCH_OPTION_INVALID', 'search option "'.concat(name, '" must be a positive finite integer, got ').concat(String(value)));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
630
651
|
function hydrateSearchRows(_0, _1, _2, _3, _4) {
|
|
631
652
|
return _async_to_generator(function(store, cfg, rows, matchedPaths, terms) {
|
|
632
653
|
var opts, _opts_snippetCharLimit, _opts_snippetCountLimit, bareTerms, charLimit, countLimit, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, row, text, _cfg_rootDir, _computeSnippets, snippets, offset, _tmp, err;
|
|
@@ -746,6 +767,7 @@ function search(_0, _1, _2) {
|
|
|
746
767
|
switch(_state.label){
|
|
747
768
|
case 0:
|
|
748
769
|
opts = _arguments.length > 3 && _arguments[3] !== void 0 ? _arguments[3] : {};
|
|
770
|
+
validateSearchOptions(opts);
|
|
749
771
|
effective = (0, _indexts.resolveSearch)(cfg, opts);
|
|
750
772
|
k = effective.k, signals = effective.signals;
|
|
751
773
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/search.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { stemmer } from 'stemmer';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { embedConfig, featureEnabled, resolveSearch } from '../config/index.ts';\nimport { localModelMissing, MODEL_FILENAMES } from '../embed/store.ts';\nimport { SenseError } from '../errors.ts';\nimport type { Row } from '../output/output.ts';\nimport { bareTermSyntaxError, searchError } from '../output/search-error.ts';\nimport type { LexicalHit, Store } from '../store/types.ts';\nimport { foldForSearch, hasUnspacedRun, searchTokens, unspacedRuns } from '../text/segment.ts';\nimport { materializeScope, narrowByWhere, rawScope, scopeHasEmbeddings } from './scope.ts';\nimport { linksCandidates, vectorsCandidates, wordsCandidates } from './signals.ts';\n\n// Default budget behind --snippet-char-limit/--snippet-count-limit: the limit is whatever the\n// caller passes, these only say what happens when they pass nothing (DESIGN.md \"Search snippets\").\nexport const SNIPPET_CHAR_LIMIT_DEFAULT = 80;\nexport const SNIPPET_COUNT_LIMIT_DEFAULT = 1;\n\n// Bare terms from an FTS5 query string: strips operators/quoting, not real terms, so the\n// snippet scan matches what the query matched -- FTS5 operators are uppercase-only, so this is too.\nfunction extractBareTerms(query: string): string[] {\n const cleaned = query\n .replace(/\"/g, ' ')\n .replace(/[()*]/g, ' ')\n .replace(/\\b(AND|OR|NOT|NEAR)\\b(\\/\\d+)?/g, ' ');\n return cleaned\n .split(/\\s+/)\n .map((tok) => tok.replace(/^[A-Za-z_]\\w*:/, '')) // column filter, e.g. title:term\n .flatMap((tok) => searchTokens(tok).map(({ text }) => text))\n .map((tok) => tok.toLowerCase().trim())\n .filter((tok) => tok.length > 0);\n}\n\n// House convention (src/chunk/group.ts): Intl.Segmenter word boundaries, not a bare \\b, which\n// is ASCII-only. Built on first use: construction is a few ms, paid only when a term matches.\nlet wordSegmenter: Intl.Segmenter | undefined;\n\nfunction findOccurrences(text: string, terms: string[]): Array<{ start: number; end: number; term: string }> {\n const occ: Array<{ start: number; end: number; term: string }> = [];\n const textLower = text.toLowerCase();\n\n // Unspaced scripts (UNSPACED_SCRIPTS) mark no word boundaries: the sense-setup skill promises\n // substring semantics there, so a matching term is found wherever it occurs in the run.\n const unspacedTerms = terms.filter(hasUnspacedRun);\n if (unspacedTerms.length > 0) {\n for (const run of unspacedRuns(text)) {\n const runLower = textLower.slice(run.start, run.end);\n for (const term of unspacedTerms) {\n let idx = 0;\n for (;;) {\n const found = runLower.indexOf(term, idx);\n if (found === -1) break;\n occ.push({ start: run.start + found, end: run.start + found + term.length, term });\n idx = found + term.length;\n }\n }\n }\n }\n\n // Spaced scripts: a word is marked when its porter stem equals a query term's stem, the same\n // algorithm both indexes tokenize with (sqlite's TOKENIZE = 'porter unicode61'; duckdb's fts default).\n const spacedTerms = terms.filter((t) => !hasUnspacedRun(t));\n if (spacedTerms.length > 0) {\n const termByStem = new Map(spacedTerms.map((t) => [stemmer(foldForSearch(t)), t]));\n const stemInitials = new Set(Array.from(termByStem.keys(), (term) => term[0]));\n for (const match of searchTokens(text)) {\n const segment = match.text;\n if (match.unspaced) continue;\n const folded = foldForSearch(segment);\n // Porter stemming changes suffixes only, so a different initial cannot match a query stem.\n if (!stemInitials.has(folded[0])) continue;\n const term = termByStem.get(stemmer(folded));\n if (term !== undefined) occ.push({ start: match.start, end: match.end, term });\n }\n }\n\n return occ.sort((a, b) => a.start - b.start || b.end - a.end);\n}\n\n// Segment boundaries of the whole text, word granularity: the only cut points a snippet edge\n// may land on. One rule for every script (DESIGN.md \"Cutting\") -- a regex \\b is ASCII-only and\n// would mis-cut Japanese, Chinese and Thai, which Intl.Segmenter divides by dictionary instead.\nfunction wordBoundaries(text: string): number[] {\n wordSegmenter ??= new Intl.Segmenter('en', { granularity: 'word' });\n const bounds = [0];\n for (const { index, segment } of wordSegmenter.segment(text)) bounds.push(index + segment.length);\n return bounds;\n}\n\n// bounds is sorted: snaps are binary searches, since each runs once per candidate window.\nfunction snapForward(bounds: number[], pos: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (bounds[mid] < pos) lo = mid + 1;\n else hi = mid;\n }\n return bounds[lo];\n}\n\nfunction snapBackward(bounds: number[], pos: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n let result = bounds[0];\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (bounds[mid] <= pos) {\n lo = mid;\n result = bounds[mid];\n } else hi = mid - 1;\n }\n return result;\n}\n\nfunction firstBoundAfter(bounds: number[], pos: number): number | undefined {\n let lo = 0;\n let hi = bounds.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (bounds[mid] <= pos) lo = mid + 1;\n else hi = mid;\n }\n return bounds[lo];\n}\n\n// A raw, unmarked upper bound: [start, end) inside [anchor, anchor+charLimit), edges on\n// boundaries. Markup (guillemets, ellipses) added on top of this can push the rendered result\n// past charLimit, which is what fitEnd() below corrects for; this is only the starting guess.\n// A single segment spanning the whole target window (a word longer than the char limit) is the\n// one case where holding the boundary rule means the budget is not a hard ceiling.\nfunction cutWindow(text: string, bounds: number[], anchor: number, charLimit: number): { start: number; end: number } {\n const rawEnd = Math.min(text.length, anchor + charLimit);\n const start = snapForward(bounds, anchor);\n let end = snapBackward(bounds, rawEnd);\n if (end <= start) end = firstBoundAfter(bounds, start) ?? text.length;\n return { start, end: Math.min(end, text.length) };\n}\n\n// The largest boundary <= upperBound, > floor, whose rendered [*, end) fits charLimit. Markup\n// only ever adds characters as end grows, so rendered length is non-decreasing in end and\n// shrinking from upperBound is guaranteed to find the true fit rather than guess at it.\n// `floor` is the one end this never shrinks past (the anchor's own marked word, or the first\n// word in the unmarked fallback): DESIGN.md's budget is a ceiling except here, where returning\n// nothing is worse than a single word that overruns it.\nfunction fitEnd(render: (end: number) => string, bounds: number[], floor: number, upperBound: number, charLimit: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (bounds[mid] <= upperBound) lo = mid;\n else hi = mid - 1;\n }\n for (; lo >= 0 && bounds[lo] > floor; lo--) {\n if (render(bounds[lo]).length <= charLimit) return bounds[lo];\n }\n return floor;\n}\n\ninterface Span {\n start: number;\n end: number;\n}\n\ninterface SnippetWindow extends Span {\n distinct: number;\n count: number;\n}\n\n// occ is start-sorted: a window's first candidate occurrence is a binary search, not a walk.\nfunction firstOccAtOrAfter(occ: Array<{ start: number; end: number; term: string }>, pos: number): number {\n let lo = 0;\n let hi = occ.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (occ[mid].start < pos) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction renderWindow(text: string, occ: Array<{ start: number; end: number; term: string }>, win: Span): string {\n let out = '';\n let cursor = win.start;\n for (let i = firstOccAtOrAfter(occ, win.start); i < occ.length && occ[i].start < win.end; i++) {\n const o = occ[i];\n if (o.end > win.end) continue;\n // Occurrences of duplicate or substring-overlapping terms (\"test tests\") can overlap;\n // emitting each would duplicate document text. Keep the first, absorb the rest.\n if (o.start < cursor) continue;\n out += `${text.slice(cursor, o.start)}«${text.slice(o.start, o.end)}»`;\n cursor = o.end;\n }\n out += text.slice(cursor, win.end);\n const prefix = win.start > 0 ? '…' : '';\n const suffix = win.end < text.length ? '…' : '';\n return `${prefix}${out.replace(/\\s+/g, ' ')}${suffix}`;\n}\n\n// Scores every occurrence-anchored candidate window: most distinct terms wins, ties broken by\n// most total hits -- coverage now that occurrences are real words, not the false-fragment counts\n// a substring scan produced. Selection itself is unevaluated (DESIGN.md \"Selection, unsettled\").\n// The window's `end` is fitted to the *rendered* text, markup included, not the raw span: a\n// window dense with marks (every guillemet pair adds two characters) shrinks to fit the same\n// budget a sparse one fills almost exactly.\nfunction scoreWindows(occ: Array<{ start: number; end: number; term: string }>, bounds: number[], text: string, charLimit: number): SnippetWindow[] {\n const candidates: SnippetWindow[] = [];\n for (let i = 0; i < occ.length; i++) {\n const winEnd = occ[i].start + charLimit;\n const seen = new Set<string>();\n let count = 0;\n for (let j = i; j < occ.length && occ[j].start < winEnd; j++) {\n seen.add(occ[j].term);\n count++;\n }\n const start = snapForward(bounds, occ[i].start);\n const floor = Math.max(start, occ[i].end);\n const upperBound = Math.max(floor, cutWindow(text, bounds, occ[i].start, charLimit).end);\n const end = fitEnd((e) => renderWindow(text, occ, { start, end: e }), bounds, floor, upperBound, charLimit);\n candidates.push({ start, end, distinct: seen.size, count });\n }\n return candidates;\n}\n\nfunction overlaps(a: Span, b: Span): boolean {\n return a.start < b.end && b.start < a.end;\n}\n\n// Same scoring function as a single snippet, kept rather than discarded (DESIGN.md \"Several\n// snippets per note\"): rank by score, take the top non-overlapping windows, then reorder to the\n// note's own order, since several passages from one note read as an abridged note.\nfunction selectWindows(candidates: SnippetWindow[], countLimit: number): { chosen: SnippetWindow[]; best: SnippetWindow } {\n const ranked = candidates.slice().sort((a, b) => b.distinct - a.distinct || b.count - a.count);\n const chosen: SnippetWindow[] = [];\n for (const c of ranked) {\n if (chosen.length >= countLimit) break;\n if (chosen.some((s) => overlaps(s, c))) continue;\n chosen.push(c);\n }\n chosen.sort((a, b) => a.start - b.start);\n return { chosen, best: ranked[0] };\n}\n\n// Builds bounded marked passages and returns the best window's offset for section lookup.\nexport function computeSnippets(text: string, terms: string[], charLimit: number, countLimit: number): { snippets: string[]; offset: number } {\n const occ = findOccurrences(text, terms);\n const bounds = wordBoundaries(text);\n if (occ.length === 0) {\n // A term matched only via title/summary, not this body text, finds no occurrence here;\n // fall back to the doc's start, unmarked.\n const render = (end: number): string => `${text.slice(0, end).replace(/\\s+/g, ' ').trim()}${end < text.length ? '…' : ''}`;\n const floor = bounds.find((b) => b > 0) ?? text.length;\n const upperBound = Math.max(floor, cutWindow(text, bounds, 0, charLimit).end);\n const end = fitEnd(render, bounds, floor, upperBound, charLimit);\n return { snippets: [render(end)], offset: 0 };\n }\n const candidates = scoreWindows(occ, bounds, text, charLimit);\n const { chosen, best } = selectWindows(candidates, countLimit);\n return { snippets: chosen.map((win) => renderWindow(text, occ, win)), offset: best.start };\n}\n\n// Converts an offset in the original text to its one-based line number.\nexport function lineNumberAt(text: string, offset: number): number {\n let line = 1;\n for (let i = 0; i < offset; i++) if (text.charCodeAt(i) === 10) line++;\n return line;\n}\n\nasync function lineRangeFor(store: Store, path: string, line: number): Promise<string | null> {\n const stmt = await store.prepare('SELECT start_line, end_line FROM sections WHERE \"path\" = ? AND start_line <= ? AND end_line >= ? ORDER BY start_line DESC LIMIT 1');\n const row = (await stmt.get(path, line, line)) as { start_line: number; end_line: number } | undefined;\n return row ? `L${row.start_line}-${row.end_line}` : null;\n}\n\nexport interface SearchOptions {\n k?: number;\n where?: string; // SQL fragment against frontmatter alias `f`, e.g. \"f.status = 'active'\"\n preset?: string; // named preset; unknown name throws listing declared presets, undefined -> \"default\"\n include?: string[]; // ad hoc scope override (repeatable --include); independent of exclude\n exclude?: string[]; // ad hoc scope override (repeatable --exclude); independent of include\n noExclude?: boolean; // --no-exclude: drop the preset's exclude for this command\n snippetCharLimit?: number; // --snippet-char-limit; defaults to SNIPPET_CHAR_LIMIT_DEFAULT\n snippetCountLimit?: number; // --snippet-count-limit; defaults to SNIPPET_COUNT_LIMIT_DEFAULT\n}\n\n// Hydrates already-ranked rows with snippets and containing-section ranges without reranking.\nexport async function hydrateSearchRows(store: Store, cfg: ResolvedConfig, rows: Row[], matchedPaths: Set<string>, terms: string, opts: Pick<SearchOptions, 'snippetCharLimit' | 'snippetCountLimit'> = {}): Promise<void> {\n if (matchedPaths.size === 0) return;\n const bareTerms = extractBareTerms(terms);\n const charLimit = opts.snippetCharLimit ?? SNIPPET_CHAR_LIMIT_DEFAULT;\n const countLimit = opts.snippetCountLimit ?? SNIPPET_COUNT_LIMIT_DEFAULT;\n for (const row of rows) {\n if (!matchedPaths.has(row.path as string)) continue;\n let text: string;\n try {\n text = readFileSync(join(cfg.rootDir ?? cfg.baseDir, row.path as string), 'utf8');\n } catch {\n continue; // vanished since the match; leave snippets/lines empty rather than throw\n }\n const { snippets, offset } = computeSnippets(text, bareTerms, charLimit, countLimit);\n row.snippets = snippets;\n if (row.lines == null) row.lines = featureEnabled(cfg, 'sections') ? await lineRangeFor(store, row.path as string, lineNumberAt(text, offset)) : null;\n }\n}\n\n// The declared or defaulted signals compose via RRF; `via` names which ones produced each row.\n// `opts` arrives already resolved (config.ts:resolveSearch).\nexport async function search(store: Store, cfg: ResolvedConfig, terms: string, opts: SearchOptions = {}): Promise<Row[]> {\n const effective = resolveSearch(cfg, opts);\n const { k, signals } = effective;\n\n const allPaths = ((await (await store.prepare('SELECT \"path\" FROM frontmatter')).all()) as Array<{ path: string }>).map((r) => r.path);\n const scopePaths = await rawScope(store, cfg, opts, allPaths);\n const scopeActive = scopePaths.size < allPaths.length;\n // The set every candidate pool must be filtered to before truncation: scope narrowed by\n // --where, the same composition scopedPaths() gives the other commands.\n let allowedPaths: Set<string>;\n try {\n allowedPaths = await narrowByWhere(store, scopePaths, effective.where);\n } catch (err) {\n throw searchError(err as Error, terms, effective.where);\n }\n const fetch = Math.max(k * 3, 30);\n\n // A downloadable HF id proceeds -- getProvider fetches it lazily on consent. Only a\n // local path with missing files errors here, since nothing will ever fetch it for itself.\n const wantsVectors = signals.vectors !== undefined;\n if (wantsVectors) {\n const e = embedConfig(cfg); // validate.ts guarantees this is set whenever \"vectors\" is declared\n if (localModelMissing(e)) {\n throw new SenseError('EMBED_MODEL_MISSING', `preset \"${effective.presetName}\" searches with vectors, but the local model path \"${e.model}\" is missing ${MODEL_FILENAMES}; point embed.model at a directory containing them, or drop \"vectors\" from that preset's signals to search without them`);\n }\n }\n const semanticEnabled = wantsVectors && (await scopeHasEmbeddings(store, cfg, allowedPaths));\n\n // --where applies inside the candidate query (a post-filter would drop matches ranked past\n // the pool) and again on the final select, for link-derived rows.\n const scope = effective.where;\n const whereJoin = scope ? `JOIN frontmatter f ON f.\"path\" = content.path` : '';\n const whereCond = scope ? `AND (${scope})` : '';\n // Filtered before LIMIT, not after, or scoped notes ranking below the global top-`fetch`\n // never reach the filter; joined against a temp table since real scopes exceed SQLITE_MAX_VARIABLE_NUMBER.\n if (scopeActive) await materializeScope(store, '_search_scope', scopePaths);\n const scopeCond = scopeActive ? `AND content.path IN (SELECT \"path\" FROM _search_scope)` : '';\n\n const candidates = new Map<string, { score: number; via: string }>();\n let matchRows: LexicalHit[] = [];\n const hasEmptyPhrase = [...terms.matchAll(/\"([^\"]*)\"/g)].some((match) => !/[\\p{L}\\p{N}_]/u.test(match[1]));\n const hasBareSyntaxOnly = /[()]/u.test(terms.replace(/\"[^\"]*\"/g, ' '));\n // A query that is only whitespace or punctuation has no lexical rows; other declared signals\n // compose normally. In particular, unspaced-script punctuation can rewrite to an empty MATCH.\n if (signals.words !== undefined && terms.trim() !== '' && (/[\\p{L}\\p{N}_]/u.test(terms) || hasBareSyntaxOnly) && !hasEmptyPhrase) {\n const syntaxError = bareTermSyntaxError(terms);\n if (syntaxError) throw syntaxError;\n try {\n matchRows = await wordsCandidates(store, candidates, terms, whereJoin, whereCond, scopeCond, fetch, signals.words);\n } catch (err) {\n throw searchError(err as Error, terms, scope);\n }\n }\n // Every store's lexical `snippets` is NULL; the snippet text is always computed below.\n // Distinguish from via='link' rows, which never appear in matchRows.\n const matchedPaths = new Set(matchRows.map((r) => r.path));\n\n if (signals.links !== undefined) await linksCandidates(store, candidates, matchRows, allPaths, allowedPaths, fetch, signals.links);\n\n let chunkLines = new Map<string, string>();\n let chunkSimilarity = new Map<string, number>();\n if (semanticEnabled) {\n ({ chunkLines, chunkSimilarity } = await vectorsCandidates(store, cfg, candidates, terms, fetch, allowedPaths, signals.vectors as number));\n }\n\n await store.exec('DROP TABLE IF EXISTS _search');\n // DOUBLE, not REAL: sqlite's REAL is an 8-byte double but duckdb's is a 4-byte float, and the\n // rounded score/similarity are printed at full precision in rows.\n await store.exec('CREATE TEMP TABLE _search (\"path\" TEXT PRIMARY KEY, score DOUBLE, via TEXT, lines TEXT, similarity DOUBLE)');\n if (candidates.size > 0) {\n await store.runBatch(\n 'INSERT INTO _search (\"path\", score, via, lines, similarity) VALUES (?, ?, ?, ?, ?)',\n [...candidates].map(([path, c]) => [path, c.score, c.via, chunkLines.get(path) ?? null, chunkSimilarity.get(path) ?? null])\n );\n }\n\n // Reapplies --where even though _search is already scope+where filtered, since the join to\n // frontmatter is already needed for the path column.\n const where = scope ? `WHERE (${scope})` : '';\n // lines: semantic rows carry their chunk's range, lexical rows gain one below,\n // everything else stays null; similarity stays semantic-only.\n const similarityCol = semanticEnabled ? ', _search.similarity' : '';\n // NULL AS snippets holds this column's position (between summary and via) for every row;\n // overwritten below, always to an array, never left null (DESIGN.md).\n const selectStmt = await store.prepare(\n `SELECT f.\"path\" AS path, content.title, content.summary, NULL AS snippets, _search.via, round(_search.score, 4) AS score, _search.lines${similarityCol}\n FROM _search JOIN frontmatter f ON f.\"path\" = _search.\"path\" JOIN content ON content.path = _search.\"path\"\n ${where} ORDER BY _search.score DESC LIMIT ?`\n );\n const rows = (await selectStmt.all(k)) as Row[];\n for (const row of rows) row.snippets = [];\n\n await hydrateSearchRows(store, cfg, rows, matchedPaths, terms, opts);\n\n return rows;\n}\n"],"names":["SNIPPET_CHAR_LIMIT_DEFAULT","SNIPPET_COUNT_LIMIT_DEFAULT","computeSnippets","hydrateSearchRows","lineNumberAt","search","extractBareTerms","query","cleaned","replace","split","map","tok","flatMap","searchTokens","text","toLowerCase","trim","filter","length","wordSegmenter","findOccurrences","terms","occ","textLower","unspacedTerms","hasUnspacedRun","unspacedRuns","run","runLower","slice","start","end","term","idx","found","indexOf","push","spacedTerms","t","termByStem","Map","stemmer","foldForSearch","stemInitials","Set","Array","from","keys","match","segment","unspaced","folded","has","get","undefined","sort","a","b","wordBoundaries","Intl","Segmenter","granularity","bounds","index","snapForward","pos","lo","hi","mid","snapBackward","result","firstBoundAfter","cutWindow","anchor","charLimit","rawEnd","Math","min","fitEnd","render","floor","upperBound","firstOccAtOrAfter","renderWindow","win","out","cursor","i","o","prefix","suffix","scoreWindows","winEnd","seen","count","j","add","max","e","candidates","distinct","size","overlaps","selectWindows","countLimit","ranked","chosen","c","some","s","best","find","snippets","offset","line","charCodeAt","lineRangeFor","store","path","stmt","row","prepare","start_line","end_line","cfg","rows","matchedPaths","opts","bareTerms","snippetCharLimit","snippetCountLimit","readFileSync","join","rootDir","baseDir","lines","featureEnabled","effective","k","signals","allPaths","scopePaths","scopeActive","allowedPaths","err","fetch","wantsVectors","semanticEnabled","scope","whereJoin","whereCond","scopeCond","matchRows","hasEmptyPhrase","hasBareSyntaxOnly","syntaxError","chunkLines","chunkSimilarity","where","similarityCol","selectStmt","resolveSearch","all","r","rawScope","narrowByWhere","searchError","vectors","embedConfig","localModelMissing","SenseError","presetName","MODEL_FILENAMES","model","scopeHasEmbeddings","materializeScope","matchAll","test","words","bareTermSyntaxError","wordsCandidates","links","linksCandidates","vectorsCandidates","exec","runBatch","score","via"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/search.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { stemmer } from 'stemmer';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { embedConfig, featureEnabled, resolveSearch } from '../config/index.ts';\nimport { localModelMissing, MODEL_FILENAMES } from '../embed/store.ts';\nimport { SenseError } from '../errors.ts';\nimport type { Row } from '../output/output.ts';\nimport { bareTermSyntaxError, searchError } from '../output/search-error.ts';\nimport type { LexicalHit, Store } from '../store/types.ts';\nimport { foldForSearch, hasUnspacedRun, searchTokens, unspacedRuns } from '../text/segment.ts';\nimport { materializeScope, narrowByWhere, rawScope, scopeHasEmbeddings } from './scope.ts';\nimport { linksCandidates, vectorsCandidates, wordsCandidates } from './signals.ts';\n\n// Default budget behind --snippet-char-limit/--snippet-count-limit: the limit is whatever the\n// caller passes, these only say what happens when they pass nothing (DESIGN.md \"Search snippets\").\nexport const SNIPPET_CHAR_LIMIT_DEFAULT = 80;\nexport const SNIPPET_COUNT_LIMIT_DEFAULT = 1;\n\n// Bare terms from an FTS5 query string: strips operators/quoting, not real terms, so the\n// snippet scan matches what the query matched -- FTS5 operators are uppercase-only, so this is too.\nfunction extractBareTerms(query: string): string[] {\n const cleaned = query\n .replace(/\"/g, ' ')\n .replace(/[()*]/g, ' ')\n .replace(/\\b(AND|OR|NOT|NEAR)\\b(\\/\\d+)?/g, ' ');\n return cleaned\n .split(/\\s+/)\n .map((tok) => tok.replace(/^[A-Za-z_]\\w*:/, '')) // column filter, e.g. title:term\n .flatMap((tok) => searchTokens(tok).map(({ text }) => text))\n .map((tok) => tok.toLowerCase().trim())\n .filter((tok) => tok.length > 0);\n}\n\n// House convention (src/chunk/group.ts): Intl.Segmenter word boundaries, not a bare \\b, which\n// is ASCII-only. Built on first use: construction is a few ms, paid only when a term matches.\nlet wordSegmenter: Intl.Segmenter | undefined;\n\nfunction findOccurrences(text: string, terms: string[]): Array<{ start: number; end: number; term: string }> {\n const occ: Array<{ start: number; end: number; term: string }> = [];\n const textLower = text.toLowerCase();\n\n // Unspaced scripts (UNSPACED_SCRIPTS) mark no word boundaries: the sense-setup skill promises\n // substring semantics there, so a matching term is found wherever it occurs in the run.\n const unspacedTerms = terms.filter(hasUnspacedRun);\n if (unspacedTerms.length > 0) {\n for (const run of unspacedRuns(text)) {\n const runLower = textLower.slice(run.start, run.end);\n for (const term of unspacedTerms) {\n let idx = 0;\n for (;;) {\n const found = runLower.indexOf(term, idx);\n if (found === -1) break;\n occ.push({ start: run.start + found, end: run.start + found + term.length, term });\n idx = found + term.length;\n }\n }\n }\n }\n\n // Spaced scripts: a word is marked when its porter stem equals a query term's stem, the same\n // algorithm both indexes tokenize with (sqlite's TOKENIZE = 'porter unicode61'; duckdb's fts default).\n const spacedTerms = terms.filter((t) => !hasUnspacedRun(t));\n if (spacedTerms.length > 0) {\n const termByStem = new Map(spacedTerms.map((t) => [stemmer(foldForSearch(t)), t]));\n const stemInitials = new Set(Array.from(termByStem.keys(), (term) => term[0]));\n for (const match of searchTokens(text)) {\n const segment = match.text;\n if (match.unspaced) continue;\n const folded = foldForSearch(segment);\n // Porter stemming changes suffixes only, so a different initial cannot match a query stem.\n if (!stemInitials.has(folded[0])) continue;\n const term = termByStem.get(stemmer(folded));\n if (term !== undefined) occ.push({ start: match.start, end: match.end, term });\n }\n }\n\n return occ.sort((a, b) => a.start - b.start || b.end - a.end);\n}\n\n// Segment boundaries of the whole text, word granularity: the only cut points a snippet edge\n// may land on. One rule for every script (DESIGN.md \"Cutting\") -- a regex \\b is ASCII-only and\n// would mis-cut Japanese, Chinese and Thai, which Intl.Segmenter divides by dictionary instead.\nfunction wordBoundaries(text: string): number[] {\n wordSegmenter ??= new Intl.Segmenter('en', { granularity: 'word' });\n const bounds = [0];\n for (const { index, segment } of wordSegmenter.segment(text)) bounds.push(index + segment.length);\n return bounds;\n}\n\n// bounds is sorted: snaps are binary searches, since each runs once per candidate window.\nfunction snapForward(bounds: number[], pos: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (bounds[mid] < pos) lo = mid + 1;\n else hi = mid;\n }\n return bounds[lo];\n}\n\nfunction snapBackward(bounds: number[], pos: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n let result = bounds[0];\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (bounds[mid] <= pos) {\n lo = mid;\n result = bounds[mid];\n } else hi = mid - 1;\n }\n return result;\n}\n\nfunction firstBoundAfter(bounds: number[], pos: number): number | undefined {\n let lo = 0;\n let hi = bounds.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (bounds[mid] <= pos) lo = mid + 1;\n else hi = mid;\n }\n return bounds[lo];\n}\n\n// A raw, unmarked upper bound: [start, end) inside [anchor, anchor+charLimit), edges on\n// boundaries. Markup (guillemets, ellipses) added on top of this can push the rendered result\n// past charLimit, which is what fitEnd() below corrects for; this is only the starting guess.\n// A single segment spanning the whole target window (a word longer than the char limit) is the\n// one case where holding the boundary rule means the budget is not a hard ceiling.\nfunction cutWindow(text: string, bounds: number[], anchor: number, charLimit: number): { start: number; end: number } {\n const rawEnd = Math.min(text.length, anchor + charLimit);\n const start = snapForward(bounds, anchor);\n let end = snapBackward(bounds, rawEnd);\n if (end <= start) end = firstBoundAfter(bounds, start) ?? text.length;\n return { start, end: Math.min(end, text.length) };\n}\n\n// The largest boundary <= upperBound, > floor, whose rendered [*, end) fits charLimit. Markup\n// only ever adds characters as end grows, so rendered length is non-decreasing in end and\n// shrinking from upperBound is guaranteed to find the true fit rather than guess at it.\n// `floor` is the one end this never shrinks past (the anchor's own marked word, or the first\n// word in the unmarked fallback): DESIGN.md's budget is a ceiling except here, where returning\n// nothing is worse than a single word that overruns it.\nfunction fitEnd(render: (end: number) => string, bounds: number[], floor: number, upperBound: number, charLimit: number): number {\n let lo = 0;\n let hi = bounds.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (bounds[mid] <= upperBound) lo = mid;\n else hi = mid - 1;\n }\n for (; lo >= 0 && bounds[lo] > floor; lo--) {\n if (render(bounds[lo]).length <= charLimit) return bounds[lo];\n }\n return floor;\n}\n\ninterface Span {\n start: number;\n end: number;\n}\n\ninterface SnippetWindow extends Span {\n distinct: number;\n count: number;\n}\n\n// occ is start-sorted: a window's first candidate occurrence is a binary search, not a walk.\nfunction firstOccAtOrAfter(occ: Array<{ start: number; end: number; term: string }>, pos: number): number {\n let lo = 0;\n let hi = occ.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (occ[mid].start < pos) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nfunction renderWindow(text: string, occ: Array<{ start: number; end: number; term: string }>, win: Span): string {\n let out = '';\n let cursor = win.start;\n for (let i = firstOccAtOrAfter(occ, win.start); i < occ.length && occ[i].start < win.end; i++) {\n const o = occ[i];\n if (o.end > win.end) continue;\n // Occurrences of duplicate or substring-overlapping terms (\"test tests\") can overlap;\n // emitting each would duplicate document text. Keep the first, absorb the rest.\n if (o.start < cursor) continue;\n out += `${text.slice(cursor, o.start)}«${text.slice(o.start, o.end)}»`;\n cursor = o.end;\n }\n out += text.slice(cursor, win.end);\n const prefix = win.start > 0 ? '…' : '';\n const suffix = win.end < text.length ? '…' : '';\n return `${prefix}${out.replace(/\\s+/g, ' ')}${suffix}`;\n}\n\n// Scores every occurrence-anchored candidate window: most distinct terms wins, ties broken by\n// most total hits -- coverage now that occurrences are real words, not the false-fragment counts\n// a substring scan produced. Selection itself is unevaluated (DESIGN.md \"Selection, unsettled\").\n// The window's `end` is fitted to the *rendered* text, markup included, not the raw span: a\n// window dense with marks (every guillemet pair adds two characters) shrinks to fit the same\n// budget a sparse one fills almost exactly.\nfunction scoreWindows(occ: Array<{ start: number; end: number; term: string }>, bounds: number[], text: string, charLimit: number): SnippetWindow[] {\n const candidates: SnippetWindow[] = [];\n for (let i = 0; i < occ.length; i++) {\n const winEnd = occ[i].start + charLimit;\n const seen = new Set<string>();\n let count = 0;\n for (let j = i; j < occ.length && occ[j].start < winEnd; j++) {\n seen.add(occ[j].term);\n count++;\n }\n const start = snapForward(bounds, occ[i].start);\n const floor = Math.max(start, occ[i].end);\n const upperBound = Math.max(floor, cutWindow(text, bounds, occ[i].start, charLimit).end);\n const end = fitEnd((e) => renderWindow(text, occ, { start, end: e }), bounds, floor, upperBound, charLimit);\n candidates.push({ start, end, distinct: seen.size, count });\n }\n return candidates;\n}\n\nfunction overlaps(a: Span, b: Span): boolean {\n return a.start < b.end && b.start < a.end;\n}\n\n// Same scoring function as a single snippet, kept rather than discarded (DESIGN.md \"Several\n// snippets per note\"): rank by score, take the top non-overlapping windows, then reorder to the\n// note's own order, since several passages from one note read as an abridged note.\nfunction selectWindows(candidates: SnippetWindow[], countLimit: number): { chosen: SnippetWindow[]; best: SnippetWindow } {\n const ranked = candidates.slice().sort((a, b) => b.distinct - a.distinct || b.count - a.count);\n const chosen: SnippetWindow[] = [];\n for (const c of ranked) {\n if (chosen.length >= countLimit) break;\n if (chosen.some((s) => overlaps(s, c))) continue;\n chosen.push(c);\n }\n chosen.sort((a, b) => a.start - b.start);\n return { chosen, best: ranked[0] };\n}\n\n// Builds bounded marked passages and returns the best window's offset for section lookup.\nexport function computeSnippets(text: string, terms: string[], charLimit: number, countLimit: number): { snippets: string[]; offset: number } {\n const occ = findOccurrences(text, terms);\n const bounds = wordBoundaries(text);\n if (occ.length === 0) {\n // A term matched only via title/summary, not this body text, finds no occurrence here;\n // fall back to the doc's start, unmarked.\n const render = (end: number): string => `${text.slice(0, end).replace(/\\s+/g, ' ').trim()}${end < text.length ? '…' : ''}`;\n const floor = bounds.find((b) => b > 0) ?? text.length;\n const upperBound = Math.max(floor, cutWindow(text, bounds, 0, charLimit).end);\n const end = fitEnd(render, bounds, floor, upperBound, charLimit);\n return { snippets: [render(end)], offset: 0 };\n }\n const candidates = scoreWindows(occ, bounds, text, charLimit);\n const { chosen, best } = selectWindows(candidates, countLimit);\n return { snippets: chosen.map((win) => renderWindow(text, occ, win)), offset: best.start };\n}\n\n// Converts an offset in the original text to its one-based line number.\nexport function lineNumberAt(text: string, offset: number): number {\n let line = 1;\n for (let i = 0; i < offset; i++) if (text.charCodeAt(i) === 10) line++;\n return line;\n}\n\nasync function lineRangeFor(store: Store, path: string, line: number): Promise<string | null> {\n const stmt = await store.prepare('SELECT start_line, end_line FROM sections WHERE \"path\" = ? AND start_line <= ? AND end_line >= ? ORDER BY start_line DESC LIMIT 1');\n const row = (await stmt.get(path, line, line)) as { start_line: number; end_line: number } | undefined;\n return row ? `L${row.start_line}-${row.end_line}` : null;\n}\n\nexport interface SearchOptions {\n k?: number;\n where?: string; // SQL fragment against frontmatter alias `f`, e.g. \"f.status = 'active'\"\n preset?: string; // named preset; unknown name throws listing declared presets, undefined -> \"default\"\n include?: string[]; // ad hoc scope override (repeatable --include); independent of exclude\n exclude?: string[]; // ad hoc scope override (repeatable --exclude); independent of include\n noExclude?: boolean; // --no-exclude: drop the preset's exclude for this command\n snippetCharLimit?: number; // --snippet-char-limit; defaults to SNIPPET_CHAR_LIMIT_DEFAULT\n snippetCountLimit?: number; // --snippet-count-limit; defaults to SNIPPET_COUNT_LIMIT_DEFAULT\n}\n\nfunction validateSearchOptions(opts: SearchOptions): void {\n for (const [name, value] of [\n ['k', opts.k],\n ['snippetCharLimit', opts.snippetCharLimit],\n ['snippetCountLimit', opts.snippetCountLimit],\n ] as const) {\n if (value !== undefined && (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0)) {\n throw new SenseError('SEARCH_OPTION_INVALID', `search option \"${name}\" must be a positive finite integer, got ${String(value)}`);\n }\n }\n}\n\n// Hydrates already-ranked rows with snippets and containing-section ranges without reranking.\nexport async function hydrateSearchRows(store: Store, cfg: ResolvedConfig, rows: Row[], matchedPaths: Set<string>, terms: string, opts: Pick<SearchOptions, 'snippetCharLimit' | 'snippetCountLimit'> = {}): Promise<void> {\n if (matchedPaths.size === 0) return;\n const bareTerms = extractBareTerms(terms);\n const charLimit = opts.snippetCharLimit ?? SNIPPET_CHAR_LIMIT_DEFAULT;\n const countLimit = opts.snippetCountLimit ?? SNIPPET_COUNT_LIMIT_DEFAULT;\n for (const row of rows) {\n if (!matchedPaths.has(row.path as string)) continue;\n let text: string;\n try {\n text = readFileSync(join(cfg.rootDir ?? cfg.baseDir, row.path as string), 'utf8');\n } catch {\n continue; // vanished since the match; leave snippets/lines empty rather than throw\n }\n const { snippets, offset } = computeSnippets(text, bareTerms, charLimit, countLimit);\n row.snippets = snippets;\n if (row.lines == null) row.lines = featureEnabled(cfg, 'sections') ? await lineRangeFor(store, row.path as string, lineNumberAt(text, offset)) : null;\n }\n}\n\n// The declared or defaulted signals compose via RRF; `via` names which ones produced each row.\n// `opts` arrives already resolved (config.ts:resolveSearch).\nexport async function search(store: Store, cfg: ResolvedConfig, terms: string, opts: SearchOptions = {}): Promise<Row[]> {\n validateSearchOptions(opts);\n const effective = resolveSearch(cfg, opts);\n const { k, signals } = effective;\n\n const allPaths = ((await (await store.prepare('SELECT \"path\" FROM frontmatter')).all()) as Array<{ path: string }>).map((r) => r.path);\n const scopePaths = await rawScope(store, cfg, opts, allPaths);\n const scopeActive = scopePaths.size < allPaths.length;\n // The set every candidate pool must be filtered to before truncation: scope narrowed by\n // --where, the same composition scopedPaths() gives the other commands.\n let allowedPaths: Set<string>;\n try {\n allowedPaths = await narrowByWhere(store, scopePaths, effective.where);\n } catch (err) {\n throw searchError(err as Error, terms, effective.where);\n }\n const fetch = Math.max(k * 3, 30);\n\n // A downloadable HF id proceeds -- getProvider fetches it lazily on consent. Only a\n // local path with missing files errors here, since nothing will ever fetch it for itself.\n const wantsVectors = signals.vectors !== undefined;\n if (wantsVectors) {\n const e = embedConfig(cfg); // validate.ts guarantees this is set whenever \"vectors\" is declared\n if (localModelMissing(e)) {\n throw new SenseError('EMBED_MODEL_MISSING', `preset \"${effective.presetName}\" searches with vectors, but the local model path \"${e.model}\" is missing ${MODEL_FILENAMES}; point embed.model at a directory containing them, or drop \"vectors\" from that preset's signals to search without them`);\n }\n }\n const semanticEnabled = wantsVectors && (await scopeHasEmbeddings(store, cfg, allowedPaths));\n\n // --where applies inside the candidate query (a post-filter would drop matches ranked past\n // the pool) and again on the final select, for link-derived rows.\n const scope = effective.where;\n const whereJoin = scope ? `JOIN frontmatter f ON f.\"path\" = content.path` : '';\n const whereCond = scope ? `AND (${scope})` : '';\n // Filtered before LIMIT, not after, or scoped notes ranking below the global top-`fetch`\n // never reach the filter; joined against a temp table since real scopes exceed SQLITE_MAX_VARIABLE_NUMBER.\n if (scopeActive) await materializeScope(store, '_search_scope', scopePaths);\n const scopeCond = scopeActive ? `AND content.path IN (SELECT \"path\" FROM _search_scope)` : '';\n\n const candidates = new Map<string, { score: number; via: string }>();\n let matchRows: LexicalHit[] = [];\n const hasEmptyPhrase = [...terms.matchAll(/\"([^\"]*)\"/g)].some((match) => !/[\\p{L}\\p{N}_]/u.test(match[1]));\n const hasBareSyntaxOnly = /[()]/u.test(terms.replace(/\"[^\"]*\"/g, ' '));\n // A query that is only whitespace or punctuation has no lexical rows; other declared signals\n // compose normally. In particular, unspaced-script punctuation can rewrite to an empty MATCH.\n if (signals.words !== undefined && terms.trim() !== '' && (/[\\p{L}\\p{N}_]/u.test(terms) || hasBareSyntaxOnly) && !hasEmptyPhrase) {\n const syntaxError = bareTermSyntaxError(terms);\n if (syntaxError) throw syntaxError;\n try {\n matchRows = await wordsCandidates(store, candidates, terms, whereJoin, whereCond, scopeCond, fetch, signals.words);\n } catch (err) {\n throw searchError(err as Error, terms, scope);\n }\n }\n // Every store's lexical `snippets` is NULL; the snippet text is always computed below.\n // Distinguish from via='link' rows, which never appear in matchRows.\n const matchedPaths = new Set(matchRows.map((r) => r.path));\n\n if (signals.links !== undefined) await linksCandidates(store, candidates, matchRows, allPaths, allowedPaths, fetch, signals.links);\n\n let chunkLines = new Map<string, string>();\n let chunkSimilarity = new Map<string, number>();\n if (semanticEnabled) {\n ({ chunkLines, chunkSimilarity } = await vectorsCandidates(store, cfg, candidates, terms, fetch, allowedPaths, signals.vectors as number));\n }\n\n await store.exec('DROP TABLE IF EXISTS _search');\n // DOUBLE, not REAL: sqlite's REAL is an 8-byte double but duckdb's is a 4-byte float, and the\n // rounded score/similarity are printed at full precision in rows.\n await store.exec('CREATE TEMP TABLE _search (\"path\" TEXT PRIMARY KEY, score DOUBLE, via TEXT, lines TEXT, similarity DOUBLE)');\n if (candidates.size > 0) {\n await store.runBatch(\n 'INSERT INTO _search (\"path\", score, via, lines, similarity) VALUES (?, ?, ?, ?, ?)',\n [...candidates].map(([path, c]) => [path, c.score, c.via, chunkLines.get(path) ?? null, chunkSimilarity.get(path) ?? null])\n );\n }\n\n // Reapplies --where even though _search is already scope+where filtered, since the join to\n // frontmatter is already needed for the path column.\n const where = scope ? `WHERE (${scope})` : '';\n // lines: semantic rows carry their chunk's range, lexical rows gain one below,\n // everything else stays null; similarity stays semantic-only.\n const similarityCol = semanticEnabled ? ', _search.similarity' : '';\n // NULL AS snippets holds this column's position (between summary and via) for every row;\n // overwritten below, always to an array, never left null (DESIGN.md).\n const selectStmt = await store.prepare(\n `SELECT f.\"path\" AS path, content.title, content.summary, NULL AS snippets, _search.via, round(_search.score, 4) AS score, _search.lines${similarityCol}\n FROM _search JOIN frontmatter f ON f.\"path\" = _search.\"path\" JOIN content ON content.path = _search.\"path\"\n ${where} ORDER BY _search.score DESC LIMIT ?`\n );\n const rows = (await selectStmt.all(k)) as Row[];\n for (const row of rows) row.snippets = [];\n\n await hydrateSearchRows(store, cfg, rows, matchedPaths, terms, opts);\n\n return rows;\n}\n"],"names":["SNIPPET_CHAR_LIMIT_DEFAULT","SNIPPET_COUNT_LIMIT_DEFAULT","computeSnippets","hydrateSearchRows","lineNumberAt","search","extractBareTerms","query","cleaned","replace","split","map","tok","flatMap","searchTokens","text","toLowerCase","trim","filter","length","wordSegmenter","findOccurrences","terms","occ","textLower","unspacedTerms","hasUnspacedRun","unspacedRuns","run","runLower","slice","start","end","term","idx","found","indexOf","push","spacedTerms","t","termByStem","Map","stemmer","foldForSearch","stemInitials","Set","Array","from","keys","match","segment","unspaced","folded","has","get","undefined","sort","a","b","wordBoundaries","Intl","Segmenter","granularity","bounds","index","snapForward","pos","lo","hi","mid","snapBackward","result","firstBoundAfter","cutWindow","anchor","charLimit","rawEnd","Math","min","fitEnd","render","floor","upperBound","firstOccAtOrAfter","renderWindow","win","out","cursor","i","o","prefix","suffix","scoreWindows","winEnd","seen","count","j","add","max","e","candidates","distinct","size","overlaps","selectWindows","countLimit","ranked","chosen","c","some","s","best","find","snippets","offset","line","charCodeAt","lineRangeFor","store","path","stmt","row","prepare","start_line","end_line","validateSearchOptions","opts","k","snippetCharLimit","snippetCountLimit","name","value","Number","isFinite","isInteger","SenseError","String","cfg","rows","matchedPaths","bareTerms","readFileSync","join","rootDir","baseDir","lines","featureEnabled","effective","signals","allPaths","scopePaths","scopeActive","allowedPaths","err","fetch","wantsVectors","semanticEnabled","scope","whereJoin","whereCond","scopeCond","matchRows","hasEmptyPhrase","hasBareSyntaxOnly","syntaxError","chunkLines","chunkSimilarity","where","similarityCol","selectStmt","resolveSearch","all","r","rawScope","narrowByWhere","searchError","vectors","embedConfig","localModelMissing","presetName","MODEL_FILENAMES","model","scopeHasEmbeddings","materializeScope","matchAll","test","words","bareTermSyntaxError","wordsCandidates","links","linksCandidates","vectorsCandidates","exec","runBatch","score","via"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/types.ts"],"sourcesContent":["import type { SignalWeights } from './signals.ts';\n\nexport const CONFIG_FILENAME = 'sense.config.json';\nexport const STATE_DIR = '.sense';\n\n// Highest sense.config.json `version` this build understands. Older versions auto-migrate on load.\nexport const SUPPORTED_CONFIG_VERSION = 5;\n\n// Each feature owns its tables, parse-time extraction, and reconcile step; commands degrade when one is off.\n// links/sections/tags/rank are opt-out toggles in `features`; embed is on exactly when an `embed` block names a model.\nexport const FEATURE_NAMES = ['links', 'sections', 'tags', 'rank', 'embed'] as const;\nexport type FeatureName = (typeof FEATURE_NAMES)[number];\n\n// `embed` names the model and gives the tree vectors at all; a preset's `signals` says which\n// engines that scope's searches use.\nexport interface EmbedConfig {\n model?: string;\n provider?: 'static' | 'openai' | 'cohere';\n url?: string; // openai provider: OpenAI-compatible base URL, e.g. http://localhost:11434/v1\n key?: string; // openai/cohere provider: name of the env var holding the bearer token, if any\n languages?: string[]; // owner-declared model languages; enables the language-fit check where no card exists\n chunkTokens?: number; // chunk size ceiling in estimated tokens for small-context models; default 500\n}\n\nexport const DEFAULT_EMBED_MODEL = 'minishlab/potion-retrieval-32M';\n\n// The single declaration every other store name derives from (Store.name, the store/index.ts\n// registry, validate.ts's accepted set). An array, not a bare union, so runtime checks read the same list.\nexport const STORE_NAMES = ['sqlite', 'duckdb', 'turso'] as const;\nexport type StoreName = (typeof STORE_NAMES)[number];\n\n// A named, self-contained file-selection scope: include/exclude are globby patterns resolved\n// relative to the
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/types.ts"],"sourcesContent":["import type { SignalWeights } from './signals.ts';\n\nexport const CONFIG_FILENAME = 'sense.config.json';\nexport const STATE_DIR = '.sense';\n\n// Highest sense.config.json `version` this build understands. Older versions auto-migrate on load.\nexport const SUPPORTED_CONFIG_VERSION = 5;\n\n// Each feature owns its tables, parse-time extraction, and reconcile step; commands degrade when one is off.\n// links/sections/tags/rank are opt-out toggles in `features`; embed is on exactly when an `embed` block names a model.\nexport const FEATURE_NAMES = ['links', 'sections', 'tags', 'rank', 'embed'] as const;\nexport type FeatureName = (typeof FEATURE_NAMES)[number];\n\n// `embed` names the model and gives the tree vectors at all; a preset's `signals` says which\n// engines that scope's searches use.\nexport interface EmbedConfig {\n model?: string;\n provider?: 'static' | 'openai' | 'cohere';\n url?: string; // openai provider: OpenAI-compatible base URL, e.g. http://localhost:11434/v1\n key?: string; // openai/cohere provider: name of the env var holding the bearer token, if any\n languages?: string[]; // owner-declared model languages; enables the language-fit check where no card exists\n chunkTokens?: number; // chunk size ceiling in estimated tokens for small-context models; default 500\n}\n\nexport const DEFAULT_EMBED_MODEL = 'minishlab/potion-retrieval-32M';\n\n// The single declaration every other store name derives from (Store.name, the store/index.ts\n// registry, validate.ts's accepted set). An array, not a bare union, so runtime checks read the same list.\nexport const STORE_NAMES = ['sqlite', 'duckdb', 'turso'] as const;\nexport type StoreName = (typeof STORE_NAMES)[number];\n\n// A named, self-contained file-selection scope: include/exclude are globby patterns resolved\n// relative to the configured tree root. No inheritance between presets; they may overlap freely (views, not partitions).\nexport interface Preset {\n include: string[];\n exclude?: string[];\n k?: number; // result count for `search` scoped to this preset; default 10\n // Exhaustive when present: every signal this preset's searches compose, each mapped to its RRF\n // weight (finite > 0; presence is enablement). Absent = every signal whose prerequisite holds, at weight 1 (words always, links when on, vectors when a model is named).\n signals?: SignalWeights;\n where?: string; // standing SQL condition against frontmatter alias `f`\n}\n\n// A saved `search` invocation: `sense <name>` runs like\n// `sense search <search> [--preset] [--include] [--exclude] [--where] [--k]`.\nexport interface SavedSearch {\n search: string;\n preset?: string;\n include?: string[];\n exclude?: string[];\n where?: string;\n k?: number;\n}\n\n// An entry names the verb it runs, one to one with the commands: { sql } runs like\n// `sense sql`, { search } like `sense search`.\nexport type SavedQuery = { sql: string } | SavedSearch;\n\nexport interface Config {\n // Editor-only pointer to schema.json; never read by sense.\n $schema?: string;\n version?: number;\n // Markdown tree to index. Relative paths resolve from the configuration file's directory;\n // omitted keeps the historic colocated-config behavior.\n root?: string;\n // File selection, index-time, and per-preset search defaults. A file is indexed iff any\n // preset's include/exclude covers it (union). `default` is used when a command names no preset.\n presets: Record<string, Preset>;\n // Global feature defaults; absent block or key means enabled. embed is not a member here --\n // see the `embed` block.\n features?: { links?: boolean; sections?: boolean; tags?: boolean; rank?: boolean };\n // Names the embedding model. Present means every indexed file gets vectors; absent means none do.\n embed?: EmbedConfig;\n // Backing store engine: \"sqlite\" (default, zero-dependency), \"duckdb\", or \"turso\" (optional\n // dependency, installed on first use). What differs per store is declared through CAPABILITIES (store/types.ts).\n store?: StoreName;\n queries: Record<string, SavedQuery>;\n}\n\nexport interface ResolvedConfig extends Config {\n // Configuration and state ownership are deliberately separate from the indexed tree.\n configDir?: string;\n rootDir?: string;\n // Compatibility for callers that construct a ResolvedConfig for `open()` directly. New code\n // uses rootDir/configDir; openStore normalizes this alias to both when necessary.\n baseDir: string;\n configPath: string | null;\n // Keys the file declares that this build does not read; cli reports them.\n unknownKeys?: string[];\n // Set when loadConfig auto-migrated the file on disk; cli reports it.\n migratedFrom?: number;\n}\n\nexport interface SearchOverrides {\n preset?: string;\n k?: number;\n where?: string;\n include?: string[];\n exclude?: string[];\n noExclude?: boolean; // drop the preset's exclude for this command; --exclude still applies\n}\n\nexport interface EffectiveSearch {\n presetName: string;\n k: number;\n where?: string;\n include: string[];\n exclude?: string[];\n signals: SignalWeights; // this preset's effective signal weights\n}\n"],"names":["CONFIG_FILENAME","DEFAULT_EMBED_MODEL","FEATURE_NAMES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION"],"mappings":";;;;;;;;;;;QAEaA;eAAAA;;QAsBAC;eAAAA;;QAdAC;eAAAA;;QAPAC;eAAAA;;QAyBAC;eAAAA;;QAtBAC;eAAAA;;;AAJN,IAAML,kBAAkB;AACxB,IAAMG,YAAY;AAGlB,IAAME,2BAA2B;AAIjC,IAAMH,gBAAgB;IAAC;IAAS;IAAY;IAAQ;IAAQ;CAAQ;AAcpE,IAAMD,sBAAsB;AAI5B,IAAMG,cAAc;IAAC;IAAU;IAAU;CAAQ"}
|
package/dist/cjs/errors.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'EMBED_MODEL_MISSING' | 'EMBED_MODEL_MISMATCH' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT' | 'PRESET_UNKNOWN' | 'PRESET_NOT_SEMANTIC' | 'NOTE_NOT_EMBEDDED' | 'STORE_UNKNOWN' | 'STORE_DEPENDENCY_MISSING' | 'STORE_CAPABILITY_MISSING' | 'STORE_BUSY' | 'LEXICAL_NULL_PATH';
|
|
1
|
+
export type SenseErrorCode = 'CONFIG_NOT_FOUND' | 'CONFIG_EXISTS' | 'CONFIG_INVALID' | 'CONFIG_VERSION_UNSUPPORTED' | 'WATCH_ACTIVE' | 'NOTE_NOT_FOUND' | 'NOTE_AMBIGUOUS' | 'EMBED_DISABLED' | 'EMBED_MODEL' | 'EMBED_MODEL_MISSING' | 'EMBED_MODEL_MISMATCH' | 'SEARCH_OPTION_INVALID' | 'SEARCH_SYNTAX' | 'COLUMN_LIMIT' | 'PRESET_UNKNOWN' | 'PRESET_NOT_SEMANTIC' | 'NOTE_NOT_EMBEDDED' | 'STORE_UNKNOWN' | 'STORE_DEPENDENCY_MISSING' | 'STORE_CAPABILITY_MISSING' | 'STORE_BUSY' | 'LEXICAL_NULL_PATH';
|
|
2
2
|
export declare class SenseError extends Error {
|
|
3
3
|
code: SenseErrorCode;
|
|
4
4
|
constructor(code: SenseErrorCode, message: string);
|