@intentic/base 1.303.0 → 1.305.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # @intentic/base
2
2
 
3
- The runtime primitives every tier shares: the `when` condition language, disposal, the async schedulers, and
4
- the outside-text neutralizer.
3
+ The runtime primitives every tier shares: the `when` condition language, disposal, the async schedulers, the
4
+ outside-text neutralizer, the fuzzy path scorer, and the SQLite driver seam.
5
5
 
6
6
  Almost nothing in here knows what this product is. That is the point: each module replaced a decision
7
7
  that had been made independently, and differently, in the daemon and in the web app, where the copies could
@@ -25,6 +25,12 @@ and a package that offers them as one thing invites being treated as a junk draw
25
25
  reserved tokens are folded (homoglyphs, zero-width characters) and replaced before content is sealed or
26
26
  written to disk. Shared because the daemon's seams, webq's saved pages and fileq's derived sidecars must all
27
27
  neutralize identically — a drifted copy is a working forgery.
28
+ - **`fuzzy`**: the fzf-style path scorer and the ranking order built on it. Both ends of quick-open answer with
29
+ it — the sandbox's iq `files` engine and the app's own search box — and they used to answer with two copies of
30
+ it, kept identical by hand, where the same keystrokes could have put a different file first on either side.
31
+ - **`sqlite`**: the narrow seam a `node:sqlite` store is written against — the five-method driver interface, the
32
+ BEGIN/COMMIT/ROLLBACK transaction the driver has no helper for, and the schema-version guard that treats a
33
+ mismatch as cache loss. iq's index and iq's session recall are written against this one, not against two.
28
34
  - **`async`**: the four shapes of "don't do that again yet", named so the choice between them is visible:
29
35
  `Delayer` restarts its clock on every call, `Coalescer` opens a window on the first call and lets later ones
30
36
  join it, `SingleFlight` shares one run per key among concurrent callers, and `retry` is the loop with the
@@ -60,6 +66,8 @@ when nobody needs it any more.
60
66
  - [src/when.ts](src/when.ts): the grammar, the parser, and what a condition means against a context.
61
67
  - [src/lifecycle.ts](src/lifecycle.ts): `DisposableStore` and the two things built on it.
62
68
  - [src/async.ts](src/async.ts): the schedulers, each with the case that made it a separate name.
69
+ - [src/fuzzy.ts](src/fuzzy.ts): the path scorer, with its substring/subsequence split and why the substring
70
+ branch is deliberately uncapped.
63
71
  - [src/when.test.ts](src/when.test.ts), the evaluation rules that are decisions rather than syntax: an absent
64
72
  key is false, ordering refuses anything but numbers, comparison crosses the type boundary by string form.
65
73
  - [src/async.test.ts](src/async.test.ts): the Delayer/Coalescer distinction pinned as behaviour.
