@keel_flow/kb-pipeline 0.2.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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunking/ast.d.ts +8 -0
  3. package/dist/chunking/ast.d.ts.map +1 -0
  4. package/dist/chunking/ast.js +86 -0
  5. package/dist/chunking/ast.js.map +1 -0
  6. package/dist/chunking/contextual-fallback.d.ts +15 -0
  7. package/dist/chunking/contextual-fallback.d.ts.map +1 -0
  8. package/dist/chunking/contextual-fallback.js +33 -0
  9. package/dist/chunking/contextual-fallback.js.map +1 -0
  10. package/dist/chunking/fixed.d.ts +6 -0
  11. package/dist/chunking/fixed.d.ts.map +1 -0
  12. package/dist/chunking/fixed.js +24 -0
  13. package/dist/chunking/fixed.js.map +1 -0
  14. package/dist/chunking/index.d.ts +24 -0
  15. package/dist/chunking/index.d.ts.map +1 -0
  16. package/dist/chunking/index.js +86 -0
  17. package/dist/chunking/index.js.map +1 -0
  18. package/dist/chunking/late.d.ts +11 -0
  19. package/dist/chunking/late.d.ts.map +1 -0
  20. package/dist/chunking/late.js +27 -0
  21. package/dist/chunking/late.js.map +1 -0
  22. package/dist/chunking/recursive.d.ts +7 -0
  23. package/dist/chunking/recursive.d.ts.map +1 -0
  24. package/dist/chunking/recursive.js +87 -0
  25. package/dist/chunking/recursive.js.map +1 -0
  26. package/dist/embedding/index.d.ts +14 -0
  27. package/dist/embedding/index.d.ts.map +1 -0
  28. package/dist/embedding/index.js +33 -0
  29. package/dist/embedding/index.js.map +1 -0
  30. package/dist/embedding/local-minilm.d.ts +8 -0
  31. package/dist/embedding/local-minilm.d.ts.map +1 -0
  32. package/dist/embedding/local-minilm.js +51 -0
  33. package/dist/embedding/local-minilm.js.map +1 -0
  34. package/dist/embedding/openai-text-3-small.d.ts +9 -0
  35. package/dist/embedding/openai-text-3-small.d.ts.map +1 -0
  36. package/dist/embedding/openai-text-3-small.js +51 -0
  37. package/dist/embedding/openai-text-3-small.js.map +1 -0
  38. package/dist/embedding/types.d.ts +8 -0
  39. package/dist/embedding/types.d.ts.map +1 -0
  40. package/dist/embedding/types.js +2 -0
  41. package/dist/embedding/types.js.map +1 -0
  42. package/dist/embedding/voyage-context-3.d.ts +9 -0
  43. package/dist/embedding/voyage-context-3.d.ts.map +1 -0
  44. package/dist/embedding/voyage-context-3.js +55 -0
  45. package/dist/embedding/voyage-context-3.js.map +1 -0
  46. package/dist/index.d.ts +9 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +5 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/pipeline.d.ts +51 -0
  51. package/dist/pipeline.d.ts.map +1 -0
  52. package/dist/pipeline.js +90 -0
  53. package/dist/pipeline.js.map +1 -0
  54. package/dist/retrieval/bm25.d.ts +14 -0
  55. package/dist/retrieval/bm25.d.ts.map +1 -0
  56. package/dist/retrieval/bm25.js +60 -0
  57. package/dist/retrieval/bm25.js.map +1 -0
  58. package/dist/retrieval/dense.d.ts +11 -0
  59. package/dist/retrieval/dense.d.ts.map +1 -0
  60. package/dist/retrieval/dense.js +27 -0
  61. package/dist/retrieval/dense.js.map +1 -0
  62. package/dist/retrieval/index.d.ts +71 -0
  63. package/dist/retrieval/index.d.ts.map +1 -0
  64. package/dist/retrieval/index.js +90 -0
  65. package/dist/retrieval/index.js.map +1 -0
  66. package/dist/retrieval/rerank.d.ts +34 -0
  67. package/dist/retrieval/rerank.d.ts.map +1 -0
  68. package/dist/retrieval/rerank.js +101 -0
  69. package/dist/retrieval/rerank.js.map +1 -0
  70. package/dist/retrieval/rrf.d.ts +17 -0
  71. package/dist/retrieval/rrf.d.ts.map +1 -0
  72. package/dist/retrieval/rrf.js +23 -0
  73. package/dist/retrieval/rrf.js.map +1 -0
  74. package/package.json +47 -0
