pcl-mcp 0.2.4 → 0.3.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 (114) hide show
  1. package/README.md +137 -28
  2. package/dist/benchmarks/evaluators/context-retrieval-quality.d.ts +30 -0
  3. package/dist/benchmarks/evaluators/context-retrieval-quality.d.ts.map +1 -0
  4. package/dist/benchmarks/evaluators/context-retrieval-quality.js +50 -0
  5. package/dist/benchmarks/evaluators/context-retrieval-quality.js.map +1 -0
  6. package/dist/benchmarks/evaluators/ir-metrics.d.ts +32 -0
  7. package/dist/benchmarks/evaluators/ir-metrics.d.ts.map +1 -0
  8. package/dist/benchmarks/evaluators/ir-metrics.js +98 -0
  9. package/dist/benchmarks/evaluators/ir-metrics.js.map +1 -0
  10. package/dist/benchmarks/evaluators/structured-judge.d.ts +34 -0
  11. package/dist/benchmarks/evaluators/structured-judge.d.ts.map +1 -0
  12. package/dist/benchmarks/evaluators/structured-judge.js +153 -0
  13. package/dist/benchmarks/evaluators/structured-judge.js.map +1 -0
  14. package/dist/benchmarks/evaluators/token-counter.d.ts +9 -0
  15. package/dist/benchmarks/evaluators/token-counter.d.ts.map +1 -0
  16. package/dist/benchmarks/evaluators/token-counter.js +24 -0
  17. package/dist/benchmarks/evaluators/token-counter.js.map +1 -0
  18. package/dist/benchmarks/generators/generate-corpus.d.ts +2 -0
  19. package/dist/benchmarks/generators/generate-corpus.d.ts.map +1 -0
  20. package/dist/benchmarks/generators/generate-corpus.js +243 -0
  21. package/dist/benchmarks/generators/generate-corpus.js.map +1 -0
  22. package/dist/benchmarks/lib/harness.d.ts +23 -0
  23. package/dist/benchmarks/lib/harness.d.ts.map +1 -0
  24. package/dist/benchmarks/lib/harness.js +44 -0
  25. package/dist/benchmarks/lib/harness.js.map +1 -0
  26. package/dist/benchmarks/lib/types.d.ts +79 -0
  27. package/dist/benchmarks/lib/types.d.ts.map +1 -0
  28. package/dist/benchmarks/lib/types.js +2 -0
  29. package/dist/benchmarks/lib/types.js.map +1 -0
  30. package/dist/benchmarks/reporters/markdown-reporter.d.ts +2 -0
  31. package/dist/benchmarks/reporters/markdown-reporter.d.ts.map +1 -0
  32. package/dist/benchmarks/reporters/markdown-reporter.js +80 -0
  33. package/dist/benchmarks/reporters/markdown-reporter.js.map +1 -0
  34. package/dist/benchmarks/runners/bench-ablation.d.ts +2 -0
  35. package/dist/benchmarks/runners/bench-ablation.d.ts.map +1 -0
  36. package/dist/benchmarks/runners/bench-ablation.js +49 -0
  37. package/dist/benchmarks/runners/bench-ablation.js.map +1 -0
  38. package/dist/benchmarks/runners/bench-ai-quality.d.ts +2 -0
  39. package/dist/benchmarks/runners/bench-ai-quality.d.ts.map +1 -0
  40. package/dist/benchmarks/runners/bench-ai-quality.js +297 -0
  41. package/dist/benchmarks/runners/bench-ai-quality.js.map +1 -0
  42. package/dist/benchmarks/runners/bench-interactive-eval.d.ts +2 -0
  43. package/dist/benchmarks/runners/bench-interactive-eval.d.ts.map +1 -0
  44. package/dist/benchmarks/runners/bench-interactive-eval.js +119 -0
  45. package/dist/benchmarks/runners/bench-interactive-eval.js.map +1 -0
  46. package/dist/benchmarks/runners/bench-performance.bench.d.ts +2 -0
  47. package/dist/benchmarks/runners/bench-performance.bench.d.ts.map +1 -0
  48. package/dist/benchmarks/runners/bench-performance.bench.js +50 -0
  49. package/dist/benchmarks/runners/bench-performance.bench.js.map +1 -0
  50. package/dist/benchmarks/runners/bench-search-quality.d.ts +2 -0
  51. package/dist/benchmarks/runners/bench-search-quality.d.ts.map +1 -0
  52. package/dist/benchmarks/runners/bench-search-quality.js +70 -0
  53. package/dist/benchmarks/runners/bench-search-quality.js.map +1 -0
  54. package/dist/benchmarks/runners/bench-token-efficiency.d.ts +2 -0
  55. package/dist/benchmarks/runners/bench-token-efficiency.d.ts.map +1 -0
  56. package/dist/benchmarks/runners/bench-token-efficiency.js +89 -0
  57. package/dist/benchmarks/runners/bench-token-efficiency.js.map +1 -0
  58. package/dist/benchmarks/runners/diag.d.ts +2 -0
  59. package/dist/benchmarks/runners/diag.d.ts.map +1 -0
  60. package/dist/benchmarks/runners/diag.js +30 -0
  61. package/dist/benchmarks/runners/diag.js.map +1 -0
  62. package/dist/benchmarks/vitest.config.bench.d.ts +3 -0
  63. package/dist/benchmarks/vitest.config.bench.d.ts.map +1 -0
  64. package/dist/benchmarks/vitest.config.bench.js +14 -0
  65. package/dist/benchmarks/vitest.config.bench.js.map +1 -0
  66. package/dist/bin/pcl.js +36 -23
  67. package/dist/bin/pcl.js.map +1 -1
  68. package/dist/src/db.d.ts +2 -1
  69. package/dist/src/db.d.ts.map +1 -1
  70. package/dist/src/db.js +25 -21
  71. package/dist/src/db.js.map +1 -1
  72. package/dist/src/embeddings.d.ts +1 -1
  73. package/dist/src/embeddings.js +2 -2
  74. package/dist/src/embeddings.js.map +1 -1
  75. package/dist/src/indexer.d.ts +1 -1
  76. package/dist/src/indexer.d.ts.map +1 -1
  77. package/dist/src/indexer.js +6 -2
  78. package/dist/src/indexer.js.map +1 -1
  79. package/dist/src/search.d.ts.map +1 -1
  80. package/dist/src/search.js +138 -26
  81. package/dist/src/search.js.map +1 -1
  82. package/dist/src/server.js +6 -0
  83. package/dist/src/server.js.map +1 -1
  84. package/dist/src/types.d.ts +1 -0
  85. package/dist/src/types.d.ts.map +1 -1
  86. package/dist/tests/db.test.d.ts +2 -0
  87. package/dist/tests/db.test.d.ts.map +1 -0
  88. package/dist/tests/db.test.js +459 -0
  89. package/dist/tests/db.test.js.map +1 -0
  90. package/dist/tests/embeddings.test.d.ts +2 -0
  91. package/dist/tests/embeddings.test.d.ts.map +1 -0
  92. package/dist/tests/embeddings.test.js +165 -0
  93. package/dist/tests/embeddings.test.js.map +1 -0
  94. package/dist/tests/helpers/test-harness.d.ts +26 -0
  95. package/dist/tests/helpers/test-harness.d.ts.map +1 -0
  96. package/dist/tests/helpers/test-harness.js +80 -0
  97. package/dist/tests/helpers/test-harness.js.map +1 -0
  98. package/dist/tests/indexer.test.d.ts +2 -0
  99. package/dist/tests/indexer.test.d.ts.map +1 -0
  100. package/dist/tests/indexer.test.js +299 -0
  101. package/dist/tests/indexer.test.js.map +1 -0
  102. package/dist/tests/schemas.test.d.ts +2 -0
  103. package/dist/tests/schemas.test.d.ts.map +1 -0
  104. package/dist/tests/schemas.test.js +378 -0
  105. package/dist/tests/schemas.test.js.map +1 -0
  106. package/dist/tests/search.test.d.ts +2 -0
  107. package/dist/tests/search.test.d.ts.map +1 -0
  108. package/dist/tests/search.test.js +129 -0
  109. package/dist/tests/search.test.js.map +1 -0
  110. package/dist/tests/tools.test.d.ts +2 -0
  111. package/dist/tests/tools.test.d.ts.map +1 -0
  112. package/dist/tests/tools.test.js +232 -0
  113. package/dist/tests/tools.test.js.map +1 -0
  114. package/package.json +14 -2