@@ -0,0 +1,6 @@
1
+ export declare const fuzzyScore: (needle: string, path: string) => number | undefined;
2
+ export declare const rankByFuzzy: (needle: string, paths: Iterable<string>) => {
3
+ readonly path: string;
4
+ readonly score: number;
5
+ }[];
6
+ //# sourceMappingURL=fuzzy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.d.ts","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,UAAU,WAAY,MAAM,QAAQ,MAAM,KAAG,MAAM,GAAG,SAalE,CAAC;AAMF,eAAO,MAAM,WAAW,WAAY,MAAM,SAAS,QAAQ,CAAC,MAAM,CAAC,KAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAStH,CAAC"}
package/dist/fuzzy.js ADDED
@@ -0,0 +1,43 @@
1
+ const BOUNDARY = new Set(["/", ".", "_", "-"]);
2
+ const substringScore = (haystack, at) => 0.75 + (at >= haystack.lastIndexOf("/") + 1 ? 0.2 : 0) + 5 / haystack.length;
3
+ const subsequenceScore = (needle, haystack, path) => {
4
+ let score = 0;
5
+ let hi = 0;
6
+ let previousHit = -2;
7
+ for (let ni = 0; ni < needle.length; ni++) {
8
+ const ch = needle[ni];
9
+ const found = haystack.indexOf(ch, hi);
10
+ if (found === -1) {
11
+ return undefined;
12
+ }
13
+ const boundary = found === 0 || BOUNDARY.has(haystack[found - 1]) || (path[found] !== undefined && path[found] >= "A" && path[found] <= "Z");
14
+ score += 1 + (found === previousHit + 1 ? 0.8 : 0) + (boundary ? 0.6 : 0);
15
+ previousHit = found;
16
+ hi = found + 1;
17
+ }
18
+ return score;
19
+ };
20
+ export const fuzzyScore = (needle, path) => {
21
+ const n = needle.toLowerCase();
22
+ const h = path.toLowerCase();
23
+ if (n.length === 0 || n.length > h.length) {
24
+ return undefined;
25
+ }
26
+ const at = h.indexOf(n);
27
+ if (at !== -1) {
28
+ return substringScore(h, at);
29
+ }
30
+ const raw = subsequenceScore(n, h, path);
31
+ return raw === undefined ? undefined : (raw / (n.length * 2.4)) * 0.7 * Math.min(1, 20 / Math.max(20, h.length - n.length));
32
+ };
33
+ export const rankByFuzzy = (needle, paths) => {
34
+ const scored = [];
35
+ for (const path of paths) {
36
+ const score = fuzzyScore(needle, path);
37
+ if (score !== undefined) {
38
+ scored.push({ path, score });
39
+ }
40
+ }
41
+ return scored.toSorted((a, b) => b.score - a.score || (a.path < b.path ? -1 : 1));
42
+ };
43
+ //# sourceMappingURL=fuzzy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.js","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ export type SqliteValue = string | number | bigint | Uint8Array | null;
3
+ export type Row = Record<string, SqliteValue>;
4
+ export interface SqliteDb {
5
+ all(sql: string, ...params: SqliteValue[]): Row[];
6
+ get(sql: string, ...params: SqliteValue[]): Row | undefined;
7
+ run(sql: string, ...params: SqliteValue[]): void;
8
+ transaction(fn: () => void): void;
9
+ close(): void;
10
+ }
11
+ export declare const wrapDb: (db: DatabaseSync) => SqliteDb;
12
+ export declare const guardSchemaVersion: (db: SqliteDb, version: string, label: string) => void;
13
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;AACvE,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE9C,MAAM,WAAW,QAAQ;IACrB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,EAAE,CAAC;IAClD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,GAAG,SAAS,CAAC;IAC5D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACjD,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAClC,KAAK,IAAI,IAAI,CAAC;CACjB;AAMD,eAAO,MAAM,MAAM,OAAQ,YAAY,KAAG,QAiBxC,CAAC;AAMH,eAAO,MAAM,kBAAkB,OAAQ,QAAQ,WAAW,MAAM,SAAS,MAAM,KAAG,IAUjF,CAAC"}
package/dist/sqlite.js ADDED
@@ -0,0 +1,31 @@
1
+ export const wrapDb = (db) => ({
2
+ all: (sql, ...params) => db.prepare(sql).all(...params),
3
+ get: (sql, ...params) => db.prepare(sql).get(...params),
4
+ run: (sql, ...params) => {
5
+ db.prepare(sql).run(...params);
6
+ },
7
+ transaction: (fn) => {
8
+ db.exec("BEGIN");
9
+ try {
10
+ fn();
11
+ db.exec("COMMIT");
12
+ }
13
+ catch (error) {
14
+ db.exec("ROLLBACK");
15
+ throw error;
16
+ }
17
+ },
18
+ close: () => db.close(),
19
+ });
20
+ export const guardSchemaVersion = (db, version, label) => {
21
+ const found = db.get("SELECT value FROM meta WHERE key = 'schema_version'")?.["value"];
22
+ if (found === undefined) {
23
+ db.run("INSERT INTO meta (key, value) VALUES ('schema_version', ?)", version);
24
+ return;
25
+ }
26
+ if (found !== version) {
27
+ db.close();
28
+ throw new Error(`${label} schema ${String(found)} != ${version}`);
29
+ }
30
+ };
31
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EAAgB,EAAY,EAAE,CAAC,CAAC;IACnD,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAU;IAChE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAoB;IAC1E,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,EAAE;QACpB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE;QAChB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjB,IAAI,CAAC;YACD,EAAE,EAAE,CAAC;YACL,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACpB,MAAM,KAAK,CAAC;QAChB,CAAC;IACL,CAAC;IACD,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE;CAC1B,CAAC,CAAC;AAMH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAY,EAAE,OAAe,EAAE,KAAa,EAAQ,EAAE;IACrF,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,qDAAqD,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;IACvF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,EAAE,CAAC,GAAG,CAAC,4DAA4D,EAAE,OAAO,CAAC,CAAC;QAC9E,OAAO;IACX,CAAC;IACD,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACpB,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,MAAM,CAAC,KAAK,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;AACL,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/base",
3
- "version": "1.303.0",
3
+ "version": "1.305.0",
4
4
  "description": "Runtime primitives every tier shares, when-expressions, disposal, and the async schedulers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -83,6 +83,28 @@
83
83
  "default": "./dist/format.js"
84
84
  }
85
85
  },
86
+ "./fuzzy": {
87
+ "types": "./dist/fuzzy.d.ts",
88
+ "import": {
89
+ "@intentic/src": "./src/fuzzy.ts",
90
+ "default": "./dist/fuzzy.js"
91
+ },
92
+ "require": {
93
+ "@intentic/src": "./src/fuzzy.ts",
94
+ "default": "./dist/fuzzy.js"
95
+ }
96
+ },
97
+ "./sqlite": {
98
+ "types": "./dist/sqlite.d.ts",
99
+ "import": {
100
+ "@intentic/src": "./src/sqlite.ts",
101
+ "default": "./dist/sqlite.js"
102
+ },
103
+ "require": {
104
+ "@intentic/src": "./src/sqlite.ts",
105
+ "default": "./dist/sqlite.js"
106
+ }
107
+ },
86
108
  "./plain-text": {
87
109
  "types": "./dist/plain-text.d.ts",
88
110
  "import": {
@@ -101,15 +123,16 @@
101
123
  "devDependencies": {
102
124
  "@intentic/testing": "0.0.0",
103
125
  "@intentic/tsconfig": "0.0.0",
126
+ "@types/bun": "1.4.0",
104
127
  "@types/node": "24.13.2",
105
128
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
106
- "vitest": "4.1.10"
129
+ "fast-check": "4.9.0"
107
130
  },
108
131
  "scripts": {
109
132
  "build": "tsgo",
110
133
  "typecheck": "tsgo --noEmit -p tsconfig.test.json",
111
134
  "watch": "tsgo --build --watch",
112
- "test": "vitest run",
113
- "test:watch": "vitest"
135
+ "test": "suites",
136
+ "test:watch": "suites --watch"
114
137
  }
115
138
  }