@@ -0,0 +1,90 @@
1
+ import { denseRank } from "./dense.js";
2
+ import { bm25Rank } from "./bm25.js";
3
+ import { reciprocalRankFusion } from "./rrf.js";
4
+ const RRF_POOL = 50;
5
+ function effectiveScore(chunk) {
6
+ return chunk.rerankScore ?? chunk.rrfScore;
7
+ }
8
+ export async function retrieve(opts) {
9
+ const start = Date.now();
10
+ const k = opts.k ?? 5;
11
+ const rerankTopN = opts.rerankTopN ?? Math.max(k * 4, 20);
12
+ let dense;
13
+ if (opts.precomputedDenseScores) {
14
+ // Database-side ranking (pgvector). Already sorted by the query; cap to
15
+ // the same pool size the in-process path uses so RRF sees equal lists.
16
+ dense = opts.precomputedDenseScores.slice(0, RRF_POOL);
17
+ }
18
+ else if (opts.queryEmbedding) {
19
+ dense = denseRank(opts.queryEmbedding, opts.candidates
20
+ .filter((c) => Array.isArray(c.embedding))
21
+ .map((c) => ({ id: c.id, embedding: c.embedding })), RRF_POOL);
22
+ }
23
+ else {
24
+ throw new Error("retrieve() needs queryEmbedding or precomputedDenseScores");
25
+ }
26
+ const bm25 = bm25Rank(opts.query, opts.candidates.map((c) => ({ id: c.id, content: c.contentForBm25 ?? c.content })), RRF_POOL);
27
+ const fused = reciprocalRankFusion([
28
+ { source: "dense", scores: dense },
29
+ { source: "bm25", scores: bm25 },
30
+ ]);
31
+ const denseById = new Map(dense.map((s) => [s.id, s.score]));
32
+ const bm25ById = new Map(bm25.map((s) => [s.id, s.score]));
33
+ const candById = new Map(opts.candidates.map((c) => [c.id, c]));
34
+ let rerankScores = null;
35
+ let finalIds;
36
+ if (opts.reranker) {
37
+ const top = fused.slice(0, rerankTopN);
38
+ const rerankInput = top
39
+ .map((r) => candById.get(r.id))
40
+ .filter((c) => c !== undefined)
41
+ .map((c) => ({ id: c.id, content: c.content }));
42
+ rerankScores = await opts.reranker.rerank(opts.query, rerankInput);
43
+ finalIds = rerankScores.slice(0, k).map((s) => s.id);
44
+ }
45
+ else {
46
+ finalIds = fused.slice(0, k).map((r) => r.id);
47
+ }
48
+ const rrfById = new Map(fused.map((r) => [r.id, r.rrfScore]));
49
+ const rerankById = new Map(rerankScores?.map((s) => [s.id, s.score]) ?? []);
50
+ const allChunks = finalIds
51
+ .map((id) => {
52
+ const cand = candById.get(id);
53
+ if (!cand)
54
+ return undefined;
55
+ return {
56
+ id,
57
+ content: cand.content,
58
+ rrfScore: rrfById.get(id) ?? 0,
59
+ denseScore: denseById.get(id),
60
+ bm25Score: bm25ById.get(id),
61
+ rerankScore: rerankById.get(id),
62
+ };
63
+ })
64
+ .filter((c) => c !== undefined);
65
+ const chunks = opts.minScore === undefined
66
+ ? allChunks
67
+ : allChunks.filter((c) => effectiveScore(c) >= opts.minScore);
68
+ return {
69
+ chunks,
70
+ trace: {
71
+ denseScores: dense,
72
+ bm25Scores: bm25,
73
+ rrfScores: fused.map((r) => ({ id: r.id, score: r.rrfScore })),
74
+ rerankScores,
75
+ finalIds: chunks.map((c) => c.id),
76
+ latencyMs: Date.now() - start,
77
+ },
78
+ };
79
+ }
80
+ export async function embedQuery(embedder, query) {
81
+ const [vec] = await embedder.embed([query], "query");
82
+ if (!vec)
83
+ throw new Error("embedder returned no vector for query");
84
+ return vec;
85
+ }
86
+ export { denseRank, cosineSim } from "./dense.js";
87
+ export { bm25Rank } from "./bm25.js";
88
+ export { reciprocalRankFusion } from "./rrf.js";
89
+ export { createVoyageReranker, createCrossEncoderReranker, createDefaultReranker, shouldRerank, } from "./rerank.js";
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface RerankCandidate {
2
+ id: string;
3
+ content: string;
4
+ }
5
+ export interface RerankScore {
6
+ id: string;
7
+ score: number;
8
+ }
9
+ export interface Reranker {
10
+ modelId: string;
11
+ rerank(query: string, candidates: RerankCandidate[]): Promise<RerankScore[]>;
12
+ }
13
+ export interface VoyageRerankOpts {
14
+ apiKey?: string;
15
+ endpoint?: string;
16
+ model?: string;
17
+ fetchFn?: typeof fetch;
18
+ }
19
+ export declare function createVoyageReranker(opts?: VoyageRerankOpts): Reranker;
20
+ export interface CrossEncoderOpts {
21
+ pipelineFactory?: () => Promise<(input: {
22
+ text: string;
23
+ text_pair: string;
24
+ }, opts: object) => Promise<{
25
+ data: Float32Array;
26
+ } | Array<{
27
+ score: number;
28
+ label: string;
29
+ }>>>;
30
+ }
31
+ export declare function createCrossEncoderReranker(opts?: CrossEncoderOpts): Reranker;
32
+ export declare function shouldRerank(env?: NodeJS.ProcessEnv): boolean;
33
+ export declare function createDefaultReranker(env?: NodeJS.ProcessEnv): Reranker;
34
+ //# sourceMappingURL=rerank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rerank.d.ts","sourceRoot":"","sources":["../../src/retrieval/rerank.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAID,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,gBAAqB,GAAG,QAAQ,CA4C1E;AAID,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,EAAE,MAAM,OAAO,CAC7B,CACE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAC1C,IAAI,EAAE,MAAM,KACT,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,CAAA;KAAE,GAAG,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAC/E,CAAC;CACH;AAOD,wBAAgB,0BAA0B,CAAC,IAAI,GAAE,gBAAqB,GAAG,QAAQ,CAiDhF;AAED,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE1E;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,QAAQ,CAMpF"}
@@ -0,0 +1,101 @@
1
+ const VOYAGE_RERANK_ENDPOINT = "https://api.voyageai.com/v1/rerank";
2
+ export function createVoyageReranker(opts = {}) {
3
+ const apiKey = opts.apiKey ?? process.env["VOYAGE_RERANK_API_KEY"] ?? process.env["VOYAGE_API_KEY"];
4
+ if (!apiKey) {
5
+ throw new Error("VOYAGE_RERANK_API_KEY or VOYAGE_API_KEY is required for voyage-rerank-2.5");
6
+ }
7
+ const model = opts.model ?? "voyage-rerank-2.5";
8
+ const endpoint = opts.endpoint ?? VOYAGE_RERANK_ENDPOINT;
9
+ const fetchFn = opts.fetchFn ?? fetch;
10
+ return {
11
+ modelId: model,
12
+ async rerank(query, candidates) {
13
+ if (candidates.length === 0)
14
+ return [];
15
+ const res = await fetchFn(endpoint, {
16
+ method: "POST",
17
+ headers: {
18
+ "Authorization": `Bearer ${apiKey}`,
19
+ "Content-Type": "application/json",
20
+ },
21
+ body: JSON.stringify({
22
+ model,
23
+ query,
24
+ documents: candidates.map((c) => c.content),
25
+ }),
26
+ });
27
+ if (!res.ok) {
28
+ const body = await res.text().catch(() => "");
29
+ throw new Error(`voyage rerank failed: ${res.status} ${body}`);
30
+ }
31
+ const json = (await res.json());
32
+ const out = [];
33
+ for (const row of json.data ?? []) {
34
+ const cand = candidates[row.index ?? -1];
35
+ if (!cand)
36
+ continue;
37
+ out.push({ id: cand.id, score: row.relevance_score ?? 0 });
38
+ }
39
+ return out.sort((a, b) => b.score - a.score);
40
+ },
41
+ };
42
+ }
43
+ export function createCrossEncoderReranker(opts = {}) {
44
+ let pipelinePromise = null;
45
+ async function getPipeline() {
46
+ if (pipelinePromise)
47
+ return pipelinePromise;
48
+ pipelinePromise = (async () => {
49
+ if (opts.pipelineFactory)
50
+ return opts.pipelineFactory();
51
+ let rawMod;
52
+ try {
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic import of the optional @huggingface/transformers peer; the `as {...}` assertion below pins the used shape
54
+ rawMod = await import("@huggingface/transformers");
55
+ }
56
+ catch (cause) {
57
+ throw new Error("The cross-encoder reranker requires @huggingface/transformers, which is an optional peer dependency of @keel_flow/kb-pipeline. " +
58
+ "Install it with: pnpm add @huggingface/transformers — " +
59
+ "or set VOYAGE_RERANK_API_KEY / VOYAGE_API_KEY to use the Voyage reranker instead.", { cause });
60
+ }
61
+ const mod = rawMod;
62
+ return mod.pipeline("text-classification", "Xenova/ms-marco-MiniLM-L-6-v2", { revision: "main" });
63
+ })();
64
+ pipelinePromise.catch(() => {
65
+ pipelinePromise = null;
66
+ });
67
+ return pipelinePromise;
68
+ }
69
+ return {
70
+ modelId: "Xenova/ms-marco-MiniLM-L-6-v2",
71
+ async rerank(query, candidates) {
72
+ if (candidates.length === 0)
73
+ return [];
74
+ const pipeline = await getPipeline();
75
+ const out = [];
76
+ for (const cand of candidates) {
77
+ const r = await pipeline({ text: query, text_pair: cand.content }, { topk: 1 });
78
+ let score = 0;
79
+ if (Array.isArray(r)) {
80
+ score = r[0]?.score ?? 0;
81
+ }
82
+ else if (r && "data" in r) {
83
+ score = r.data[0] ?? 0;
84
+ }
85
+ out.push({ id: cand.id, score });
86
+ }
87
+ return out.sort((a, b) => b.score - a.score);
88
+ },
89
+ };
90
+ }
91
+ export function shouldRerank(env = process.env) {
92
+ return env["KEEL_KB_RERANK"] === "true";
93
+ }
94
+ export function createDefaultReranker(env = process.env) {
95
+ const voyageKey = env["VOYAGE_RERANK_API_KEY"] ?? env["VOYAGE_API_KEY"];
96
+ if (voyageKey) {
97
+ return createVoyageReranker({ apiKey: voyageKey });
98
+ }
99
+ return createCrossEncoderReranker();
100
+ }
101
+ //# sourceMappingURL=rerank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/retrieval/rerank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface RankedList {
2
+ source: string;
3
+ scores: Array<{
4
+ id: string;
5
+ score: number;
6
+ }>;
7
+ }
8
+ export interface RrfResult {
9
+ id: string;
10
+ rrfScore: number;
11
+ sources: Record<string, number>;
12
+ }
13
+ export interface RrfOpts {
14
+ k?: number;
15
+ }
16
+ export declare function reciprocalRankFusion(lists: RankedList[], opts?: RrfOpts): RrfResult[];
17
+ //# sourceMappingURL=rrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rrf.d.ts","sourceRoot":"","sources":["../../src/retrieval/rrf.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,OAAO;IACtB,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAID,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,GAAE,OAAY,GACjB,SAAS,EAAE,CAkBb"}
@@ -0,0 +1,23 @@
1
+ // Reciprocal Rank Fusion — combines arbitrarily many ranked lists by summing
2
+ // 1 / (k + rank). The default k=60 matches the literature.
3
+ export function reciprocalRankFusion(lists, opts = {}) {
4
+ const k = opts.k ?? 60;
5
+ const fused = new Map();
6
+ for (const list of lists) {
7
+ for (let rank = 0; rank < list.scores.length; rank++) {
8
+ const entry = list.scores[rank];
9
+ if (!entry)
10
+ continue;
11
+ const existing = fused.get(entry.id) ?? {
12
+ id: entry.id,
13
+ rrfScore: 0,
14
+ sources: {},
15
+ };
16
+ existing.rrfScore += 1 / (k + rank + 1);
17
+ existing.sources[list.source] = entry.score;
18
+ fused.set(entry.id, existing);
19
+ }
20
+ }
21
+ return Array.from(fused.values()).sort((a, b) => b.rrfScore - a.rrfScore);
22
+ }
23
+ //# sourceMappingURL=rrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rrf.js","sourceRoot":"","sources":["../../src/retrieval/rrf.ts"],"names":[],"mappings":"AAeA,6EAA6E;AAC7E,2DAA2D;AAC3D,MAAM,UAAU,oBAAoB,CAClC,KAAmB,EACnB,OAAgB,EAAE;IAElB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;YACrD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI;gBACtC,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,QAAQ,EAAE,CAAC;gBACX,OAAO,EAAE,EAAE;aACZ,CAAC;YACF,QAAQ,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACxC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;YAC5C,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;AAC5E,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@keel_flow/kb-pipeline",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.js",
18
+ "types": "./dist/index.d.ts"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "zod": "^3.23.0",
23
+ "@keel_flow/schema": "0.2.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@huggingface/transformers": ">=4.0.0"
27
+ },
28
+ "peerDependenciesMeta": {
29
+ "@huggingface/transformers": {
30
+ "optional": true
31
+ }
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^25.9.1",
35
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
36
+ "@typescript-eslint/parser": "^8.0.0",
37
+ "eslint": "^9.0.0",
38
+ "typescript": "^5.5.0",
39
+ "vitest": "^2.0.0"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc",
43
+ "typecheck": "tsc --noEmit",
44
+ "test": "vitest run",
45
+ "lint": "eslint src"
46
+ }
47
+ }