Skip to content

Commit 16a0417

Browse files
committed
chore(vendor): stamp glyph-s 2.7.1 VERSION.json and profiles
Align miO vendor tree with glyph-s npm run vendor:sync output.
1 parent 6fa722b commit 16a0417

4 files changed

Lines changed: 211 additions & 18 deletions

File tree

vendor/VERSION.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "glyph-s",
3+
"version": "2.7.1",
4+
"stampedAt": "2026-07-19T00:50:16.057Z",
5+
"files": [
6+
"engine.js",
7+
"engine.cjs",
8+
"ollama.js",
9+
"ollama.cjs",
10+
"profiles.json"
11+
]
12+
}

vendor/engine.cjs

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* Query tokenization and extended search grammar.
3+
* @module tokenize
4+
*/
5+
6+
/**
7+
* Split a query into lowercase tokens on whitespace / punctuation.
8+
* @param {string} q
9+
* @returns {string[]}
10+
*/
111
function tokenizeQuery(q) {
212
return String(q || '')
313
.trim()
@@ -6,6 +16,12 @@ function tokenizeQuery(q) {
616
.filter(Boolean);
717
}
818

19+
/**
20+
* Parse extended query grammar into tokens + structured filters.
21+
* Supports phrases, exclusions, OR groups, and type/page/app/path/tag filters.
22+
* @param {string} raw
23+
* @returns {import('./types.js').ParsedSearchQuery}
24+
*/
925
function parseSearchQuery(raw) {
1026
const text = String(raw || '').trim();
1127
const filters = {
@@ -191,16 +207,45 @@ function expandQueryVariants(rawQ, settings = {}) {
191207
return Array.from(set);
192208
}
193209

210+
/**
211+
* Search quality/speed profiles for glyph-s.
212+
* Data lives in profiles.json; this module re-exports for ESM and CJS bundling.
213+
* @module profiles
214+
*/
194215

195-
196-
197-
const CAT_PRIORITY = { page: 40, note: 36, app: 32, release: 30, action: 24, news: 20 };
198-
const SEARCH_SETTINGS = { fuzzyLayout: true, fuzzyTransliteration: true };
216+
/** @type {Record<string, import('./types.js').SearchProfileConfig>} */
199217
const PROFILE_SETTINGS = {
200218
legacy: { fuzzyCutoff: 0.4, scoreScale: 1, maxCandidates: 8000 },
201219
balanced: { fuzzyCutoff: 0.48, scoreScale: 1.08, maxCandidates: 4000 },
202220
'max-quality': { fuzzyCutoff: 0.35, scoreScale: 1.16, maxCandidates: 9000 },
203221
};
222+
223+
/**
224+
* Resolve a profile name to its config (falls back to `legacy`).
225+
* @param {string} [profile]
226+
* @returns {import('./types.js').SearchProfileConfig}
227+
*/
228+
function getProfileConfig(profile) {
229+
const key = String(profile || 'legacy').toLowerCase();
230+
return PROFILE_SETTINGS[key] || PROFILE_SETTINGS.legacy;
231+
}
232+
233+
/** Stable list of known profile ids. */
234+
const PROFILE_IDS = Object.freeze(['legacy', 'balanced', 'max-quality']);
235+
236+
/**
237+
* Glyph Search core: ranking, snippets, index + engine factory.
238+
* @module engine
239+
*/
240+
241+
242+
243+
244+
245+
/** @type {Record<string, number>} */
246+
const CAT_PRIORITY = { page: 40, note: 36, app: 32, release: 30, action: 24, news: 20 };
247+
/** @type {import('./types.js').SearchSettings} */
248+
const SEARCH_SETTINGS = { fuzzyLayout: true, fuzzyTransliteration: true };
204249
const TOKEN_VARIANT_CACHE = new Map();
205250
const SNIPPET_CACHE = new Map();
206251

@@ -231,11 +276,6 @@ function tokenHitsText(tok, text, settings) {
231276
return null;
232277
}
233278

234-
function getProfileConfig(profile) {
235-
const key = String(profile || 'legacy').toLowerCase();
236-
return PROFILE_SETTINGS[key] || PROFILE_SETTINGS.legacy;
237-
}
238-
239279
function getTokenVariantsCached(tok, settings) {
240280
const profile = String((settings && settings.profile) || 'legacy');
241281
const cacheKey = `${profile}|${String(tok || '').toLowerCase()}|${settings?.fuzzyLayout !== false}|${settings?.fuzzyTransliteration !== false}`;
@@ -246,6 +286,11 @@ function getTokenVariantsCached(tok, settings) {
246286
return variants;
247287
}
248288

289+
/**
290+
* @param {import('./types.js').SearchItem} it
291+
* @param {import('./types.js').ParsedSearchQuery|null|undefined} filters
292+
* @returns {boolean}
293+
*/
249294
function matchesSearchFilters(it, filters) {
250295
if (!filters) return true;
251296
if (filters.type === 'release' && it.cat !== 'release') return false;
@@ -274,6 +319,14 @@ function matchesSearchFilters(it, filters) {
274319
return true;
275320
}
276321

322+
/**
323+
* Score one item against query tokens / filters.
324+
* @param {import('./types.js').SearchItem} it
325+
* @param {string[]} tokens
326+
* @param {import('./types.js').ParsedSearchQuery|null|undefined} filters
327+
* @param {import('./types.js').SearchSettings} [settings]
328+
* @returns {number}
329+
*/
277330
function scoreSearchItem(it, tokens, filters, settings = SEARCH_SETTINGS) {
278331
if (filters && !matchesSearchFilters(it, filters)) return 0;
279332
const title = it.title().toLowerCase();
@@ -371,6 +424,14 @@ function findSnippetInBlob(blob, tok, settings) {
371424
return null;
372425
}
373426

427+
/**
428+
* Build a short HTML-friendly snippet for the first matching token.
429+
* @param {import('./types.js').SearchItem} it
430+
* @param {string[]} tokens
431+
* @param {(s: string) => string} [esc]
432+
* @param {import('./types.js').SearchSettings} [settings]
433+
* @returns {string}
434+
*/
374435
function snippetForItem(it, tokens, esc = (s) => s, settings = SEARCH_SETTINGS) {
375436
if (!tokens.length) return '';
376437
const body = typeof it.body === 'function' ? it.body() : it.body || '';
@@ -441,6 +502,13 @@ function collectTopK(scored, limit) {
441502
return top.sort((a, b) => b.score - a.score);
442503
}
443504

505+
/**
506+
* Rank corpus items for a query string.
507+
* @param {import('./types.js').SearchItem[]} items
508+
* @param {string} q
509+
* @param {import('./types.js').RankSearchOptions} [opts]
510+
* @returns {import('./types.js').RankedHit[]}
511+
*/
444512
function rankSearchItems(items, q, opts = {}) {
445513
const settings = { ...SEARCH_SETTINGS, ...(opts.settings || {}) };
446514
settings.profile = settings.profile || opts.profile || 'legacy';
@@ -479,6 +547,12 @@ function rankSearchItems(items, q, opts = {}) {
479547
return out;
480548
}
481549

550+
/**
551+
* Pre-compute text bags for repeated searches.
552+
* @param {import('./types.js').SearchItem[]} [items]
553+
* @param {import('./types.js').BuildIndexOptions} [opts]
554+
* @returns {import('./types.js').SearchIndex}
555+
*/
482556
function buildIndex(items = [], opts = {}) {
483557
const profile = opts.profile || 'legacy';
484558
const index = items.map((it, idx) => ({
@@ -490,6 +564,11 @@ function buildIndex(items = [], opts = {}) {
490564
return { items: index, profile, createdAt: Date.now() };
491565
}
492566

567+
/**
568+
* Create a reusable search engine bound to an index / items.
569+
* @param {import('./types.js').CreateSearchEngineOptions} [options]
570+
* @returns {import('./types.js').SearchEngine}
571+
*/
493572
function createSearchEngine(options = {}) {
494573
const profile = options.profile || 'balanced';
495574
const settings = { ...SEARCH_SETTINGS, ...(options.settings || {}), profile };
@@ -518,6 +597,9 @@ module.exports = {
518597
parseSearchQuery,
519598
expandTokenVariants,
520599
expandQueryVariants,
600+
getProfileConfig,
601+
PROFILE_SETTINGS,
602+
PROFILE_IDS,
521603
matchesSearchFilters,
522604
scoreSearchItem,
523605
snippetForItem,

vendor/engine.js

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* Query tokenization and extended search grammar.
3+
* @module tokenize
4+
*/
5+
6+
/**
7+
* Split a query into lowercase tokens on whitespace / punctuation.
8+
* @param {string} q
9+
* @returns {string[]}
10+
*/
111
function tokenizeQuery(q) {
212
return String(q || '')
313
.trim()
@@ -6,6 +16,12 @@ function tokenizeQuery(q) {
616
.filter(Boolean);
717
}
818

19+
/**
20+
* Parse extended query grammar into tokens + structured filters.
21+
* Supports phrases, exclusions, OR groups, and type/page/app/path/tag filters.
22+
* @param {string} raw
23+
* @returns {import('./types.js').ParsedSearchQuery}
24+
*/
925
function parseSearchQuery(raw) {
1026
const text = String(raw || '').trim();
1127
const filters = {
@@ -191,16 +207,45 @@ function expandQueryVariants(rawQ, settings = {}) {
191207
return Array.from(set);
192208
}
193209

210+
/**
211+
* Search quality/speed profiles for glyph-s.
212+
* Data lives in profiles.json; this module re-exports for ESM and CJS bundling.
213+
* @module profiles
214+
*/
194215

195-
196-
197-
const CAT_PRIORITY = { page: 40, note: 36, app: 32, release: 30, action: 24, news: 20 };
198-
const SEARCH_SETTINGS = { fuzzyLayout: true, fuzzyTransliteration: true };
216+
/** @type {Record<string, import('./types.js').SearchProfileConfig>} */
199217
const PROFILE_SETTINGS = {
200218
legacy: { fuzzyCutoff: 0.4, scoreScale: 1, maxCandidates: 8000 },
201219
balanced: { fuzzyCutoff: 0.48, scoreScale: 1.08, maxCandidates: 4000 },
202220
'max-quality': { fuzzyCutoff: 0.35, scoreScale: 1.16, maxCandidates: 9000 },
203221
};
222+
223+
/**
224+
* Resolve a profile name to its config (falls back to `legacy`).
225+
* @param {string} [profile]
226+
* @returns {import('./types.js').SearchProfileConfig}
227+
*/
228+
function getProfileConfig(profile) {
229+
const key = String(profile || 'legacy').toLowerCase();
230+
return PROFILE_SETTINGS[key] || PROFILE_SETTINGS.legacy;
231+
}
232+
233+
/** Stable list of known profile ids. */
234+
const PROFILE_IDS = Object.freeze(['legacy', 'balanced', 'max-quality']);
235+
236+
/**
237+
* Glyph Search core: ranking, snippets, index + engine factory.
238+
* @module engine
239+
*/
240+
241+
242+
243+
244+
245+
/** @type {Record<string, number>} */
246+
const CAT_PRIORITY = { page: 40, note: 36, app: 32, release: 30, action: 24, news: 20 };
247+
/** @type {import('./types.js').SearchSettings} */
248+
const SEARCH_SETTINGS = { fuzzyLayout: true, fuzzyTransliteration: true };
204249
const TOKEN_VARIANT_CACHE = new Map();
205250
const SNIPPET_CACHE = new Map();
206251

@@ -231,11 +276,6 @@ function tokenHitsText(tok, text, settings) {
231276
return null;
232277
}
233278

234-
function getProfileConfig(profile) {
235-
const key = String(profile || 'legacy').toLowerCase();
236-
return PROFILE_SETTINGS[key] || PROFILE_SETTINGS.legacy;
237-
}
238-
239279
function getTokenVariantsCached(tok, settings) {
240280
const profile = String((settings && settings.profile) || 'legacy');
241281
const cacheKey = `${profile}|${String(tok || '').toLowerCase()}|${settings?.fuzzyLayout !== false}|${settings?.fuzzyTransliteration !== false}`;
@@ -246,6 +286,11 @@ function getTokenVariantsCached(tok, settings) {
246286
return variants;
247287
}
248288

289+
/**
290+
* @param {import('./types.js').SearchItem} it
291+
* @param {import('./types.js').ParsedSearchQuery|null|undefined} filters
292+
* @returns {boolean}
293+
*/
249294
function matchesSearchFilters(it, filters) {
250295
if (!filters) return true;
251296
if (filters.type === 'release' && it.cat !== 'release') return false;
@@ -274,6 +319,14 @@ function matchesSearchFilters(it, filters) {
274319
return true;
275320
}
276321

322+
/**
323+
* Score one item against query tokens / filters.
324+
* @param {import('./types.js').SearchItem} it
325+
* @param {string[]} tokens
326+
* @param {import('./types.js').ParsedSearchQuery|null|undefined} filters
327+
* @param {import('./types.js').SearchSettings} [settings]
328+
* @returns {number}
329+
*/
277330
function scoreSearchItem(it, tokens, filters, settings = SEARCH_SETTINGS) {
278331
if (filters && !matchesSearchFilters(it, filters)) return 0;
279332
const title = it.title().toLowerCase();
@@ -371,6 +424,14 @@ function findSnippetInBlob(blob, tok, settings) {
371424
return null;
372425
}
373426

427+
/**
428+
* Build a short HTML-friendly snippet for the first matching token.
429+
* @param {import('./types.js').SearchItem} it
430+
* @param {string[]} tokens
431+
* @param {(s: string) => string} [esc]
432+
* @param {import('./types.js').SearchSettings} [settings]
433+
* @returns {string}
434+
*/
374435
function snippetForItem(it, tokens, esc = (s) => s, settings = SEARCH_SETTINGS) {
375436
if (!tokens.length) return '';
376437
const body = typeof it.body === 'function' ? it.body() : it.body || '';
@@ -441,6 +502,13 @@ function collectTopK(scored, limit) {
441502
return top.sort((a, b) => b.score - a.score);
442503
}
443504

505+
/**
506+
* Rank corpus items for a query string.
507+
* @param {import('./types.js').SearchItem[]} items
508+
* @param {string} q
509+
* @param {import('./types.js').RankSearchOptions} [opts]
510+
* @returns {import('./types.js').RankedHit[]}
511+
*/
444512
function rankSearchItems(items, q, opts = {}) {
445513
const settings = { ...SEARCH_SETTINGS, ...(opts.settings || {}) };
446514
settings.profile = settings.profile || opts.profile || 'legacy';
@@ -479,6 +547,12 @@ function rankSearchItems(items, q, opts = {}) {
479547
return out;
480548
}
481549

550+
/**
551+
* Pre-compute text bags for repeated searches.
552+
* @param {import('./types.js').SearchItem[]} [items]
553+
* @param {import('./types.js').BuildIndexOptions} [opts]
554+
* @returns {import('./types.js').SearchIndex}
555+
*/
482556
function buildIndex(items = [], opts = {}) {
483557
const profile = opts.profile || 'legacy';
484558
const index = items.map((it, idx) => ({
@@ -490,6 +564,11 @@ function buildIndex(items = [], opts = {}) {
490564
return { items: index, profile, createdAt: Date.now() };
491565
}
492566

567+
/**
568+
* Create a reusable search engine bound to an index / items.
569+
* @param {import('./types.js').CreateSearchEngineOptions} [options]
570+
* @returns {import('./types.js').SearchEngine}
571+
*/
493572
function createSearchEngine(options = {}) {
494573
const profile = options.profile || 'balanced';
495574
const settings = { ...SEARCH_SETTINGS, ...(options.settings || {}), profile };
@@ -518,6 +597,9 @@ module.exports = {
518597
parseSearchQuery,
519598
expandTokenVariants,
520599
expandQueryVariants,
600+
getProfileConfig,
601+
PROFILE_SETTINGS,
602+
PROFILE_IDS,
521603
matchesSearchFilters,
522604
scoreSearchItem,
523605
snippetForItem,

vendor/profiles.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"legacy": {
3+
"fuzzyCutoff": 0.4,
4+
"scoreScale": 1,
5+
"maxCandidates": 8000
6+
},
7+
"balanced": {
8+
"fuzzyCutoff": 0.48,
9+
"scoreScale": 1.08,
10+
"maxCandidates": 4000
11+
},
12+
"max-quality": {
13+
"fuzzyCutoff": 0.35,
14+
"scoreScale": 1.16,
15+
"maxCandidates": 9000
16+
}
17+
}

0 commit comments

Comments
 (0)