@leemour/cli-messaging 0.145.0 → 0.146.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.
@@ -0,0 +1,35 @@
1
+ /** The version of the vendored files in `./snowball/`; `bin/snowball-update` regenerates them. */
2
+ export declare const SNOWBALL_VERSION = "3.1.1";
3
+ export declare const CYRILLIC_STEMMERS: readonly ["russian", "none"];
4
+ export declare const LATIN_STEMMERS: readonly ["spanish", "english", "none"];
5
+ export type CyrillicStemmer = (typeof CYRILLIC_STEMMERS)[number];
6
+ export type LatinStemmer = (typeof LATIN_STEMMERS)[number];
7
+ export type Stemmers = {
8
+ cyrillic: CyrillicStemmer;
9
+ latin: LatinStemmer;
10
+ };
11
+ export declare const DEFAULT_STEMMERS: Stemmers;
12
+ /** Clear-all rather than LRU: the 1M benchmark corpus holds 523k distinct words, and a Map stays cheap below this. */
13
+ export declare const STEM_CACHE_LIMIT = 200000;
14
+ /** Recorded beside an index built with these choices; a different value means the index must be rebuilt. */
15
+ export declare const analyzerIdentity: (stemmers: Stemmers) => string;
16
+ /** Checks choices that come from outside the type system — the store, a config value, an MCP argument. */
17
+ export declare const parseStemmers: (value: unknown) => Stemmers;
18
+ export type Stemmer = {
19
+ readonly stemmers: Stemmers;
20
+ readonly identity: string;
21
+ /** The indexed form of one token: stemmed by the script of its letters, then folded with `normalize()`. */
22
+ stemToken(token: string): string;
23
+ /** `stemToken` over every word of a text, split as `unicode61` splits it; tokens that fold to nothing are dropped. */
24
+ stemTokens(text: string): string[];
25
+ };
26
+ /**
27
+ * One stemmer per fill run or write drain: it owns its cache, so a cache never outlives the choices it was
28
+ * built with. A token is stemmed only when all its letters are of one script and it has no digit: mixed scripts
29
+ * (`Москвa` with a Latin `a`) are usually homoglyph spoofing or code, and `covid19` is a name, not a word form.
30
+ * Ukrainian and other Cyrillic languages go through the Russian stemmer — there is no language detection.
31
+ */
32
+ export declare const createStemmer: (stemmers?: Stemmers, { cacheLimit }?: {
33
+ cacheLimit?: number;
34
+ }) => Stemmer;
35
+ //# sourceMappingURL=stem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stem.d.ts","sourceRoot":"","sources":["../../src/search/stem.ts"],"names":[],"mappings":"AAMA,kGAAkG;AAClG,eAAO,MAAM,gBAAgB,UAAU,CAAA;AAEvC,eAAO,MAAM,iBAAiB,YAAI,SAAS,EAAE,MAAM,CAAU,CAAA;AAC7D,eAAO,MAAM,cAAc,YAAI,SAAS,EAAE,SAAS,EAAE,MAAM,CAAU,CAAA;AACrE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAChE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAC1D,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAA;AAEzE,eAAO,MAAM,gBAAgB,EAAE,QAAoD,CAAA;AAEnF,sHAAsH;AACtH,eAAO,MAAM,gBAAgB,SAAU,CAAA;AAEvC,4GAA4G;AAC5G,eAAO,MAAM,gBAAgB,aAAc,QAAQ,KAAG,MACgC,CAAA;AAEtF,0GAA0G;AAC1G,eAAO,MAAM,aAAa,UAAW,OAAO,KAAG,QAe9C,CAAA;AAeD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,2GAA2G;IAC3G,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAChC,sHAAsH;IACtH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CACnC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,cACd,QAAQ,mBACiB;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KACzD,OA6BF,CAAA"}
@@ -0,0 +1,76 @@
1
+ import { CliError } from "@leemour/cli-core";
2
+ import { normalize } from "../store/normalize.js";
3
+ import EnglishStemmer from "./snowball/english-stemmer.js";
4
+ import RussianStemmer from "./snowball/russian-stemmer.js";
5
+ import SpanishStemmer from "./snowball/spanish-stemmer.js";
6
+ /** The version of the vendored files in `./snowball/`; `bin/snowball-update` regenerates them. */
7
+ export const SNOWBALL_VERSION = "3.1.1";
8
+ export const CYRILLIC_STEMMERS = ["russian", "none"];
9
+ export const LATIN_STEMMERS = ["spanish", "english", "none"];
10
+ export const DEFAULT_STEMMERS = { cyrillic: "russian", latin: "spanish" };
11
+ /** Clear-all rather than LRU: the 1M benchmark corpus holds 523k distinct words, and a Map stays cheap below this. */
12
+ export const STEM_CACHE_LIMIT = 200_000;
13
+ /** Recorded beside an index built with these choices; a different value means the index must be rebuilt. */
14
+ export const analyzerIdentity = (stemmers) => `snowball-${SNOWBALL_VERSION} cyrillic=${stemmers.cyrillic} latin=${stemmers.latin}`;
15
+ /** Checks choices that come from outside the type system — the store, a config value, an MCP argument. */
16
+ export const parseStemmers = (value) => {
17
+ const record = (typeof value === "object" && value !== null ? value : {});
18
+ const pick = (script, allowed, fallback) => {
19
+ const choice = record[script] ?? fallback;
20
+ if (allowed.includes(choice))
21
+ return choice;
22
+ throw new CliError("validation_error", `${script} words cannot be stemmed with ${JSON.stringify(choice)} — choose ${allowed.join(", ")}`, { reason: "invalid_stemmer", script, allowed: [...allowed] });
23
+ };
24
+ return {
25
+ cyrillic: pick("cyrillic", CYRILLIC_STEMMERS, DEFAULT_STEMMERS.cyrillic),
26
+ latin: pick("latin", LATIN_STEMMERS, DEFAULT_STEMMERS.latin),
27
+ };
28
+ };
29
+ /** What FTS5 `unicode61` keeps inside a token: letters, digits, private use, and combining marks. */
30
+ const TOKEN = /[\p{L}\p{N}\p{Co}\p{M}]+/gu;
31
+ const MARKS = /\p{M}+/gu;
32
+ const CYRILLIC = /^\p{Script=Cyrillic}+$/u;
33
+ const LATIN = /^\p{Script=Latin}+$/u;
34
+ const snowball = {
35
+ russian: () => new RussianStemmer(),
36
+ spanish: () => new SpanishStemmer(),
37
+ english: () => new EnglishStemmer(),
38
+ none: () => null,
39
+ };
40
+ /**
41
+ * One stemmer per fill run or write drain: it owns its cache, so a cache never outlives the choices it was
42
+ * built with. A token is stemmed only when all its letters are of one script and it has no digit: mixed scripts
43
+ * (`Москвa` with a Latin `a`) are usually homoglyph spoofing or code, and `covid19` is a name, not a word form.
44
+ * Ukrainian and other Cyrillic languages go through the Russian stemmer — there is no language detection.
45
+ */
46
+ export const createStemmer = (stemmers = DEFAULT_STEMMERS, { cacheLimit = STEM_CACHE_LIMIT } = {}) => {
47
+ const valid = parseStemmers(stemmers);
48
+ const cyrillic = snowball[valid.cyrillic]();
49
+ const latin = snowball[valid.latin]();
50
+ const cache = new Map();
51
+ const compute = (token) => {
52
+ // Stress marks survive NFC (кварти́ру) and would hide the suffix from Snowball; ё and й compose and stay.
53
+ const word = token.normalize("NFC").toLowerCase().replace(MARKS, "");
54
+ const engine = CYRILLIC.test(word) ? cyrillic : LATIN.test(word) ? latin : null;
55
+ const stem = engine?.stemWord(word) || word;
56
+ return normalize(stem);
57
+ };
58
+ const stemToken = (token) => {
59
+ const cached = cache.get(token);
60
+ if (cached !== undefined)
61
+ return cached;
62
+ const stem = compute(token);
63
+ if (cache.size >= cacheLimit)
64
+ cache.clear();
65
+ if (cacheLimit > 0)
66
+ cache.set(token, stem);
67
+ return stem;
68
+ };
69
+ return {
70
+ stemmers: valid,
71
+ identity: analyzerIdentity(valid),
72
+ stemToken,
73
+ stemTokens: (text) => (text.normalize("NFC").toLowerCase().match(TOKEN) ?? []).map(stemToken).filter(Boolean),
74
+ };
75
+ };
76
+ //# sourceMappingURL=stem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stem.js","sourceRoot":"","sources":["../../src/search/stem.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leemour/cli-messaging",
3
- "version": "0.145.0",
3
+ "version": "0.146.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "MIT",
6
6
  "author": "Viacheslav Ptsarev",