@@ -0,0 +1,165 @@
1
+ import { describe, it, expect, beforeAll } from "vitest";
2
+ import { embedText, embedBatch, cosineSimilarity, rankBySimilarity, DIMS, } from "../src/embeddings.js";
3
+ // ─── embedText ──────────────────────────────────────────────────────────────
4
+ describe("embedText", () => {
5
+ // First call downloads/loads the 23 MB model — allow up to 120s.
6
+ beforeAll(async () => {
7
+ await embedText("warmup");
8
+ }, 120_000);
9
+ it("returns exactly 384 dimensions", async () => {
10
+ const vec = await embedText("hello world");
11
+ expect(vec).toHaveLength(DIMS);
12
+ expect(vec).toHaveLength(384);
13
+ });
14
+ it("all values are finite numbers (no NaN or Infinity)", async () => {
15
+ const vec = await embedText("some meaningful sentence");
16
+ for (const v of vec) {
17
+ expect(typeof v).toBe("number");
18
+ expect(Number.isFinite(v)).toBe(true);
19
+ }
20
+ });
21
+ it("is deterministic: same text produces same vector", async () => {
22
+ const text = "deterministic embedding test";
23
+ const a = await embedText(text);
24
+ const b = await embedText(text);
25
+ expect(a).toEqual(b);
26
+ });
27
+ it("different texts produce different vectors", async () => {
28
+ const a = await embedText("the quick brown fox");
29
+ const b = await embedText("quantum mechanics in curved spacetime");
30
+ // Vectors should not be identical — cosine similarity < 1.0
31
+ const sim = cosineSimilarity(a, b);
32
+ expect(sim).toBeLessThan(1.0);
33
+ });
34
+ it("handles empty string without throwing", async () => {
35
+ const vec = await embedText("");
36
+ expect(vec).toHaveLength(DIMS);
37
+ // All values should still be finite
38
+ for (const v of vec) {
39
+ expect(Number.isFinite(v)).toBe(true);
40
+ }
41
+ });
42
+ it("handles very long text (>2000 chars) without throwing", async () => {
43
+ // Model truncates to 512*3 = 1536 chars
44
+ const longText = "a".repeat(3000);
45
+ const vec = await embedText(longText);
46
+ expect(vec).toHaveLength(DIMS);
47
+ });
48
+ it("handles single word input", async () => {
49
+ const vec = await embedText("cat");
50
+ expect(vec).toHaveLength(DIMS);
51
+ for (const v of vec) {
52
+ expect(Number.isFinite(v)).toBe(true);
53
+ }
54
+ });
55
+ });
56
+ // ─── embedBatch ─────────────────────────────────────────────────────────────
57
+ describe("embedBatch", () => {
58
+ beforeAll(async () => {
59
+ await embedText("warmup");
60
+ }, 120_000);
61
+ it("returns array matching input length", async () => {
62
+ const texts = ["hello", "world", "test"];
63
+ const results = await embedBatch(texts);
64
+ expect(results).toHaveLength(texts.length);
65
+ for (const vec of results) {
66
+ expect(vec).toHaveLength(DIMS);
67
+ }
68
+ });
69
+ it("returns empty array for failed embeddings", async () => {
70
+ // embedBatch catches errors per-item and pushes [] for failures.
71
+ // With valid strings the model should not fail, so we verify that
72
+ // the happy path produces non-empty vectors for every input.
73
+ const results = await embedBatch(["valid text"]);
74
+ expect(results).toHaveLength(1);
75
+ expect(results[0].length).toBe(DIMS);
76
+ });
77
+ it("calls onProgress with correct counts", async () => {
78
+ const texts = ["alpha", "beta", "gamma"];
79
+ const progress = [];
80
+ await embedBatch(texts, (done, total) => {
81
+ progress.push({ done, total });
82
+ });
83
+ expect(progress).toHaveLength(texts.length);
84
+ for (let i = 0; i < texts.length; i++) {
85
+ expect(progress[i].done).toBe(i + 1);
86
+ expect(progress[i].total).toBe(texts.length);
87
+ }
88
+ });
89
+ });
90
+ // ─── cosineSimilarity ───────────────────────────────────────────────────────
91
+ describe("cosineSimilarity", () => {
92
+ it("returns 1.0 for identical normalized vectors", () => {
93
+ // Create a normalized vector (unit length)
94
+ const dim = 384;
95
+ const val = 1 / Math.sqrt(dim);
96
+ const vec = Array.from({ length: dim }, () => val);
97
+ const sim = cosineSimilarity(vec, vec);
98
+ expect(sim).toBeCloseTo(1.0, 5);
99
+ });
100
+ it("returns ~0 for orthogonal vectors", () => {
101
+ // Two basis vectors in high-dim space are orthogonal
102
+ const a = Array.from({ length: 384 }, () => 0);
103
+ const b = Array.from({ length: 384 }, () => 0);
104
+ a[0] = 1;
105
+ b[1] = 1;
106
+ const sim = cosineSimilarity(a, b);
107
+ expect(sim).toBeCloseTo(0, 5);
108
+ });
109
+ it("result is in [-1, 1] range", () => {
110
+ // Opposite direction vectors
111
+ const dim = 384;
112
+ const val = 1 / Math.sqrt(dim);
113
+ const a = Array.from({ length: dim }, () => val);
114
+ const b = Array.from({ length: dim }, () => -val);
115
+ const simSame = cosineSimilarity(a, a);
116
+ const simOpposite = cosineSimilarity(a, b);
117
+ expect(simSame).toBeGreaterThanOrEqual(-1);
118
+ expect(simSame).toBeLessThanOrEqual(1);
119
+ expect(simOpposite).toBeGreaterThanOrEqual(-1);
120
+ expect(simOpposite).toBeLessThanOrEqual(1);
121
+ expect(simOpposite).toBeCloseTo(-1.0, 5);
122
+ });
123
+ it("returns 0 for empty vectors", () => {
124
+ const sim = cosineSimilarity([], []);
125
+ expect(sim).toBe(0);
126
+ });
127
+ });
128
+ // ─── rankBySimilarity ───────────────────────────────────────────────────────
129
+ describe("rankBySimilarity", () => {
130
+ // Pre-compute some distinct vectors for ranking tests.
131
+ // Use simple hand-crafted vectors so tests are deterministic.
132
+ function makeVec(index) {
133
+ const vec = Array.from({ length: 384 }, () => 0);
134
+ vec[index % 384] = 1;
135
+ return vec;
136
+ }
137
+ const corpus = [
138
+ { id: "a", type: "persona", embedding: makeVec(0) },
139
+ { id: "b", type: "spec", embedding: makeVec(1) },
140
+ { id: "c", type: "journey", embedding: makeVec(2) },
141
+ { id: "d", type: "decision", embedding: makeVec(3) },
142
+ ];
143
+ it("returns results sorted by score descending", () => {
144
+ // Query aligns with item "a" (index 0)
145
+ const query = makeVec(0);
146
+ const results = rankBySimilarity(query, corpus, 4);
147
+ expect(results[0].id).toBe("a");
148
+ expect(results[0].score).toBeCloseTo(1.0, 5);
149
+ // Remaining items should all have score ~0 (orthogonal)
150
+ for (let i = 1; i < results.length; i++) {
151
+ expect(results[i].score).toBeLessThanOrEqual(results[i - 1].score);
152
+ }
153
+ });
154
+ it("respects topK limit", () => {
155
+ const query = makeVec(0);
156
+ const results = rankBySimilarity(query, corpus, 2);
157
+ expect(results).toHaveLength(2);
158
+ });
159
+ it("returns fewer than topK when corpus is smaller", () => {
160
+ const query = makeVec(0);
161
+ const results = rankBySimilarity(query, corpus, 100);
162
+ expect(results).toHaveLength(corpus.length);
163
+ });
164
+ });
165
+ //# sourceMappingURL=embeddings.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.test.js","sourceRoot":"","sources":["../../tests/embeddings.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { IndexedFile } from "../../src/types.js";
3
+ export declare const CORPUS_DIR: string;
4
+ export interface TestHarness {
5
+ db: Database.Database;
6
+ productDir: string;
7
+ cleanup: () => Promise<void>;
8
+ }
9
+ /**
10
+ * Create a fresh test DB environment.
11
+ * - copyCorpus: true → copies corpus-small fixtures into temp dir
12
+ * - copyCorpus: false → creates empty product dir structure
13
+ */
14
+ export declare function createTestDB(opts?: {
15
+ copyCorpus?: boolean;
16
+ }): Promise<TestHarness>;
17
+ /**
18
+ * Factory for creating IndexedFile objects with sensible defaults.
19
+ * Override any field as needed.
20
+ */
21
+ export declare function createTestFile(overrides?: Partial<IndexedFile>): IndexedFile;
22
+ /**
23
+ * Write a markdown file to the product dir with frontmatter + body.
24
+ */
25
+ export declare function writeTestMarkdown(productDir: string, relativePath: string, frontmatter: Record<string, unknown>, body: string): Promise<string>;
26
+ //# sourceMappingURL=test-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-harness.d.ts","sourceRoot":"","sources":["../../../tests/helpers/test-harness.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAY,MAAM,oBAAoB,CAAC;AAEhE,eAAO,MAAM,UAAU,QAOtB,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,OAAO,CAAC,WAAW,CAAC,CA2BtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GACnC,WAAW,CAiBb;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAcjB"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Shared test harness — creates isolated DB environments for each test.
3
+ */
4
+ import { mkdtemp, cp, rm, mkdir, writeFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+ import { openDB, closeDB } from "../../src/db.js";
8
+ export const CORPUS_DIR = join(import.meta.dirname, "..", "..", "benchmarks", "fixtures", "corpus-small");
9
+ /**
10
+ * Create a fresh test DB environment.
11
+ * - copyCorpus: true → copies corpus-small fixtures into temp dir
12
+ * - copyCorpus: false → creates empty product dir structure
13
+ */
14
+ export async function createTestDB(opts = {}) {
15
+ closeDB();
16
+ const tmpDir = await mkdtemp(join(tmpdir(), "pcl-test-"));
17
+ const productDir = join(tmpDir, "product");
18
+ if (opts.copyCorpus) {
19
+ await cp(CORPUS_DIR, productDir, { recursive: true });
20
+ }
21
+ else {
22
+ await mkdir(productDir, { recursive: true });
23
+ await mkdir(join(productDir, "personas"), { recursive: true });
24
+ await mkdir(join(productDir, "journeys"), { recursive: true });
25
+ await mkdir(join(productDir, "specs"), { recursive: true });
26
+ await mkdir(join(productDir, "decisions"), { recursive: true });
27
+ await mkdir(join(productDir, "domain"), { recursive: true });
28
+ }
29
+ const db = openDB(productDir);
30
+ return {
31
+ db,
32
+ productDir,
33
+ cleanup: async () => {
34
+ closeDB();
35
+ await rm(tmpDir, { recursive: true, force: true });
36
+ },
37
+ };
38
+ }
39
+ /**
40
+ * Factory for creating IndexedFile objects with sensible defaults.
41
+ * Override any field as needed.
42
+ */
43
+ export function createTestFile(overrides = {}) {
44
+ return {
45
+ id: "test-file",
46
+ type: "persona",
47
+ path: "/tmp/test/personas/test-file.md",
48
+ frontmatter: { id: "test-file", name: "Test", role: "Tester", primary_goal: "Test things" },
49
+ body: "## Test file body\n\nThis is test content for benchmarking and testing.",
50
+ fullText: "---\nid: test-file\nname: Test\n---\n\n## Test file body\n\nThis is test content.",
51
+ mtime: Date.now(),
52
+ hash: "abcdef1234567890",
53
+ embedding: Array.from({ length: 384 }, () => Math.random()),
54
+ embeddingTitle: Array.from({ length: 384 }, () => Math.random()),
55
+ title: "Test",
56
+ summary: "This is test content for benchmarking and testing.",
57
+ critical: false,
58
+ ...overrides,
59
+ };
60
+ }
61
+ /**
62
+ * Write a markdown file to the product dir with frontmatter + body.
63
+ */
64
+ export async function writeTestMarkdown(productDir, relativePath, frontmatter, body) {
65
+ const fullPath = join(productDir, relativePath);
66
+ const yamlLines = Object.entries(frontmatter)
67
+ .map(([k, v]) => {
68
+ if (Array.isArray(v)) {
69
+ return `${k}:\n${v.map((item) => ` - "${item}"`).join("\n")}`;
70
+ }
71
+ if (typeof v === "boolean")
72
+ return `${k}: ${v}`;
73
+ return `${k}: "${v}"`;
74
+ })
75
+ .join("\n");
76
+ const content = `---\n${yamlLines}\n---\n\n${body}`;
77
+ await writeFile(fullPath, content);
78
+ return fullPath;
79
+ }
80
+ //# sourceMappingURL=test-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-harness.js","sourceRoot":"","sources":["../../../tests/helpers/test-harness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=indexer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.test.d.ts","sourceRoot":"","sources":["../../tests/indexer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,299 @@
1
+ import { describe, it, expect, beforeAll, afterEach } from "vitest";
2
+ import { createTestDB, writeTestMarkdown, } from "./helpers/test-harness.js";
3
+ import { parseFile, indexFile, fullIndex } from "../src/indexer.js";
4
+ import { embedText } from "../src/embeddings.js";
5
+ import { getFileByPath } from "../src/db.js";
6
+ // ─── parseFile ──────────────────────────────────────────────────────────────
7
+ describe("parseFile", () => {
8
+ let harness;
9
+ beforeAll(async () => {
10
+ // Warm up embedding model for later suites
11
+ await embedText("warmup");
12
+ }, 120_000);
13
+ afterEach(async () => {
14
+ if (harness)
15
+ await harness.cleanup();
16
+ });
17
+ it("parses valid persona markdown into correct shape", async () => {
18
+ harness = await createTestDB();
19
+ const path = await writeTestMarkdown(harness.productDir, "personas/alpha-user.md", {
20
+ id: "alpha-user",
21
+ name: "Alpha User",
22
+ role: "Engineer",
23
+ primary_goal: "Ship fast",
24
+ }, "## About\n\nAlpha user is a power user who loves automation.");
25
+ const result = await parseFile(path, harness.productDir);
26
+ expect(result).not.toBeNull();
27
+ expect(result.file.id).toBe("alpha-user");
28
+ expect(result.file.type).toBe("persona");
29
+ expect(result.file.body).toContain("Alpha user is a power user");
30
+ expect(result.file.frontmatter).toHaveProperty("name", "Alpha User");
31
+ expect(typeof result.file.hash).toBe("string");
32
+ expect(result.file.hash.length).toBeGreaterThan(0);
33
+ });
34
+ it("detects type 'product' from path product.md", async () => {
35
+ harness = await createTestDB();
36
+ const path = await writeTestMarkdown(harness.productDir, "product.md", {
37
+ name: "TestProduct",
38
+ tagline: "A test",
39
+ problem: "Testing",
40
+ solution: "Tests",
41
+ primary_persona: "tester",
42
+ stage: "idea",
43
+ }, "# Product");
44
+ const result = await parseFile(path, harness.productDir);
45
+ expect(result).not.toBeNull();
46
+ expect(result.file.type).toBe("product");
47
+ });
48
+ it("detects type 'persona' from path personas/x.md", async () => {
49
+ harness = await createTestDB();
50
+ const path = await writeTestMarkdown(harness.productDir, "personas/test-persona.md", { id: "test-persona", name: "Test", role: "Tester", primary_goal: "Test" }, "Body");
51
+ const result = await parseFile(path, harness.productDir);
52
+ expect(result).not.toBeNull();
53
+ expect(result.file.type).toBe("persona");
54
+ });
55
+ it("detects type 'journey' from path journeys/x.md", async () => {
56
+ harness = await createTestDB();
57
+ const path = await writeTestMarkdown(harness.productDir, "journeys/test-journey.md", {
58
+ id: "test-journey",
59
+ persona: "tester",
60
+ trigger: "click",
61
+ success_state: "done",
62
+ steps: "step1",
63
+ }, "Journey body");
64
+ const result = await parseFile(path, harness.productDir);
65
+ expect(result).not.toBeNull();
66
+ expect(result.file.type).toBe("journey");
67
+ });
68
+ it("detects type 'spec' from path specs/x.md", async () => {
69
+ harness = await createTestDB();
70
+ const path = await writeTestMarkdown(harness.productDir, "specs/test-spec.md", { id: "test-spec", title: "Test Spec", status: "draft" }, "Spec body");
71
+ const result = await parseFile(path, harness.productDir);
72
+ expect(result).not.toBeNull();
73
+ expect(result.file.type).toBe("spec");
74
+ });
75
+ it("detects type 'decision' from path decisions/x.md", async () => {
76
+ harness = await createTestDB();
77
+ const path = await writeTestMarkdown(harness.productDir, "decisions/adr-test.md", {
78
+ id: "adr-test",
79
+ title: "Test Decision",
80
+ status: "proposed",
81
+ date: "2025-01-01",
82
+ context: "Testing",
83
+ decision: "Decided",
84
+ }, "Decision body");
85
+ const result = await parseFile(path, harness.productDir);
86
+ expect(result).not.toBeNull();
87
+ expect(result.file.type).toBe("decision");
88
+ });
89
+ it("detects type 'domain' from path domain/x.md", async () => {
90
+ harness = await createTestDB();
91
+ const path = await writeTestMarkdown(harness.productDir, "domain/rules.md", { id: "rules", title: "Business Rules" }, "Domain rules here");
92
+ const result = await parseFile(path, harness.productDir);
93
+ expect(result).not.toBeNull();
94
+ expect(result.file.type).toBe("domain");
95
+ });
96
+ it("returns null for unrecognized path (e.g., random/file.md)", async () => {
97
+ harness = await createTestDB();
98
+ // Write a file outside the recognized directories
99
+ const { writeFile, mkdir } = await import("node:fs/promises");
100
+ const { join } = await import("node:path");
101
+ const dir = join(harness.productDir, "random");
102
+ await mkdir(dir, { recursive: true });
103
+ const path = join(dir, "file.md");
104
+ await writeFile(path, "---\nid: x\n---\nBody");
105
+ const result = await parseFile(path, harness.productDir);
106
+ expect(result).toBeNull();
107
+ });
108
+ it("returns null for non-existent file", async () => {
109
+ harness = await createTestDB();
110
+ const fakePath = harness.productDir + "/personas/does-not-exist.md";
111
+ const result = await parseFile(fakePath, harness.productDir);
112
+ expect(result).toBeNull();
113
+ });
114
+ it("returns error when frontmatter fails validation", async () => {
115
+ harness = await createTestDB();
116
+ // Persona requires id, name, role, primary_goal — omit required fields
117
+ const path = await writeTestMarkdown(harness.productDir, "personas/invalid.md", { id: "invalid" }, "Body with missing fields");
118
+ const result = await parseFile(path, harness.productDir);
119
+ expect(result).not.toBeNull();
120
+ expect(result.error).toBeDefined();
121
+ expect(typeof result.error).toBe("string");
122
+ expect(result.error.length).toBeGreaterThan(0);
123
+ });
124
+ it("still returns file data when frontmatter is invalid", async () => {
125
+ harness = await createTestDB();
126
+ const path = await writeTestMarkdown(harness.productDir, "personas/partial.md", { id: "partial" }, "Some body content");
127
+ const result = await parseFile(path, harness.productDir);
128
+ expect(result).not.toBeNull();
129
+ expect(result.error).toBeDefined();
130
+ // Even with validation failure, file data is returned
131
+ expect(result.file.id).toBe("partial");
132
+ expect(result.file.type).toBe("persona");
133
+ expect(result.file.body).toContain("Some body content");
134
+ });
135
+ it("derives id from frontmatter.id when present", async () => {
136
+ harness = await createTestDB();
137
+ const path = await writeTestMarkdown(harness.productDir, "personas/filename-differs.md", {
138
+ id: "custom-id",
139
+ name: "Custom",
140
+ role: "Tester",
141
+ primary_goal: "Test",
142
+ }, "Body");
143
+ const result = await parseFile(path, harness.productDir);
144
+ expect(result).not.toBeNull();
145
+ expect(result.file.id).toBe("custom-id");
146
+ });
147
+ it("derives id from filename when frontmatter.id is missing", async () => {
148
+ harness = await createTestDB();
149
+ // Product schema does not require an id field in frontmatter
150
+ const path = await writeTestMarkdown(harness.productDir, "product.md", {
151
+ name: "NoIdProduct",
152
+ tagline: "Tag",
153
+ problem: "Prob",
154
+ solution: "Sol",
155
+ primary_persona: "tester",
156
+ stage: "idea",
157
+ }, "Body");
158
+ const result = await parseFile(path, harness.productDir);
159
+ expect(result).not.toBeNull();
160
+ // Falls back to basename without extension: "product"
161
+ expect(result.file.id).toBe("product");
162
+ });
163
+ it("sets critical=true only for domain files with critical: true", async () => {
164
+ harness = await createTestDB();
165
+ const criticalPath = await writeTestMarkdown(harness.productDir, "domain/critical-rules.md", { id: "critical-rules", critical: true, title: "Critical" }, "Critical domain rules");
166
+ const nonCriticalPath = await writeTestMarkdown(harness.productDir, "domain/normal-rules.md", { id: "normal-rules", critical: false, title: "Normal" }, "Normal domain rules");
167
+ const personaPath = await writeTestMarkdown(harness.productDir, "personas/not-domain.md", { id: "not-domain", name: "NPC", role: "None", primary_goal: "Nothing" }, "Not a domain file");
168
+ const critical = await parseFile(criticalPath, harness.productDir);
169
+ const nonCritical = await parseFile(nonCriticalPath, harness.productDir);
170
+ const persona = await parseFile(personaPath, harness.productDir);
171
+ expect(critical.file.critical).toBe(true);
172
+ expect(nonCritical.file.critical).toBe(false);
173
+ expect(persona.file.critical).toBe(false);
174
+ });
175
+ it("generates summary from first 300 chars of body", async () => {
176
+ harness = await createTestDB();
177
+ const longBody = "A".repeat(500);
178
+ const path = await writeTestMarkdown(harness.productDir, "domain/long-body.md", { id: "long-body", title: "Long" }, longBody);
179
+ const result = await parseFile(path, harness.productDir);
180
+ expect(result).not.toBeNull();
181
+ expect(result.file.summary.length).toBeLessThanOrEqual(300);
182
+ });
183
+ });
184
+ // ─── indexFile ───────────────────────────────────────────────────────────────
185
+ describe("indexFile", () => {
186
+ let harness;
187
+ beforeAll(async () => {
188
+ await embedText("warmup");
189
+ }, 120_000);
190
+ afterEach(async () => {
191
+ if (harness)
192
+ await harness.cleanup();
193
+ });
194
+ it("indexes a new file and returns indexed: true", async () => {
195
+ harness = await createTestDB();
196
+ const path = await writeTestMarkdown(harness.productDir, "personas/new-persona.md", {
197
+ id: "new-persona",
198
+ name: "New Persona",
199
+ role: "Engineer",
200
+ primary_goal: "Build things",
201
+ }, "## About\n\nA brand new persona for testing.");
202
+ const result = await indexFile(harness.db, path, harness.productDir, true);
203
+ expect(result.indexed).toBe(true);
204
+ expect(result.embedded).toBe(true);
205
+ expect(result.error).toBeUndefined();
206
+ // Verify it was actually written to DB
207
+ const stored = getFileByPath(harness.db, path);
208
+ expect(stored).not.toBeNull();
209
+ expect(stored.id).toBe("new-persona");
210
+ expect(stored.embedding.length).toBe(384);
211
+ });
212
+ it("skips re-indexing when content hash unchanged", async () => {
213
+ harness = await createTestDB();
214
+ const path = await writeTestMarkdown(harness.productDir, "personas/stable.md", {
215
+ id: "stable",
216
+ name: "Stable Persona",
217
+ role: "Tester",
218
+ primary_goal: "Remain stable",
219
+ }, "Unchanged body content");
220
+ // First index
221
+ const first = await indexFile(harness.db, path, harness.productDir, true);
222
+ expect(first.indexed).toBe(true);
223
+ // Second index with same content — should skip
224
+ const second = await indexFile(harness.db, path, harness.productDir, true);
225
+ expect(second.indexed).toBe(false);
226
+ expect(second.embedded).toBe(false);
227
+ });
228
+ it("returns indexed: false for non-markdown paths", async () => {
229
+ harness = await createTestDB();
230
+ // parseFile returns null for unrecognized paths
231
+ const result = await indexFile(harness.db, harness.productDir + "/README.txt", harness.productDir, false);
232
+ expect(result.indexed).toBe(false);
233
+ expect(result.embedded).toBe(false);
234
+ });
235
+ });
236
+ // ─── fullIndex ──────────────────────────────────────────────────────────────
237
+ describe("fullIndex", () => {
238
+ let harness;
239
+ beforeAll(async () => {
240
+ await embedText("warmup");
241
+ }, 120_000);
242
+ afterEach(async () => {
243
+ if (harness)
244
+ await harness.cleanup();
245
+ });
246
+ it("indexes all markdown files in corpus", async () => {
247
+ harness = await createTestDB({ copyCorpus: true });
248
+ const result = await fullIndex(harness.db, harness.productDir);
249
+ // corpus-small has: product.md + 2 personas + 2 journeys + 2 specs + 1 decision + 2 domain = 10
250
+ expect(result.total).toBeGreaterThan(0);
251
+ expect(result.indexed).toBe(result.total);
252
+ expect(result.errors).toBeInstanceOf(Array);
253
+ });
254
+ it("reports correct total count", async () => {
255
+ harness = await createTestDB({ copyCorpus: true });
256
+ const result = await fullIndex(harness.db, harness.productDir);
257
+ // Verify total matches the actual number of .md files in the fixture corpus
258
+ const { readdir } = await import("node:fs/promises");
259
+ const { join } = await import("node:path");
260
+ async function countMd(dir) {
261
+ let count = 0;
262
+ const entries = await readdir(dir, { withFileTypes: true });
263
+ for (const e of entries) {
264
+ if (e.isDirectory())
265
+ count += await countMd(join(dir, e.name));
266
+ else if (e.isFile() && e.name.endsWith(".md"))
267
+ count++;
268
+ }
269
+ return count;
270
+ }
271
+ const expected = await countMd(harness.productDir);
272
+ expect(result.total).toBe(expected);
273
+ });
274
+ it("on re-run with no changes, indexed count is 0", async () => {
275
+ harness = await createTestDB({ copyCorpus: true });
276
+ // First run — indexes everything
277
+ await fullIndex(harness.db, harness.productDir);
278
+ // Second run — nothing changed, so indexed should be 0
279
+ const second = await fullIndex(harness.db, harness.productDir);
280
+ expect(second.indexed).toBe(0);
281
+ expect(second.total).toBeGreaterThan(0);
282
+ });
283
+ it("calls onProgress with done/total/path", async () => {
284
+ harness = await createTestDB({ copyCorpus: true });
285
+ const progress = [];
286
+ const result = await fullIndex(harness.db, harness.productDir, (done, total, path) => {
287
+ progress.push({ done, total, path });
288
+ });
289
+ expect(progress).toHaveLength(result.total);
290
+ // done should increment from 1 to total
291
+ for (let i = 0; i < progress.length; i++) {
292
+ expect(progress[i].done).toBe(i + 1);
293
+ expect(progress[i].total).toBe(result.total);
294
+ expect(typeof progress[i].path).toBe("string");
295
+ expect(progress[i].path.endsWith(".md")).toBe(true);
296
+ }
297
+ });
298
+ });
299
+ //# sourceMappingURL=indexer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.test.js","sourceRoot":"","sources":["../../tests/indexer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,iBAAiB,GAGlB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,+EAA+E;AAE/E,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,OAAoB,CAAC;IAEzB,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,2CAA2C;QAC3C,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,EAAE,OAAO,CAAC,CAAC;IAEZ,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,OAAO;YAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,wBAAwB,EACxB;YACE,EAAE,EAAE,YAAY;YAChB,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,WAAW;SAC1B,EACD,8DAA8D,CAC/D,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAEzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QAClE,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACtE,MAAM,CAAC,OAAO,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,YAAY,EACZ;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,OAAO;YACjB,eAAe,EAAE,QAAQ;YACzB,KAAK,EAAE,MAAM;SACd,EACD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,0BAA0B,EAC1B,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,EAC1E,MAAM,CACP,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,0BAA0B,EAC1B;YACE,EAAE,EAAE,cAAc;YAClB,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,OAAO;YAChB,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,OAAO;SACf,EACD,cAAc,CACf,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,oBAAoB,EACpB,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,EACxD,WAAW,CACZ,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,uBAAuB,EACvB;YACE,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,eAAe;YACtB,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,SAAS;SACpB,EACD,eAAe,CAChB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,iBAAiB,EACjB,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,EACxC,mBAAmB,CACpB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,kDAAkD;QAClD,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC9D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAClC,MAAM,SAAS,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;QAE/C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,6BAA6B,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,uEAAuE;QACvE,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,qBAAqB,EACrB,EAAE,EAAE,EAAE,SAAS,EAAE,EACjB,0BAA0B,CAC3B,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,CAAC,OAAO,MAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAO,CAAC,KAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,qBAAqB,EACrB,EAAE,EAAE,EAAE,SAAS,EAAE,EACjB,mBAAmB,CACpB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,sDAAsD;QACtD,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,8BAA8B,EAC9B;YACE,EAAE,EAAE,WAAW;YACf,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,YAAY,EAAE,MAAM;SACrB,EACD,MAAM,CACP,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,6DAA6D;QAC7D,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,YAAY,EACZ;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,KAAK;YACf,eAAe,EAAE,QAAQ;YACzB,KAAK,EAAE,MAAM;SACd,EACD,MAAM,CACP,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,sDAAsD;QACtD,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAE/B,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAC1C,OAAO,CAAC,UAAU,EAClB,0BAA0B,EAC1B,EAAE,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAC3D,uBAAuB,CACxB,CAAC;QACF,MAAM,eAAe,GAAG,MAAM,iBAAiB,CAC7C,OAAO,CAAC,UAAU,EAClB,wBAAwB,EACxB,EAAE,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EACxD,qBAAqB,CACtB,CAAC;QACF,MAAM,WAAW,GAAG,MAAM,iBAAiB,CACzC,OAAO,CAAC,UAAU,EAClB,wBAAwB,EACxB,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,EACxE,mBAAmB,CACpB,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACnE,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAEjE,MAAM,CAAC,QAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,CAAC,WAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,qBAAqB,EACrB,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,EAClC,QAAQ,CACT,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAEhF,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,OAAoB,CAAC;IAEzB,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,EAAE,OAAO,CAAC,CAAC;IAEZ,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,OAAO;YAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,yBAAyB,EACzB;YACE,EAAE,EAAE,aAAa;YACjB,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,cAAc;SAC7B,EACD,8CAA8C,CAC/C,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAE3E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QAErC,uCAAuC;QACvC,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,MAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,OAAO,CAAC,UAAU,EAClB,oBAAoB,EACpB;YACE,EAAE,EAAE,QAAQ;YACZ,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,QAAQ;YACd,YAAY,EAAE,eAAe;SAC9B,EACD,wBAAwB,CACzB,CAAC;QAEF,cAAc;QACd,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjC,+CAA+C;QAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC3E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;QAC/B,gDAAgD;QAChD,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,UAAU,GAAG,aAAa,EAClC,OAAO,CAAC,UAAU,EAClB,KAAK,CACN,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+EAA+E;AAE/E,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,OAAoB,CAAC;IAEzB,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,EAAE,OAAO,CAAC,CAAC;IAEZ,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,OAAO;YAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAE/D,gGAAgG;QAChG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAE/D,4EAA4E;QAC5E,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAE3C,KAAK,UAAU,OAAO,CAAC,GAAW;YAChC,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,CAAC,WAAW,EAAE;oBAAE,KAAK,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;qBAC1D,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAAE,KAAK,EAAE,CAAC;YACzD,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnD,iCAAiC;QACjC,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAEhD,uDAAuD;QACvD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAyD,EAAE,CAAC;QAE1E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE5C,wCAAwC;QACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9C,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schemas.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.test.d.ts","sourceRoot":"","sources":["../../tests/schemas.test.ts"],"names":[],"mappings":""}