sensemaking 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/cjs/config/access.d.cts +0 -1
- package/dist/cjs/config/access.d.ts +0 -1
- package/dist/cjs/config/access.js +10 -17
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +1 -1
- package/dist/cjs/config/index.d.ts +1 -1
- package/dist/cjs/config/index.js +0 -3
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/types.d.cts +0 -3
- package/dist/cjs/config/types.d.ts +0 -3
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js +6 -24
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/links.js +4 -5
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/sections.js +4 -1
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/store/builder.d.cts +9 -1
- package/dist/cjs/store/builder.d.ts +9 -1
- package/dist/cjs/store/builder.js +593 -2
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/duckdb/open.js +7 -1
- package/dist/cjs/store/duckdb/open.js.map +1 -1
- package/dist/cjs/store/duckdb/reconcile.js +30 -5
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
- package/dist/cjs/store/embed-scope.d.cts +2 -0
- package/dist/cjs/store/embed-scope.d.ts +2 -0
- package/dist/cjs/store/embed-scope.js +85 -0
- package/dist/cjs/store/embed-scope.js.map +1 -0
- package/dist/cjs/store/feature-scope.d.cts +8 -0
- package/dist/cjs/store/feature-scope.d.ts +8 -0
- package/dist/cjs/store/feature-scope.js +107 -0
- package/dist/cjs/store/feature-scope.js.map +1 -0
- package/dist/cjs/store/open.js +193 -101
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/preset-scope.d.cts +3 -0
- package/dist/cjs/store/preset-scope.d.ts +3 -0
- package/dist/cjs/store/preset-scope.js +293 -0
- package/dist/cjs/store/preset-scope.js.map +1 -0
- package/dist/cjs/store/reconcile.d.cts +1 -1
- package/dist/cjs/store/reconcile.d.ts +1 -1
- package/dist/cjs/store/reconcile.js +172 -178
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/signature.js +7 -5
- package/dist/cjs/store/signature.js.map +1 -1
- package/dist/cjs/store/sqlite/lexical.d.cts +1 -1
- package/dist/cjs/store/sqlite/lexical.d.ts +1 -1
- package/dist/cjs/store/sqlite/lexical.js +2 -2
- package/dist/cjs/store/sqlite/lexical.js.map +1 -1
- package/dist/cjs/store/sqlite/open.d.cts +0 -1
- package/dist/cjs/store/sqlite/open.d.ts +0 -1
- package/dist/cjs/store/sqlite/open.js +14 -231
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/reconcile.d.cts +1 -1
- package/dist/cjs/store/sqlite/reconcile.d.ts +1 -1
- package/dist/cjs/store/sqlite/reconcile.js +78 -16
- package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
- package/dist/cjs/store/sqlite/sql-functions.d.cts +1 -1
- package/dist/cjs/store/sqlite/sql-functions.d.ts +1 -1
- package/dist/cjs/store/sqlite/sql-functions.js +3 -3
- package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/store.d.cts +1 -2
- package/dist/cjs/store/sqlite/store.d.ts +1 -2
- package/dist/cjs/store/sqlite/store.js +2 -3
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/turso/open.js +6 -0
- package/dist/cjs/store/turso/open.js.map +1 -1
- package/dist/cjs/store/turso/reconcile.js +72 -3
- package/dist/cjs/store/turso/reconcile.js.map +1 -1
- package/dist/cjs/store/types.d.cts +2 -4
- package/dist/cjs/store/types.d.ts +2 -4
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/esm/config/access.d.ts +0 -1
- package/dist/esm/config/access.js +12 -17
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +1 -1
- package/dist/esm/config/index.js +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/types.d.ts +0 -3
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js +6 -22
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/links.js +3 -4
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/sections.js +4 -1
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/store/builder.d.ts +9 -1
- package/dist/esm/store/builder.js +152 -3
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/duckdb/open.js +5 -1
- package/dist/esm/store/duckdb/open.js.map +1 -1
- package/dist/esm/store/duckdb/reconcile.js +11 -3
- package/dist/esm/store/duckdb/reconcile.js.map +1 -1
- package/dist/esm/store/embed-scope.d.ts +2 -0
- package/dist/esm/store/embed-scope.js +28 -0
- package/dist/esm/store/embed-scope.js.map +1 -0
- package/dist/esm/store/feature-scope.d.ts +8 -0
- package/dist/esm/store/feature-scope.js +49 -0
- package/dist/esm/store/feature-scope.js.map +1 -0
- package/dist/esm/store/open.js +78 -28
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/preset-scope.d.ts +3 -0
- package/dist/esm/store/preset-scope.js +77 -0
- package/dist/esm/store/preset-scope.js.map +1 -0
- package/dist/esm/store/reconcile.d.ts +1 -1
- package/dist/esm/store/reconcile.js +30 -5
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/signature.js +7 -5
- package/dist/esm/store/signature.js.map +1 -1
- package/dist/esm/store/sqlite/lexical.d.ts +1 -1
- package/dist/esm/store/sqlite/lexical.js +4 -4
- package/dist/esm/store/sqlite/lexical.js.map +1 -1
- package/dist/esm/store/sqlite/open.d.ts +0 -1
- package/dist/esm/store/sqlite/open.js +14 -88
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/reconcile.d.ts +1 -1
- package/dist/esm/store/sqlite/reconcile.js +14 -14
- package/dist/esm/store/sqlite/reconcile.js.map +1 -1
- package/dist/esm/store/sqlite/sql-functions.d.ts +1 -1
- package/dist/esm/store/sqlite/sql-functions.js +3 -3
- package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/store.d.ts +1 -2
- package/dist/esm/store/sqlite/store.js +2 -3
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/turso/open.js +4 -0
- package/dist/esm/store/turso/open.js.map +1 -1
- package/dist/esm/store/turso/reconcile.js +6 -2
- package/dist/esm/store/turso/reconcile.js.map +1 -1
- package/dist/esm/store/types.d.ts +2 -4
- package/dist/esm/store/types.js.map +1 -1
- package/package.json +3 -2
- package/schema.json +0 -11
package/README.md
CHANGED
|
@@ -93,7 +93,6 @@ ORDER BY bm25(content, 10.0, 5.0, 1.0) LIMIT 10
|
|
|
93
93
|
|---|---|
|
|
94
94
|
| `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. |
|
|
95
95
|
| `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. |
|
|
96
|
-
| `content` | settings for the `content` table. `tokenize` names the FTS5 tokenizer, defaulting to `porter unicode61`: name `trigram` for substring matching inside a Latin word, or `unicode61 tokenchars '-_'` to keep hyphenated terms whole. Languages written without word spaces (Chinese, Japanese, Thai, Khmer, Lao, Burmese) need no decision here: they are indexed per grapheme and searched as ordered phrases, substring semantics, what grep gives, needing no minimum length; naming a tokenizer turns that off, since the tree has then chosen its own scheme. Changing it rebuilds the text index only; vectors, links, and sections are kept. |
|
|
97
96
|
| `store` | backing store engine: `sqlite` (default, zero-dependency, Node's built-in SQLite), or the experimental `duckdb` and `turso`. The first command that opens such a tree installs that engine's package on its own (`@duckdb/node-api`, a one-time native download of ~110 MB; `@tursodatabase/database`, much smaller). The same commands and table names run on all three; what does not port is FTS5 syntax. Under `duckdb` and `turso`, `search` text and raw `MATCH` reject FTS5's prefix (`foo*`), boolean (`AND`/`OR`/`NOT`), `NEAR`, initial-token (`^`), and column-filter (`title:foo`) operators with a named error that says how to rephrase or set `store` to `sqlite`; bare words and quoted phrases work on all three. Raw `sql` is a per-store dialect: the tables are portable, but sqlite's FTS5 `MATCH`/`snippet()`/`bm25()` do not run under `duckdb` or `turso`, so saved queries written in FTS5 syntax are sqlite dialect, and `has`/`basename`/`segment` are registered on `sqlite` and `duckdb` but not `turso`, whose client cannot register SQL functions. `sense watch` requires `sqlite`; on the other two it errors at start naming the fix. Each store keeps its own cache file (`.sense/cache.db`, `.sense/cache.duckdb`, `.sense/cache.turso.db`); switching stores is a rebuild, not a migration. |
|
|
98
97
|
| `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. |
|
|
99
98
|
| `version` | schema version; older configs auto-migrate on load, noted on stderr. |
|
|
@@ -21,5 +21,4 @@ export declare function embedConfig(cfg: Config): {
|
|
|
21
21
|
languages?: string[];
|
|
22
22
|
chunkTokens?: number;
|
|
23
23
|
} | null;
|
|
24
|
-
export declare function contentTokenize(cfg: Config): string | undefined;
|
|
25
24
|
export declare function featureSignature(cfg: Config, features: Feature[]): string;
|
|
@@ -21,5 +21,4 @@ export declare function embedConfig(cfg: Config): {
|
|
|
21
21
|
languages?: string[];
|
|
22
22
|
chunkTokens?: number;
|
|
23
23
|
} | null;
|
|
24
|
-
export declare function contentTokenize(cfg: Config): string | undefined;
|
|
25
24
|
export declare function featureSignature(cfg: Config, features: Feature[]): string;
|
|
@@ -12,9 +12,6 @@ _export(exports, {
|
|
|
12
12
|
get anyPresetEmbeds () {
|
|
13
13
|
return anyPresetEmbeds;
|
|
14
14
|
},
|
|
15
|
-
get contentTokenize () {
|
|
16
|
-
return contentTokenize;
|
|
17
|
-
},
|
|
18
15
|
get embedConfig () {
|
|
19
16
|
return embedConfig;
|
|
20
17
|
},
|
|
@@ -142,15 +139,15 @@ function embedConfig(cfg) {
|
|
|
142
139
|
chunkTokens: e.chunkTokens
|
|
143
140
|
};
|
|
144
141
|
}
|
|
145
|
-
function contentTokenize(cfg) {
|
|
146
|
-
var _cfg_content;
|
|
147
|
-
var tokenize = (_cfg_content = cfg.content) === null || _cfg_content === void 0 ? void 0 : _cfg_content.tokenize;
|
|
148
|
-
return tokenize === undefined || tokenize.trim() === '' ? undefined : tokenize.trim();
|
|
149
|
-
}
|
|
150
142
|
function featureSignature(cfg, features) {
|
|
151
|
-
|
|
143
|
+
// One segment per toggle (not one lumped csv) so store/signature.ts's changedSignatureKeys can
|
|
144
|
+
// tell which feature moved -- store/feature-scope.ts routes a recognised toggle to a narrow
|
|
145
|
+
// per-table invalidation instead of the full clear.
|
|
146
|
+
var togglesPart = _typests.FEATURE_NAMES.filter(function(name) {
|
|
152
147
|
return name !== 'embed';
|
|
153
|
-
}).
|
|
148
|
+
}).map(function(name) {
|
|
149
|
+
return "feature:".concat(name, ":").concat(featureEnabled(cfg, name) ? 'on' : 'off');
|
|
150
|
+
});
|
|
154
151
|
var featureParts = features.map(function(feature) {
|
|
155
152
|
var _feature_signature;
|
|
156
153
|
return (_feature_signature = feature.signature) === null || _feature_signature === void 0 ? void 0 : _feature_signature.call(feature, cfg);
|
|
@@ -165,12 +162,8 @@ function featureSignature(cfg, features) {
|
|
|
165
162
|
var exclude = _to_consumable_array((_p_exclude = p.exclude) !== null && _p_exclude !== void 0 ? _p_exclude : []).sort().join('+');
|
|
166
163
|
return "preset:".concat(name, ":").concat(include, ":").concat(exclude, ":").concat(presetHasSignal(cfg, name, 'vectors') ? 'on' : 'off');
|
|
167
164
|
}).join('|');
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
].concat(_to_consumable_array(featureParts));
|
|
172
|
-
if (tokenize !== undefined) parts.push("tokenize:".concat(tokenize));
|
|
173
|
-
parts.push(presetsPart);
|
|
174
|
-
return parts.join('|');
|
|
165
|
+
return _to_consumable_array(togglesPart).concat(_to_consumable_array(featureParts), [
|
|
166
|
+
presetsPart
|
|
167
|
+
]).join('|');
|
|
175
168
|
}
|
|
176
169
|
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/access.ts"],"sourcesContent":["import type { Feature } from '../features/types.ts';\nimport type { SignalName, SignalWeights } from './signals.ts';\nimport { type Config, type EmbedConfig, FEATURE_NAMES, type FeatureName, type StoreName } from './types.ts';\n\nexport function presetNames(cfg: Config): string[] {\n return Object.keys(cfg.presets);\n}\n\n// The backing store engine this tree uses; absent means the default.\nexport function storeName(cfg: Config): StoreName {\n return cfg.store ?? 'sqlite';\n}\n\n// Whether the tree names a model at all.\nexport function embedEnabled(cfg: Config): boolean {\n return typeof cfg.embed?.model === 'string' && cfg.embed.model.length > 0;\n}\n\n// A preset's effective signal weights: declared exhaustively when `signals` is present, else\n// every signal whose prerequisite holds at weight 1 (words always, links when on, vectors when a model is named).\nexport function presetSignals(cfg: Config, name: string): SignalWeights {\n const declared = cfg.presets[name]?.signals;\n if (declared) return declared;\n const signals: SignalWeights = { words: 1 };\n if (cfg.features?.links !== false) signals.links = 1;\n if (embedEnabled(cfg)) signals.vectors = 1;\n return signals;\n}\n\nexport function presetHasSignal(cfg: Config, name: string, signal: SignalName): boolean {\n return presetSignals(cfg, name)[signal] !== undefined;\n}\n\n// Whether embedding needs to run: a model is named AND some preset's effective signals include vectors.\nexport function anyPresetEmbeds(cfg: Config): boolean {\n return presetNames(cfg).some((name) => presetHasSignal(cfg, name, 'vectors'));\n}\n\n// Opt-out features (default on): absent block or key means enabled. `rank` additionally requires\n// `links`. `embed` is derived (not a features-block member): on iff some preset's signals include vectors.\nexport function featureEnabled(cfg: Config, name: FeatureName): boolean {\n if (name === 'embed') return anyPresetEmbeds(cfg);\n const enabled = cfg.features?.[name] !== false;\n if (name === 'rank') return enabled && featureEnabled(cfg, 'links');\n return enabled;\n}\n\nexport function enabledFeatures(cfg: Config): FeatureName[] {\n return FEATURE_NAMES.filter((name) => featureEnabled(cfg, name));\n}\n\n// Feature states, so \"off\" and \"empty\" stay distinguishable in output. `embed` is excluded:\n// it is not a features-block toggle, and `status` reports it on its own line.\nexport function featureStates(cfg: Config): { on: FeatureName[]; off: FeatureName[] } {\n const reported = FEATURE_NAMES.filter((name) => name !== 'embed');\n return {\n on: reported.filter((name) => featureEnabled(cfg, name)),\n off: reported.filter((name) => !featureEnabled(cfg, name)),\n };\n}\n\n// Resolved embed provider settings, or null when the config names no model. No fallback to\n// DEFAULT_EMBED_MODEL: that's a template constant `init` and the v4 migration write into the file, never a runtime default.\nexport function embedConfig(cfg: Config): { model: string; provider: 'static' | 'openai' | 'cohere'; url?: string; key?: string; languages?: string[]; chunkTokens?: number } | null {\n if (!embedEnabled(cfg)) return null;\n const e = cfg.embed as EmbedConfig;\n return { model: e.model as string, provider: e.provider ?? 'static', url: e.url, key: e.key, languages: e.languages, chunkTokens: e.chunkTokens };\n}\n\n//
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/access.ts"],"sourcesContent":["import type { Feature } from '../features/types.ts';\nimport type { SignalName, SignalWeights } from './signals.ts';\nimport { type Config, type EmbedConfig, FEATURE_NAMES, type FeatureName, type StoreName } from './types.ts';\n\nexport function presetNames(cfg: Config): string[] {\n return Object.keys(cfg.presets);\n}\n\n// The backing store engine this tree uses; absent means the default.\nexport function storeName(cfg: Config): StoreName {\n return cfg.store ?? 'sqlite';\n}\n\n// Whether the tree names a model at all.\nexport function embedEnabled(cfg: Config): boolean {\n return typeof cfg.embed?.model === 'string' && cfg.embed.model.length > 0;\n}\n\n// A preset's effective signal weights: declared exhaustively when `signals` is present, else\n// every signal whose prerequisite holds at weight 1 (words always, links when on, vectors when a model is named).\nexport function presetSignals(cfg: Config, name: string): SignalWeights {\n const declared = cfg.presets[name]?.signals;\n if (declared) return declared;\n const signals: SignalWeights = { words: 1 };\n if (cfg.features?.links !== false) signals.links = 1;\n if (embedEnabled(cfg)) signals.vectors = 1;\n return signals;\n}\n\nexport function presetHasSignal(cfg: Config, name: string, signal: SignalName): boolean {\n return presetSignals(cfg, name)[signal] !== undefined;\n}\n\n// Whether embedding needs to run: a model is named AND some preset's effective signals include vectors.\nexport function anyPresetEmbeds(cfg: Config): boolean {\n return presetNames(cfg).some((name) => presetHasSignal(cfg, name, 'vectors'));\n}\n\n// Opt-out features (default on): absent block or key means enabled. `rank` additionally requires\n// `links`. `embed` is derived (not a features-block member): on iff some preset's signals include vectors.\nexport function featureEnabled(cfg: Config, name: FeatureName): boolean {\n if (name === 'embed') return anyPresetEmbeds(cfg);\n const enabled = cfg.features?.[name] !== false;\n if (name === 'rank') return enabled && featureEnabled(cfg, 'links');\n return enabled;\n}\n\nexport function enabledFeatures(cfg: Config): FeatureName[] {\n return FEATURE_NAMES.filter((name) => featureEnabled(cfg, name));\n}\n\n// Feature states, so \"off\" and \"empty\" stay distinguishable in output. `embed` is excluded:\n// it is not a features-block toggle, and `status` reports it on its own line.\nexport function featureStates(cfg: Config): { on: FeatureName[]; off: FeatureName[] } {\n const reported = FEATURE_NAMES.filter((name) => name !== 'embed');\n return {\n on: reported.filter((name) => featureEnabled(cfg, name)),\n off: reported.filter((name) => !featureEnabled(cfg, name)),\n };\n}\n\n// Resolved embed provider settings, or null when the config names no model. No fallback to\n// DEFAULT_EMBED_MODEL: that's a template constant `init` and the v4 migration write into the file, never a runtime default.\nexport function embedConfig(cfg: Config): { model: string; provider: 'static' | 'openai' | 'cohere'; url?: string; key?: string; languages?: string[]; chunkTokens?: number } | null {\n if (!embedEnabled(cfg)) return null;\n const e = cfg.embed as EmbedConfig;\n return { model: e.model as string, provider: e.provider ?? 'static', url: e.url, key: e.key, languages: e.languages, chunkTokens: e.chunkTokens };\n}\n\n// Cache key over everything indexing derives from, so any change to those inputs rebuilds.\n// Segment order is fixed (one `feature:<name>:on|off` per FEATURE_NAMES entry but embed, then\n// `features` in registry order, then presets) since reordering alone would fire a spurious\n// rebuild; presets stay here because no Feature module owns it.\nexport function featureSignature(cfg: Config, features: Feature[]): string {\n // One segment per toggle (not one lumped csv) so store/signature.ts's changedSignatureKeys can\n // tell which feature moved -- store/feature-scope.ts routes a recognised toggle to a narrow\n // per-table invalidation instead of the full clear.\n const togglesPart = FEATURE_NAMES.filter((name) => name !== 'embed').map((name) => `feature:${name}:${featureEnabled(cfg, name) ? 'on' : 'off'}`);\n const featureParts = features.map((feature) => feature.signature?.(cfg)).filter((part): part is string => part !== undefined);\n // One keyed segment per preset so a rebuild notice can name exactly which preset moved.\n const presetsPart = [...presetNames(cfg)]\n .sort()\n .map((name) => {\n const p = cfg.presets[name];\n const include = [...p.include].sort().join('+');\n const exclude = [...(p.exclude ?? [])].sort().join('+');\n return `preset:${name}:${include}:${exclude}:${presetHasSignal(cfg, name, 'vectors') ? 'on' : 'off'}`;\n })\n .join('|');\n return [...togglesPart, ...featureParts, presetsPart].join('|');\n}\n"],"names":["anyPresetEmbeds","embedConfig","embedEnabled","enabledFeatures","featureEnabled","featureSignature","featureStates","presetHasSignal","presetNames","presetSignals","storeName","cfg","Object","keys","presets","store","embed","model","length","name","declared","signals","words","features","links","vectors","signal","undefined","some","enabled","FEATURE_NAMES","filter","reported","on","off","e","provider","url","key","languages","chunkTokens","togglesPart","map","featureParts","feature","signature","part","presetsPart","sort","p","include","join","exclude"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { anyPresetEmbeds,
|
|
1
|
+
export { anyPresetEmbeds, embedConfig, embedEnabled, enabledFeatures, featureEnabled, featureSignature, featureStates, presetHasSignal, presetNames, presetSignals, storeName } from './access.js';
|
|
2
2
|
export type { InitOverrides } from './load.js';
|
|
3
3
|
export { findConfigPath, initConfig, loadConfig, migrateConfig } from './load.js';
|
|
4
4
|
export { resolvePreset, resolveSearch } from './resolve.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { anyPresetEmbeds,
|
|
1
|
+
export { anyPresetEmbeds, embedConfig, embedEnabled, enabledFeatures, featureEnabled, featureSignature, featureStates, presetHasSignal, presetNames, presetSignals, storeName } from './access.js';
|
|
2
2
|
export type { InitOverrides } from './load.js';
|
|
3
3
|
export { findConfigPath, initConfig, loadConfig, migrateConfig } from './load.js';
|
|
4
4
|
export { resolvePreset, resolveSearch } from './resolve.js';
|
package/dist/cjs/config/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/index.ts"],"sourcesContent":["export { anyPresetEmbeds,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/index.ts"],"sourcesContent":["export { anyPresetEmbeds, embedConfig, embedEnabled, enabledFeatures, featureEnabled, featureSignature, featureStates, presetHasSignal, presetNames, presetSignals, storeName } from './access.ts';\nexport type { InitOverrides } from './load.ts';\nexport { findConfigPath, initConfig, loadConfig, migrateConfig } from './load.ts';\nexport { resolvePreset, resolveSearch } from './resolve.ts';\nexport type { SignalName, SignalWeights } from './signals.ts';\nexport { SIGNAL_NAMES, SIGNAL_PREREQUISITES } from './signals.ts';\nexport type { Config, EffectiveSearch, EmbedConfig, FeatureName, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, StoreName } from './types.ts';\nexport { CONFIG_FILENAME, DEFAULT_EMBED_MODEL, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './types.ts';\nexport { KNOWN_EMBED_KEYS } from './validate.ts';\n"],"names":["CONFIG_FILENAME","DEFAULT_EMBED_MODEL","KNOWN_EMBED_KEYS","SIGNAL_NAMES","SIGNAL_PREREQUISITES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION","anyPresetEmbeds","embedConfig","embedEnabled","enabledFeatures","featureEnabled","featureSignature","featureStates","findConfigPath","initConfig","loadConfig","migrateConfig","presetHasSignal","presetNames","presetSignals","resolvePreset","resolveSearch","storeName"],"mappings":";;;;;;;;;;;QAOSA;eAAAA,wBAAe;;QAAEC;eAAAA,4BAAmB;;QACpCC;eAAAA,4BAAgB;;QAHhBC;eAAAA,uBAAY;;QAAEC;eAAAA,+BAAoB;;QAEIC;eAAAA,kBAAS;;QAAEC;eAAAA,oBAAW;;QAAEC;eAAAA,iCAAwB;;QAPtFC;eAAAA,yBAAe;;QAAEC;eAAAA,qBAAW;;QAAEC;eAAAA,sBAAY;;QAAEC;eAAAA,yBAAe;;QAAEC;eAAAA,wBAAc;;QAAEC;eAAAA,0BAAgB;;QAAEC;eAAAA,uBAAa;;QAE5GC;eAAAA,sBAAc;;QAAEC;eAAAA,kBAAU;;QAAEC;eAAAA,kBAAU;;QAAEC;eAAAA,qBAAa;;QAFyDC;eAAAA,yBAAe;;QAAEC;eAAAA,qBAAW;;QAAEC;eAAAA,uBAAa;;QAGzJC;eAAAA,wBAAa;;QAAEC;eAAAA,wBAAa;;QAH+HC;eAAAA,mBAAS;;;wBAAQ;sBAE/G;yBACzB;yBAEM;uBAEoD;0BACtE"}
|
|
@@ -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 config file. 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 // 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 //
|
|
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 config file. 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 // 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 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"}
|
|
@@ -83,7 +83,6 @@ var KNOWN_KEYS = new Set([
|
|
|
83
83
|
'presets',
|
|
84
84
|
'features',
|
|
85
85
|
'embed',
|
|
86
|
-
'content',
|
|
87
86
|
'store',
|
|
88
87
|
'queries'
|
|
89
88
|
]);
|
|
@@ -108,9 +107,6 @@ var KNOWN_EMBED_KEYS = new Set([
|
|
|
108
107
|
'languages',
|
|
109
108
|
'chunkTokens'
|
|
110
109
|
]);
|
|
111
|
-
var KNOWN_CONTENT_KEYS = new Set([
|
|
112
|
-
'tokenize'
|
|
113
|
-
]);
|
|
114
110
|
var SAVED_SEARCH_KEYS = new Set([
|
|
115
111
|
'search',
|
|
116
112
|
'preset',
|
|
@@ -136,23 +132,6 @@ function validateLegacyScan(parsed, configPath) {
|
|
|
136
132
|
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": scan.include must be a non-empty array of glob strings"));
|
|
137
133
|
}
|
|
138
134
|
}
|
|
139
|
-
// Only the shape is checked here. Whether the linked SQLite accepts the tokenizer is settled
|
|
140
|
-
// by probing it in store/sqlite/open.ts, so this never has to carry a table of which version added what.
|
|
141
|
-
function validateContentBlock(value, configPath) {
|
|
142
|
-
if ((typeof value === "undefined" ? "undefined" : _type_of(value)) !== 'object' || value === null || Array.isArray(value)) {
|
|
143
|
-
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": content must be an object of { tokenize?: string }"));
|
|
144
|
-
}
|
|
145
|
-
var block = value;
|
|
146
|
-
var unknown = Object.keys(block).filter(function(k) {
|
|
147
|
-
return !KNOWN_CONTENT_KEYS.has(k);
|
|
148
|
-
});
|
|
149
|
-
if (unknown.length > 0) {
|
|
150
|
-
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": content has unknown key(s) ").concat(unknown.join(', '), "; content takes tokenize"));
|
|
151
|
-
}
|
|
152
|
-
if (block.tokenize !== undefined && (typeof block.tokenize !== 'string' || block.tokenize.trim() === '')) {
|
|
153
|
-
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ': content.tokenize must be a non-empty string, e.g. "trigram" or "unicode61 tokenchars \'-_\'"'));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
135
|
function validateStoreKey(value, configPath) {
|
|
157
136
|
if (!_typests.STORE_NAMES.includes(value)) {
|
|
158
137
|
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": store must be ").concat(_typests.STORE_NAMES.map(function(name) {
|
|
@@ -395,6 +374,12 @@ function validateConfig(parsed, configPath) {
|
|
|
395
374
|
if (cfg.checks !== undefined) {
|
|
396
375
|
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": checks was removed in v3 -- sense check no longer asserts on saved queries; a returned row set is the reader's judgment"));
|
|
397
376
|
}
|
|
377
|
+
// `content` (content.tokenize) is rejected by name for the same reason: every outcome it
|
|
378
|
+
// selected (unspaced-script search, stemming, quoted-phrase substring matching) is now
|
|
379
|
+
// automatic on every store, so a config that still sets it would silently get nothing back.
|
|
380
|
+
if (cfg.content !== undefined) {
|
|
381
|
+
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ': content.tokenize was removed -- every outcome it selected is now automatic on every store; remove the "content" block'));
|
|
382
|
+
}
|
|
398
383
|
var presets = cfg.presets;
|
|
399
384
|
if (!presets || (typeof presets === "undefined" ? "undefined" : _type_of(presets)) !== 'object' || Array.isArray(presets) || Object.keys(presets).length === 0) {
|
|
400
385
|
throw new _errorsts.SenseError('CONFIG_INVALID', "".concat(configPath, ": presets must be a non-empty object of preset name -> { include, exclude?, k?, signals?, where? }"));
|
|
@@ -453,9 +438,6 @@ function validateConfig(parsed, configPath) {
|
|
|
453
438
|
if (cfg.embed !== undefined) {
|
|
454
439
|
validateEmbedBlock(cfg.embed, configPath);
|
|
455
440
|
}
|
|
456
|
-
if (cfg.content !== undefined) {
|
|
457
|
-
validateContentBlock(cfg.content, configPath);
|
|
458
|
-
}
|
|
459
441
|
if (cfg.store !== undefined) {
|
|
460
442
|
validateStoreKey(cfg.store, configPath);
|
|
461
443
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/validate.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { SIGNAL_NAMES, SIGNAL_PREREQUISITES, type SignalName } from './signals.ts';\nimport { type Config, STORE_NAMES, type StoreName } from './types.ts';\n\n// Shape check for hand-edited files, so a typo names itself instead of surfacing as a\n// TypeError. Unknown top-level keys warn (forward compat); unknown keys inside a block error.\nconst KNOWN_KEYS = new Set(['$schema', 'version', 'presets', 'features', 'embed', 'content', 'store', 'queries']);\nconst KNOWN_PRESET_KEYS = new Set(['include', 'exclude', 'k', 'signals', 'where']);\nconst KNOWN_FEATURE_KEYS = new Set(['links', 'sections', 'tags', 'rank']);\n// Exported so a docs test can assert every key here has a schema.json property -- one source\n// of truth for what the embed block accepts, checked against the other for drift.\nexport const KNOWN_EMBED_KEYS = new Set(['model', 'provider', 'url', 'key', 'languages', 'chunkTokens']);\nconst KNOWN_CONTENT_KEYS = new Set(['tokenize']);\nconst SAVED_SEARCH_KEYS = new Set(['search', 'preset', 'include', 'exclude', 'where', 'k']);\n\nexport function unknownConfigKeys(cfg: Record<string, unknown>): string[] {\n return Object.keys(cfg).filter((k) => !KNOWN_KEYS.has(k));\n}\n\nfunction isNonEmptyStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.length > 0 && value.every((g) => typeof g === 'string' && g.length > 0);\n}\n\n// Pre-v3 shape check, just enough for migrateConfig to run safely (it reads scan.include\n// directly). The full v3 shape is checked by validateConfig once migration has produced it.\nexport function validateLegacyScan(parsed: unknown, configPath: string): void {\n const cfg = typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ? (parsed as Record<string, unknown>) : null;\n const scan = cfg?.scan as { include?: unknown } | undefined;\n if (!cfg || !scan || !isNonEmptyStringArray(scan.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: scan.include must be a non-empty array of glob strings`);\n }\n}\n\n// Only the shape is checked here. Whether the linked SQLite accepts the tokenizer is settled\n// by probing it in store/sqlite/open.ts, so this never has to carry a table of which version added what.\nfunction validateContentBlock(value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: content must be an object of { tokenize?: string }`);\n }\n const block = value as Record<string, unknown>;\n const unknown = Object.keys(block).filter((k) => !KNOWN_CONTENT_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: content has unknown key(s) ${unknown.join(', ')}; content takes tokenize`);\n }\n if (block.tokenize !== undefined && (typeof block.tokenize !== 'string' || block.tokenize.trim() === '')) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: content.tokenize must be a non-empty string, e.g. \"trigram\" or \"unicode61 tokenchars '-_'\"`);\n }\n}\n\nfunction validateStoreKey(value: unknown, configPath: string): void {\n if (!STORE_NAMES.includes(value as StoreName)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: store must be ${STORE_NAMES.map((name) => `\"${name}\"`).join(' or ')}`);\n }\n}\n\nfunction validateFeaturesBlock(value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features must be an object of name -> boolean`);\n }\n const block = value as Record<string, unknown>;\n const unknown = Object.keys(block).filter((k) => !KNOWN_FEATURE_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features has unknown key(s) ${unknown.join(', ')}; embed is not a features key -- see the top-level \"embed\" block`);\n }\n for (const [name, v] of Object.entries(block)) {\n if (typeof v !== 'boolean') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features.${name} must be a boolean`);\n }\n }\n}\n\nfunction validateEmbedBlock(value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed must be an object of { model?, provider?: \"static\"|\"openai\"|\"cohere\", url?, key? }`);\n }\n const embed = value as Record<string, unknown>;\n const unknown = Object.keys(embed).filter((k) => !KNOWN_EMBED_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed has unknown key(s) ${unknown.join(', ')}`);\n }\n if (embed.model !== undefined && typeof embed.model !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.model must be a string`);\n }\n // The block exists to name a model; provider settings without one would read as \"vectors\n // configured\" while embedding stays off, which is the ambiguity v4 removed.\n if (embed.model === undefined || embed.model === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.model is required when the \"embed\" block is present (it is what turns vectors on); remove the block to index without vectors`);\n }\n if (embed.provider !== undefined && embed.provider !== 'static' && embed.provider !== 'openai' && embed.provider !== 'cohere') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.provider must be \"static\", \"openai\", or \"cohere\"`);\n }\n if (embed.url !== undefined && typeof embed.url !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.url must be a string`);\n }\n if (embed.key !== undefined && typeof embed.key !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.key must be a string`);\n }\n // openai has no default host, so a missing url would otherwise only surface at the first\n // vector search; a config error belongs at config time.\n if (embed.provider === 'openai' && (embed.url === undefined || embed.url === '')) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.provider \"openai\" requires embed.url (e.g. \"http://localhost:11434/v1\" for Ollama)`);\n }\n if (embed.languages !== undefined && (!Array.isArray(embed.languages) || embed.languages.length === 0 || embed.languages.some((l) => typeof l !== 'string' || l === ''))) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.languages must be a non-empty array of language tags (e.g. [\"en\", \"zh\"])`);\n }\n if (embed.chunkTokens !== undefined && (typeof embed.chunkTokens !== 'number' || !Number.isInteger(embed.chunkTokens) || embed.chunkTokens <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.chunkTokens must be a positive integer`);\n }\n}\n\nfunction isSignalName(value: unknown): value is SignalName {\n return typeof value === 'string' && (SIGNAL_NAMES as readonly string[]).includes(value);\n}\n\nfunction isSignalWeight(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0;\n}\n\n// Shape (an object of signal name -> weight) plus the one cross-signal prerequisite that doesn't\n// need the top-level embed block: links is seeded by word-match rows, so declaring it without words is always empty.\nfunction validatePresetSignals(name: string, value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value) || Object.keys(value).length === 0) {\n throw new SenseError(\n 'CONFIG_INVALID',\n `${configPath}: presets.${name}.signals must be a non-empty object of signal name -> weight (a finite number > 0), naming ${SIGNAL_NAMES.join(', ')} -- a preset that searches nothing is a mistake; name at least \"words\", or omit \"signals\" to use every signal whose prerequisites hold at weight 1`\n );\n }\n const entries = Object.entries(value as Record<string, unknown>);\n const unknown = entries.filter(([k]) => !isSignalName(k)).map(([k]) => k);\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals names unknown signal(s) ${unknown.join(', ')}; valid signals are ${SIGNAL_NAMES.join(', ')}`);\n }\n for (const [signal, weight] of entries) {\n if (!isSignalWeight(weight)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals.${signal} must be a finite number > 0`);\n }\n }\n const names = new Set(entries.map(([k]) => k));\n for (const [signal, requires] of Object.entries(SIGNAL_PREREQUISITES) as Array<[SignalName, SignalName]>) {\n if (names.has(signal) && !names.has(requires)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals has \"${signal}\" without \"${requires}\"; add \"${requires}\" to presets.${name}.signals, or drop \"${signal}\"`);\n }\n }\n}\n\nfunction validatePreset(name: string, value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name} must be an object`);\n }\n const preset = value as Record<string, unknown>;\n const unknown = Object.keys(preset).filter((k) => !KNOWN_PRESET_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name} has unknown key(s) ${unknown.join(', ')}; a preset takes include, exclude, k, signals, where`);\n }\n if (!isNonEmptyStringArray(preset.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.include must be a non-empty array of glob strings`);\n }\n if (preset.exclude !== undefined && !isNonEmptyStringArray(preset.exclude)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.exclude must be a non-empty array of glob strings`);\n }\n if (preset.signals !== undefined) validatePresetSignals(name, preset.signals, configPath);\n if (preset.k !== undefined && (typeof preset.k !== 'number' || !Number.isInteger(preset.k) || preset.k <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.k must be a positive integer`);\n }\n if (preset.where !== undefined && typeof preset.where !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.where must be a SQL condition string`);\n }\n}\n\n// A queries.<name> entry: { sql } or a saved search { search, preset?, include?, exclude?, where?, k? }.\nfunction validateSavedQuery(name: string, value: unknown, configPath: string): void {\n // A bare string is rejected rather than inferred to be SQL: an entry says which of the two\n // verbs it runs, the same choice the CLI makes explicit.\n if (typeof value === 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must say which verb it runs: { \"sql\": ${JSON.stringify(value.length > 40 ? `${value.slice(0, 37)}...` : value)} } to run it as SQL, or { \"search\": \"...\" } for a ranked search`);\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must be { sql } or { search, preset?, include?, exclude?, where?, k? }`);\n }\n const entry = value as Record<string, unknown>;\n if ('sql' in entry) {\n const unknown = Object.keys(entry).filter((k) => k !== 'sql');\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} has unknown key(s) ${unknown.join(', ')}; a { sql } query takes only sql`);\n }\n if (typeof entry.sql !== 'string' || entry.sql.trim() === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.sql must be a non-empty string`);\n }\n return;\n }\n if ('search' in entry) {\n const unknown = Object.keys(entry).filter((k) => !SAVED_SEARCH_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} has unknown key(s) ${unknown.join(', ')}; a saved search takes search, preset, include, exclude, where, k`);\n }\n // A saved entry saves a question; a scope without a question is just flags.\n if (typeof entry.search !== 'string' || entry.search.trim() === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.search must be non-empty text`);\n }\n if (entry.preset !== undefined && (typeof entry.preset !== 'string' || entry.preset.length === 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.preset must be a preset name`);\n }\n if (entry.include !== undefined && !isNonEmptyStringArray(entry.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.include must be a non-empty array of glob strings`);\n }\n if (entry.exclude !== undefined && !isNonEmptyStringArray(entry.exclude)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.exclude must be a non-empty array of glob strings`);\n }\n if (entry.where !== undefined && typeof entry.where !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.where must be a SQL condition string`);\n }\n if (entry.k !== undefined && (typeof entry.k !== 'number' || !Number.isInteger(entry.k) || entry.k <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.k must be a positive integer`);\n }\n return;\n }\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must be { sql } or { search, preset?, include?, exclude?, where?, k? }`);\n}\n\nexport function validateConfig(parsed: unknown, configPath: string): Config {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);\n }\n const cfg = parsed as Record<string, unknown>;\n\n // `checks` is rejected by name, not warned: silence would hide that assertions are gone.\n if (cfg.checks !== undefined) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: checks was removed in v3 -- sense check no longer asserts on saved queries; a returned row set is the reader's judgment`);\n }\n\n const presets = cfg.presets as Record<string, unknown> | undefined;\n if (!presets || typeof presets !== 'object' || Array.isArray(presets) || Object.keys(presets).length === 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets must be a non-empty object of preset name -> { include, exclude?, k?, signals?, where? }`);\n }\n for (const [name, value] of Object.entries(presets)) {\n validatePreset(name, value, configPath);\n }\n if (presets.default === undefined) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets must include a \"default\" preset`);\n }\n\n if (cfg.queries === undefined) cfg.queries = {};\n if (typeof cfg.queries !== 'object' || cfg.queries === null || Array.isArray(cfg.queries)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries must be an object of name -> { sql } or { search }`);\n }\n const queries = cfg.queries as Record<string, unknown>;\n for (const [name, value] of Object.entries(queries)) {\n validateSavedQuery(name, value, configPath);\n }\n\n if (cfg.features !== undefined) {\n validateFeaturesBlock(cfg.features, configPath);\n }\n if (cfg.embed !== undefined) {\n validateEmbedBlock(cfg.embed, configPath);\n }\n if (cfg.content !== undefined) {\n validateContentBlock(cfg.content, configPath);\n }\n if (cfg.store !== undefined) {\n validateStoreKey(cfg.store, configPath);\n }\n\n // vectors' prerequisite is a named model, checked here once embed is known valid (or absent).\n if (cfg.embed === undefined) {\n for (const [name, value] of Object.entries(presets)) {\n const signals = (value as Record<string, unknown>).signals as Record<string, unknown> | undefined;\n if (signals && 'vectors' in signals) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals includes \"vectors\", but no \"embed\" block names a model; add one, or drop \"vectors\" from presets.${name}.signals`);\n }\n }\n }\n\n return cfg as unknown as Config;\n}\n"],"names":["KNOWN_EMBED_KEYS","unknownConfigKeys","validateConfig","validateLegacyScan","KNOWN_KEYS","Set","KNOWN_PRESET_KEYS","KNOWN_FEATURE_KEYS","KNOWN_CONTENT_KEYS","SAVED_SEARCH_KEYS","cfg","Object","keys","filter","k","has","isNonEmptyStringArray","value","Array","isArray","length","every","g","parsed","configPath","scan","include","SenseError","validateContentBlock","block","unknown","join","tokenize","undefined","trim","validateStoreKey","STORE_NAMES","includes","map","name","validateFeaturesBlock","entries","v","validateEmbedBlock","embed","model","provider","url","key","languages","some","l","chunkTokens","Number","isInteger","isSignalName","SIGNAL_NAMES","isSignalWeight","isFinite","validatePresetSignals","signal","weight","names","SIGNAL_PREREQUISITES","requires","validatePreset","preset","exclude","signals","where","validateSavedQuery","JSON","stringify","slice","entry","sql","search","checks","presets","default","queries","features","content","store"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/config/validate.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { SIGNAL_NAMES, SIGNAL_PREREQUISITES, type SignalName } from './signals.ts';\nimport { type Config, STORE_NAMES, type StoreName } from './types.ts';\n\n// Shape check for hand-edited files, so a typo names itself instead of surfacing as a\n// TypeError. Unknown top-level keys warn (forward compat); unknown keys inside a block error.\nconst KNOWN_KEYS = new Set(['$schema', 'version', 'presets', 'features', 'embed', 'store', 'queries']);\nconst KNOWN_PRESET_KEYS = new Set(['include', 'exclude', 'k', 'signals', 'where']);\nconst KNOWN_FEATURE_KEYS = new Set(['links', 'sections', 'tags', 'rank']);\n// Exported so a docs test can assert every key here has a schema.json property -- one source\n// of truth for what the embed block accepts, checked against the other for drift.\nexport const KNOWN_EMBED_KEYS = new Set(['model', 'provider', 'url', 'key', 'languages', 'chunkTokens']);\nconst SAVED_SEARCH_KEYS = new Set(['search', 'preset', 'include', 'exclude', 'where', 'k']);\n\nexport function unknownConfigKeys(cfg: Record<string, unknown>): string[] {\n return Object.keys(cfg).filter((k) => !KNOWN_KEYS.has(k));\n}\n\nfunction isNonEmptyStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.length > 0 && value.every((g) => typeof g === 'string' && g.length > 0);\n}\n\n// Pre-v3 shape check, just enough for migrateConfig to run safely (it reads scan.include\n// directly). The full v3 shape is checked by validateConfig once migration has produced it.\nexport function validateLegacyScan(parsed: unknown, configPath: string): void {\n const cfg = typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ? (parsed as Record<string, unknown>) : null;\n const scan = cfg?.scan as { include?: unknown } | undefined;\n if (!cfg || !scan || !isNonEmptyStringArray(scan.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: scan.include must be a non-empty array of glob strings`);\n }\n}\n\nfunction validateStoreKey(value: unknown, configPath: string): void {\n if (!STORE_NAMES.includes(value as StoreName)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: store must be ${STORE_NAMES.map((name) => `\"${name}\"`).join(' or ')}`);\n }\n}\n\nfunction validateFeaturesBlock(value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features must be an object of name -> boolean`);\n }\n const block = value as Record<string, unknown>;\n const unknown = Object.keys(block).filter((k) => !KNOWN_FEATURE_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features has unknown key(s) ${unknown.join(', ')}; embed is not a features key -- see the top-level \"embed\" block`);\n }\n for (const [name, v] of Object.entries(block)) {\n if (typeof v !== 'boolean') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: features.${name} must be a boolean`);\n }\n }\n}\n\nfunction validateEmbedBlock(value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed must be an object of { model?, provider?: \"static\"|\"openai\"|\"cohere\", url?, key? }`);\n }\n const embed = value as Record<string, unknown>;\n const unknown = Object.keys(embed).filter((k) => !KNOWN_EMBED_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed has unknown key(s) ${unknown.join(', ')}`);\n }\n if (embed.model !== undefined && typeof embed.model !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.model must be a string`);\n }\n // The block exists to name a model; provider settings without one would read as \"vectors\n // configured\" while embedding stays off, which is the ambiguity v4 removed.\n if (embed.model === undefined || embed.model === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.model is required when the \"embed\" block is present (it is what turns vectors on); remove the block to index without vectors`);\n }\n if (embed.provider !== undefined && embed.provider !== 'static' && embed.provider !== 'openai' && embed.provider !== 'cohere') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.provider must be \"static\", \"openai\", or \"cohere\"`);\n }\n if (embed.url !== undefined && typeof embed.url !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.url must be a string`);\n }\n if (embed.key !== undefined && typeof embed.key !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.key must be a string`);\n }\n // openai has no default host, so a missing url would otherwise only surface at the first\n // vector search; a config error belongs at config time.\n if (embed.provider === 'openai' && (embed.url === undefined || embed.url === '')) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.provider \"openai\" requires embed.url (e.g. \"http://localhost:11434/v1\" for Ollama)`);\n }\n if (embed.languages !== undefined && (!Array.isArray(embed.languages) || embed.languages.length === 0 || embed.languages.some((l) => typeof l !== 'string' || l === ''))) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.languages must be a non-empty array of language tags (e.g. [\"en\", \"zh\"])`);\n }\n if (embed.chunkTokens !== undefined && (typeof embed.chunkTokens !== 'number' || !Number.isInteger(embed.chunkTokens) || embed.chunkTokens <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: embed.chunkTokens must be a positive integer`);\n }\n}\n\nfunction isSignalName(value: unknown): value is SignalName {\n return typeof value === 'string' && (SIGNAL_NAMES as readonly string[]).includes(value);\n}\n\nfunction isSignalWeight(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0;\n}\n\n// Shape (an object of signal name -> weight) plus the one cross-signal prerequisite that doesn't\n// need the top-level embed block: links is seeded by word-match rows, so declaring it without words is always empty.\nfunction validatePresetSignals(name: string, value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value) || Object.keys(value).length === 0) {\n throw new SenseError(\n 'CONFIG_INVALID',\n `${configPath}: presets.${name}.signals must be a non-empty object of signal name -> weight (a finite number > 0), naming ${SIGNAL_NAMES.join(', ')} -- a preset that searches nothing is a mistake; name at least \"words\", or omit \"signals\" to use every signal whose prerequisites hold at weight 1`\n );\n }\n const entries = Object.entries(value as Record<string, unknown>);\n const unknown = entries.filter(([k]) => !isSignalName(k)).map(([k]) => k);\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals names unknown signal(s) ${unknown.join(', ')}; valid signals are ${SIGNAL_NAMES.join(', ')}`);\n }\n for (const [signal, weight] of entries) {\n if (!isSignalWeight(weight)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals.${signal} must be a finite number > 0`);\n }\n }\n const names = new Set(entries.map(([k]) => k));\n for (const [signal, requires] of Object.entries(SIGNAL_PREREQUISITES) as Array<[SignalName, SignalName]>) {\n if (names.has(signal) && !names.has(requires)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals has \"${signal}\" without \"${requires}\"; add \"${requires}\" to presets.${name}.signals, or drop \"${signal}\"`);\n }\n }\n}\n\nfunction validatePreset(name: string, value: unknown, configPath: string): void {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name} must be an object`);\n }\n const preset = value as Record<string, unknown>;\n const unknown = Object.keys(preset).filter((k) => !KNOWN_PRESET_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name} has unknown key(s) ${unknown.join(', ')}; a preset takes include, exclude, k, signals, where`);\n }\n if (!isNonEmptyStringArray(preset.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.include must be a non-empty array of glob strings`);\n }\n if (preset.exclude !== undefined && !isNonEmptyStringArray(preset.exclude)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.exclude must be a non-empty array of glob strings`);\n }\n if (preset.signals !== undefined) validatePresetSignals(name, preset.signals, configPath);\n if (preset.k !== undefined && (typeof preset.k !== 'number' || !Number.isInteger(preset.k) || preset.k <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.k must be a positive integer`);\n }\n if (preset.where !== undefined && typeof preset.where !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.where must be a SQL condition string`);\n }\n}\n\n// A queries.<name> entry: { sql } or a saved search { search, preset?, include?, exclude?, where?, k? }.\nfunction validateSavedQuery(name: string, value: unknown, configPath: string): void {\n // A bare string is rejected rather than inferred to be SQL: an entry says which of the two\n // verbs it runs, the same choice the CLI makes explicit.\n if (typeof value === 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must say which verb it runs: { \"sql\": ${JSON.stringify(value.length > 40 ? `${value.slice(0, 37)}...` : value)} } to run it as SQL, or { \"search\": \"...\" } for a ranked search`);\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must be { sql } or { search, preset?, include?, exclude?, where?, k? }`);\n }\n const entry = value as Record<string, unknown>;\n if ('sql' in entry) {\n const unknown = Object.keys(entry).filter((k) => k !== 'sql');\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} has unknown key(s) ${unknown.join(', ')}; a { sql } query takes only sql`);\n }\n if (typeof entry.sql !== 'string' || entry.sql.trim() === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.sql must be a non-empty string`);\n }\n return;\n }\n if ('search' in entry) {\n const unknown = Object.keys(entry).filter((k) => !SAVED_SEARCH_KEYS.has(k));\n if (unknown.length > 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} has unknown key(s) ${unknown.join(', ')}; a saved search takes search, preset, include, exclude, where, k`);\n }\n // A saved entry saves a question; a scope without a question is just flags.\n if (typeof entry.search !== 'string' || entry.search.trim() === '') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.search must be non-empty text`);\n }\n if (entry.preset !== undefined && (typeof entry.preset !== 'string' || entry.preset.length === 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.preset must be a preset name`);\n }\n if (entry.include !== undefined && !isNonEmptyStringArray(entry.include)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.include must be a non-empty array of glob strings`);\n }\n if (entry.exclude !== undefined && !isNonEmptyStringArray(entry.exclude)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.exclude must be a non-empty array of glob strings`);\n }\n if (entry.where !== undefined && typeof entry.where !== 'string') {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.where must be a SQL condition string`);\n }\n if (entry.k !== undefined && (typeof entry.k !== 'number' || !Number.isInteger(entry.k) || entry.k <= 0)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name}.k must be a positive integer`);\n }\n return;\n }\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries.${name} must be { sql } or { search, preset?, include?, exclude?, where?, k? }`);\n}\n\nexport function validateConfig(parsed: unknown, configPath: string): Config {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: config must be a JSON object`);\n }\n const cfg = parsed as Record<string, unknown>;\n\n // `checks` is rejected by name, not warned: silence would hide that assertions are gone.\n if (cfg.checks !== undefined) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: checks was removed in v3 -- sense check no longer asserts on saved queries; a returned row set is the reader's judgment`);\n }\n\n // `content` (content.tokenize) is rejected by name for the same reason: every outcome it\n // selected (unspaced-script search, stemming, quoted-phrase substring matching) is now\n // automatic on every store, so a config that still sets it would silently get nothing back.\n if (cfg.content !== undefined) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: content.tokenize was removed -- every outcome it selected is now automatic on every store; remove the \"content\" block`);\n }\n\n const presets = cfg.presets as Record<string, unknown> | undefined;\n if (!presets || typeof presets !== 'object' || Array.isArray(presets) || Object.keys(presets).length === 0) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets must be a non-empty object of preset name -> { include, exclude?, k?, signals?, where? }`);\n }\n for (const [name, value] of Object.entries(presets)) {\n validatePreset(name, value, configPath);\n }\n if (presets.default === undefined) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets must include a \"default\" preset`);\n }\n\n if (cfg.queries === undefined) cfg.queries = {};\n if (typeof cfg.queries !== 'object' || cfg.queries === null || Array.isArray(cfg.queries)) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: queries must be an object of name -> { sql } or { search }`);\n }\n const queries = cfg.queries as Record<string, unknown>;\n for (const [name, value] of Object.entries(queries)) {\n validateSavedQuery(name, value, configPath);\n }\n\n if (cfg.features !== undefined) {\n validateFeaturesBlock(cfg.features, configPath);\n }\n if (cfg.embed !== undefined) {\n validateEmbedBlock(cfg.embed, configPath);\n }\n if (cfg.store !== undefined) {\n validateStoreKey(cfg.store, configPath);\n }\n\n // vectors' prerequisite is a named model, checked here once embed is known valid (or absent).\n if (cfg.embed === undefined) {\n for (const [name, value] of Object.entries(presets)) {\n const signals = (value as Record<string, unknown>).signals as Record<string, unknown> | undefined;\n if (signals && 'vectors' in signals) {\n throw new SenseError('CONFIG_INVALID', `${configPath}: presets.${name}.signals includes \"vectors\", but no \"embed\" block names a model; add one, or drop \"vectors\" from presets.${name}.signals`);\n }\n }\n }\n\n return cfg as unknown as Config;\n}\n"],"names":["KNOWN_EMBED_KEYS","unknownConfigKeys","validateConfig","validateLegacyScan","KNOWN_KEYS","Set","KNOWN_PRESET_KEYS","KNOWN_FEATURE_KEYS","SAVED_SEARCH_KEYS","cfg","Object","keys","filter","k","has","isNonEmptyStringArray","value","Array","isArray","length","every","g","parsed","configPath","scan","include","SenseError","validateStoreKey","STORE_NAMES","includes","map","name","join","validateFeaturesBlock","block","unknown","entries","v","validateEmbedBlock","embed","model","undefined","provider","url","key","languages","some","l","chunkTokens","Number","isInteger","isSignalName","SIGNAL_NAMES","isSignalWeight","isFinite","validatePresetSignals","signal","weight","names","SIGNAL_PREREQUISITES","requires","validatePreset","preset","exclude","signals","where","validateSavedQuery","JSON","stringify","slice","entry","sql","trim","search","checks","content","presets","default","queries","features","store"],"mappings":"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"}
|
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' | '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_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);
|
package/dist/cjs/errors.d.ts
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' | '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_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);
|
package/dist/cjs/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/errors.ts"],"sourcesContent":["// Library code throws; only cli.ts prints and exits.\nexport type SenseErrorCode =\n | 'CONFIG_NOT_FOUND'\n | 'CONFIG_EXISTS'\n | 'CONFIG_INVALID'\n | 'CONFIG_VERSION_UNSUPPORTED'\n | 'WATCH_ACTIVE'\n | 'NOTE_NOT_FOUND'\n | 'NOTE_AMBIGUOUS'\n | 'EMBED_DISABLED'\n | 'EMBED_MODEL'\n | 'EMBED_MODEL_MISSING'\n | 'EMBED_MODEL_MISMATCH'\n | 'SEARCH_SYNTAX'\n | 'COLUMN_LIMIT'\n | 'PRESET_UNKNOWN'\n | 'PRESET_NOT_SEMANTIC'\n | 'NOTE_NOT_EMBEDDED'\n | 'STORE_UNKNOWN'\n | 'STORE_DEPENDENCY_MISSING'\n | 'STORE_CAPABILITY_MISSING'\n | 'LEXICAL_NULL_PATH';\n\nexport class SenseError extends Error {\n code: SenseErrorCode;\n\n constructor(code: SenseErrorCode, message: string) {\n super(message);\n this.name = 'SenseError';\n this.code = code;\n }\n}\n"],"names":["SenseError","code","message","name","Error"],"mappings":"AAAA,qDAAqD;;;;;+
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/errors.ts"],"sourcesContent":["// Library code throws; only cli.ts prints and exits.\nexport type SenseErrorCode =\n | 'CONFIG_NOT_FOUND'\n | 'CONFIG_EXISTS'\n | 'CONFIG_INVALID'\n | 'CONFIG_VERSION_UNSUPPORTED'\n | 'WATCH_ACTIVE'\n | 'NOTE_NOT_FOUND'\n | 'NOTE_AMBIGUOUS'\n | 'EMBED_DISABLED'\n | 'EMBED_MODEL'\n | 'EMBED_MODEL_MISSING'\n | 'EMBED_MODEL_MISMATCH'\n | 'SEARCH_SYNTAX'\n | 'COLUMN_LIMIT'\n | 'PRESET_UNKNOWN'\n | 'PRESET_NOT_SEMANTIC'\n | 'NOTE_NOT_EMBEDDED'\n | 'STORE_UNKNOWN'\n | 'STORE_DEPENDENCY_MISSING'\n | 'STORE_CAPABILITY_MISSING'\n | 'STORE_BUSY'\n | 'LEXICAL_NULL_PATH';\n\nexport class SenseError extends Error {\n code: SenseErrorCode;\n\n constructor(code: SenseErrorCode, message: string) {\n super(message);\n this.name = 'SenseError';\n this.code = code;\n }\n}\n"],"names":["SenseError","code","message","name","Error"],"mappings":"AAAA,qDAAqD;;;;;+BAwBxCA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAN,IAAA,AAAMA,2BAAN;;cAAMA;aAAAA,WAGCC,IAAoB,EAAEC,OAAe;gCAHtCF;;gBAIT,kBAJSA;YAIHE;;QACN,MAAKC,IAAI,GAAG;QACZ,MAAKF,IAAI,GAAGA;;;WANHD;qBAAmBI"}
|
|
@@ -946,17 +946,16 @@ var links = {
|
|
|
946
946
|
},
|
|
947
947
|
afterReconcile: function afterReconcile(db, delta) {
|
|
948
948
|
return _async_to_generator(function() {
|
|
949
|
-
var _removedWithLinks_get, removeHadLinks,
|
|
949
|
+
var _removedWithLinks_get, removeHadLinks, large, dstChanged, _tmp;
|
|
950
950
|
return _ts_generator(this, function(_state) {
|
|
951
951
|
switch(_state.label){
|
|
952
952
|
case 0:
|
|
953
953
|
// Any deleted rows mean the edge set shrank -- whether the file vanished or was reparsed
|
|
954
954
|
// down to fewer/no links.
|
|
955
955
|
removeHadLinks = (_removedWithLinks_get = removedWithLinks.get(delta)) !== null && _removedWithLinks_get !== void 0 ? _removedWithLinks_get : false;
|
|
956
|
-
|
|
957
|
-
//
|
|
958
|
-
|
|
959
|
-
large = delta.files.length === 0 || churn > 0.2 * delta.files.length;
|
|
956
|
+
// A cold build is the only case a full pass wins. Measured 2026-09-01 on 6,566 notes, resolve
|
|
957
|
+
// time alone: full is flat near 90ms at any churn, incremental 7ms at 10 files and 30ms at 2,000.
|
|
958
|
+
large = delta.files.length === 0 || delta.added.length === delta.files.length;
|
|
960
959
|
if (!large) return [
|
|
961
960
|
3,
|
|
962
961
|
2
|