@@ -65,7 +65,7 @@
65
65
  "./parity.json": "./parity.json"
66
66
  },
67
67
  "scripts": {
68
- "build": "tsc --build && node scripts/bundle-drizzle.ts",
68
+ "build": "tsc --build && node scripts/bundle-drizzle.ts && node scripts/copy-snowball.ts",
69
69
  "check:dist": "node scripts/check-dist.ts",
70
70
  "typecheck": "tsc --build --force --emitDeclarationOnly && tsc -p tsconfig.test.json && tsc -p tsconfig.scripts.json",
71
71
  "lint": "biome check .",
package/parity.json CHANGED
@@ -197,6 +197,9 @@
197
197
  "--html": {
198
198
  "meaning": "the text is HTML: <b>, <i>, <a href>, <code>"
199
199
  },
200
+ "--http": {
201
+ "meaning": "serve MCP over HTTP on 127.0.0.1 behind the owner's tunnel, with a one-owner login; every write asks first"
202
+ },
200
203
  "--idle": {
201
204
  "value": "<duration>",
202
205
  "meaning": "stop after this long with nobody using it — 15m, 1h"
@@ -373,10 +376,18 @@
373
376
  "value": "<file>",
374
377
  "meaning": "an image file — a profile photo in `account update`, a photo to send in `messages send`"
375
378
  },
379
+ "--port": {
380
+ "value": "<port>",
381
+ "meaning": "the local port for --http"
382
+ },
376
383
  "--provider": {
377
384
  "value": "<provider>",
378
385
  "meaning": "embed through a service with your key instead of on this machine: openai"
379
386
  },
387
+ "--public-url": {
388
+ "value": "<url>",
389
+ "meaning": "the tunnel's https address the browser apps use"
390
+ },
380
391
  "--qr-file": {
381
392
  "value": "<png>",
382
393
  "meaning": "write the QR code to this PNG instead of drawing it, for an agent to pass on"
@@ -407,6 +418,9 @@
407
418
  "--retract": {
408
419
  "meaning": "take your vote back, where the poll allows it"
409
420
  },
421
+ "--revoke": {
422
+ "meaning": "forget every login given to a browser app over --http"
423
+ },
410
424
  "--revote": {
411
425
  "meaning": "people may change their vote"
412
426
  },
@@ -1556,6 +1570,34 @@
1556
1570
  },
1557
1571
  "--allow-send": "all",
1558
1572
  "--confirm-send": "all",
1573
+ "--http": {
1574
+ "in": [],
1575
+ "planned": {
1576
+ "max": "CLI-58",
1577
+ "tg": "tg's next cli-messaging bump"
1578
+ }
1579
+ },
1580
+ "--port": {
1581
+ "in": [],
1582
+ "planned": {
1583
+ "max": "CLI-58",
1584
+ "tg": "tg's next cli-messaging bump"
1585
+ }
1586
+ },
1587
+ "--public-url": {
1588
+ "in": [],
1589
+ "planned": {
1590
+ "max": "CLI-58",
1591
+ "tg": "tg's next cli-messaging bump"
1592
+ }
1593
+ },
1594
+ "--revoke": {
1595
+ "in": [],
1596
+ "planned": {
1597
+ "max": "CLI-58",
1598
+ "tg": "tg's next cli-messaging bump"
1599
+ }
1600
+ },
1559
1601
  "--yes": {
1560
1602
  "in": [],
1561
1603
  "planned": {