@ai2070/memex 0.9.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 (46) hide show
  1. package/.github/workflows/ci.yml +31 -0
  2. package/.github/workflows/release.yml +35 -0
  3. package/API.md +1078 -0
  4. package/LICENSE +190 -0
  5. package/README.md +574 -0
  6. package/package.json +30 -0
  7. package/src/bulk.ts +128 -0
  8. package/src/envelope.ts +52 -0
  9. package/src/errors.ts +27 -0
  10. package/src/graph.ts +15 -0
  11. package/src/helpers.ts +51 -0
  12. package/src/index.ts +142 -0
  13. package/src/integrity.ts +378 -0
  14. package/src/intent.ts +311 -0
  15. package/src/query.ts +357 -0
  16. package/src/reducer.ts +177 -0
  17. package/src/replay.ts +32 -0
  18. package/src/retrieval.ts +306 -0
  19. package/src/serialization.ts +34 -0
  20. package/src/stats.ts +62 -0
  21. package/src/task.ts +373 -0
  22. package/src/transplant.ts +488 -0
  23. package/src/types.ts +248 -0
  24. package/tests/bugfix-and-coverage.test.ts +958 -0
  25. package/tests/bugfix-holes.test.ts +856 -0
  26. package/tests/bulk.test.ts +256 -0
  27. package/tests/edge-cases-v2.test.ts +355 -0
  28. package/tests/edge-cases.test.ts +661 -0
  29. package/tests/envelope.test.ts +92 -0
  30. package/tests/graph.test.ts +41 -0
  31. package/tests/helpers.test.ts +120 -0
  32. package/tests/integrity.test.ts +371 -0
  33. package/tests/intent.test.ts +276 -0
  34. package/tests/query-advanced.test.ts +252 -0
  35. package/tests/query.test.ts +623 -0
  36. package/tests/reducer.test.ts +342 -0
  37. package/tests/replay.test.ts +145 -0
  38. package/tests/retrieval.test.ts +691 -0
  39. package/tests/serialization.test.ts +118 -0
  40. package/tests/setup.test.ts +7 -0
  41. package/tests/stats.test.ts +163 -0
  42. package/tests/task.test.ts +322 -0
  43. package/tests/transplant.test.ts +385 -0
  44. package/tests/types.test.ts +231 -0
  45. package/tsconfig.json +18 -0
  46. package/vitest.config.ts +7 -0
@@ -0,0 +1,385 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { exportSlice, importSlice } from "../src/transplant.js";
3
+ import { createGraphState } from "../src/graph.js";
4
+ import { applyCommand } from "../src/reducer.js";
5
+ import {
6
+ createIntentState,
7
+ applyIntentCommand,
8
+ createIntent,
9
+ } from "../src/intent.js";
10
+ import { createTaskState, applyTaskCommand, createTask } from "../src/task.js";
11
+ import type { MemoryItem, Edge, GraphState } from "../src/types.js";
12
+ import type { IntentState } from "../src/intent.js";
13
+ import type { TaskState } from "../src/task.js";
14
+
15
+ // -- helpers --
16
+
17
+ const makeItem = (
18
+ id: string,
19
+ overrides: Partial<MemoryItem> = {},
20
+ ): MemoryItem => ({
21
+ id,
22
+ scope: "test",
23
+ kind: "observation",
24
+ content: {},
25
+ author: "agent:a",
26
+ source_kind: "observed",
27
+ authority: 0.5,
28
+ ...overrides,
29
+ });
30
+
31
+ const makeEdge = (
32
+ id: string,
33
+ from: string,
34
+ to: string,
35
+ kind: string = "SUPPORTS",
36
+ ): Edge => ({
37
+ edge_id: id,
38
+ from,
39
+ to,
40
+ kind,
41
+ author: "system:rule",
42
+ source_kind: "derived_deterministic",
43
+ authority: 0.8,
44
+ active: true,
45
+ });
46
+
47
+ function buildState(): {
48
+ mem: GraphState;
49
+ intents: IntentState;
50
+ tasks: TaskState;
51
+ } {
52
+ let mem = createGraphState();
53
+ mem = applyCommand(mem, {
54
+ type: "memory.create",
55
+ item: makeItem("m1"),
56
+ }).state;
57
+ mem = applyCommand(mem, {
58
+ type: "memory.create",
59
+ item: makeItem("m2", { parents: ["m1"] }),
60
+ }).state;
61
+ mem = applyCommand(mem, {
62
+ type: "memory.create",
63
+ item: makeItem("m3", { parents: ["m2"] }),
64
+ }).state;
65
+ mem = applyCommand(mem, {
66
+ type: "memory.create",
67
+ item: makeItem("m4"),
68
+ }).state;
69
+ mem = applyCommand(mem, {
70
+ type: "edge.create",
71
+ edge: makeEdge("e1", "m1", "m2"),
72
+ }).state;
73
+ mem = applyCommand(mem, {
74
+ type: "edge.create",
75
+ edge: makeEdge("e2", "m2", "m3"),
76
+ }).state;
77
+
78
+ let intents = createIntentState();
79
+ intents = applyIntentCommand(intents, {
80
+ type: "intent.create",
81
+ intent: createIntent({
82
+ id: "i1",
83
+ label: "find_kati",
84
+ priority: 0.9,
85
+ owner: "user:laz",
86
+ root_memory_ids: ["m1"],
87
+ }),
88
+ }).state;
89
+
90
+ let tasks = createTaskState();
91
+ tasks = applyTaskCommand(tasks, {
92
+ type: "task.create",
93
+ task: createTask({
94
+ id: "t1",
95
+ intent_id: "i1",
96
+ action: "search",
97
+ priority: 0.8,
98
+ input_memory_ids: ["m1"],
99
+ output_memory_ids: ["m2"],
100
+ }),
101
+ }).state;
102
+
103
+ return { mem, intents, tasks };
104
+ }
105
+
106
+ // ============================================================
107
+ // Export
108
+ // ============================================================
109
+
110
+ describe("exportSlice", () => {
111
+ it("exports specific memory ids", () => {
112
+ const { mem, intents, tasks } = buildState();
113
+ const slice = exportSlice(mem, intents, tasks, {
114
+ memory_ids: ["m1"],
115
+ });
116
+ expect(slice.memories).toHaveLength(1);
117
+ expect(slice.memories[0].id).toBe("m1");
118
+ expect(slice.edges).toHaveLength(0); // no edges with both ends in slice
119
+ expect(slice.intents).toHaveLength(0);
120
+ expect(slice.tasks).toHaveLength(0);
121
+ });
122
+
123
+ it("exports with parents", () => {
124
+ const { mem, intents, tasks } = buildState();
125
+ const slice = exportSlice(mem, intents, tasks, {
126
+ memory_ids: ["m3"],
127
+ include_parents: true,
128
+ });
129
+ expect(slice.memories.map((m) => m.id).sort()).toEqual(["m1", "m2", "m3"]);
130
+ // edges between included items
131
+ expect(slice.edges.length).toBeGreaterThanOrEqual(2);
132
+ });
133
+
134
+ it("exports with children", () => {
135
+ const { mem, intents, tasks } = buildState();
136
+ const slice = exportSlice(mem, intents, tasks, {
137
+ memory_ids: ["m1"],
138
+ include_children: true,
139
+ });
140
+ expect(slice.memories.map((m) => m.id).sort()).toEqual(["m1", "m2", "m3"]);
141
+ });
142
+
143
+ it("exports related intents and tasks", () => {
144
+ const { mem, intents, tasks } = buildState();
145
+ const slice = exportSlice(mem, intents, tasks, {
146
+ memory_ids: ["m1"],
147
+ include_related_intents: true,
148
+ include_related_tasks: true,
149
+ });
150
+ expect(slice.intents).toHaveLength(1);
151
+ expect(slice.intents[0].id).toBe("i1");
152
+ expect(slice.tasks).toHaveLength(1);
153
+ expect(slice.tasks[0].id).toBe("t1");
154
+ });
155
+
156
+ it("exports by intent id with related tasks", () => {
157
+ const { mem, intents, tasks } = buildState();
158
+ const slice = exportSlice(mem, intents, tasks, {
159
+ intent_ids: ["i1"],
160
+ include_related_tasks: true,
161
+ });
162
+ expect(slice.intents).toHaveLength(1);
163
+ expect(slice.tasks).toHaveLength(1);
164
+ });
165
+
166
+ it("empty export returns empty slice", () => {
167
+ const { mem, intents, tasks } = buildState();
168
+ const slice = exportSlice(mem, intents, tasks, {});
169
+ expect(slice.memories).toHaveLength(0);
170
+ expect(slice.edges).toHaveLength(0);
171
+ expect(slice.intents).toHaveLength(0);
172
+ expect(slice.tasks).toHaveLength(0);
173
+ });
174
+ });
175
+
176
+ // ============================================================
177
+ // Import — default (skip existing ids)
178
+ // ============================================================
179
+
180
+ describe("importSlice (default: skip existing)", () => {
181
+ it("imports into empty state", () => {
182
+ const { mem, intents, tasks } = buildState();
183
+ const slice = exportSlice(mem, intents, tasks, {
184
+ memory_ids: ["m1", "m2"],
185
+ include_related_intents: true,
186
+ include_related_tasks: true,
187
+ });
188
+
189
+ const result = importSlice(
190
+ createGraphState(),
191
+ createIntentState(),
192
+ createTaskState(),
193
+ slice,
194
+ );
195
+
196
+ expect(result.memState.items.size).toBe(2);
197
+ expect(result.intentState.intents.size).toBe(1);
198
+ expect(result.taskState.tasks.size).toBe(1);
199
+ expect(result.report.created.memories).toHaveLength(2);
200
+ expect(result.report.skipped.memories).toHaveLength(0);
201
+ });
202
+
203
+ it("skips existing ids without overwriting", () => {
204
+ const { mem, intents, tasks } = buildState();
205
+ const slice = exportSlice(mem, intents, tasks, {
206
+ memory_ids: ["m1", "m2"],
207
+ });
208
+
209
+ // import into state that already has m1
210
+ let targetMem = createGraphState();
211
+ targetMem = applyCommand(targetMem, {
212
+ type: "memory.create",
213
+ item: makeItem("m1", { authority: 0.99 }),
214
+ }).state;
215
+
216
+ const result = importSlice(
217
+ targetMem,
218
+ createIntentState(),
219
+ createTaskState(),
220
+ slice,
221
+ );
222
+
223
+ expect(result.memState.items.size).toBe(2);
224
+ expect(result.memState.items.get("m1")!.authority).toBe(0.99); // not overwritten
225
+ expect(result.report.created.memories).toEqual(["m2"]);
226
+ expect(result.report.skipped.memories).toEqual(["m1"]);
227
+ });
228
+
229
+ it("does not mutate original states", () => {
230
+ const empty = createGraphState();
231
+ const emptyIntents = createIntentState();
232
+ const emptyTasks = createTaskState();
233
+ const slice = {
234
+ memories: [makeItem("m1")],
235
+ edges: [],
236
+ intents: [],
237
+ tasks: [],
238
+ };
239
+
240
+ importSlice(empty, emptyIntents, emptyTasks, slice);
241
+
242
+ expect(empty.items.size).toBe(0);
243
+ });
244
+ });
245
+
246
+ // ============================================================
247
+ // Import — shallow compare + re-id
248
+ // ============================================================
249
+
250
+ describe("importSlice (shallow compare + re-id)", () => {
251
+ it("detects conflicts without re-id", () => {
252
+ let targetMem = createGraphState();
253
+ targetMem = applyCommand(targetMem, {
254
+ type: "memory.create",
255
+ item: makeItem("m1", { authority: 0.99 }),
256
+ }).state;
257
+
258
+ const slice = {
259
+ memories: [makeItem("m1", { authority: 0.1 })], // different
260
+ edges: [],
261
+ intents: [],
262
+ tasks: [],
263
+ };
264
+
265
+ const result = importSlice(
266
+ targetMem,
267
+ createIntentState(),
268
+ createTaskState(),
269
+ slice,
270
+ { shallowCompareExisting: true },
271
+ );
272
+
273
+ expect(result.report.conflicts.memories).toEqual(["m1"]);
274
+ expect(result.report.created.memories).toHaveLength(0);
275
+ expect(result.memState.items.get("m1")!.authority).toBe(0.99); // unchanged
276
+ });
277
+
278
+ it("skips silently when shallow-equal", () => {
279
+ const item = makeItem("m1");
280
+ let targetMem = createGraphState();
281
+ targetMem = applyCommand(targetMem, {
282
+ type: "memory.create",
283
+ item,
284
+ }).state;
285
+
286
+ const slice = {
287
+ memories: [item], // identical
288
+ edges: [],
289
+ intents: [],
290
+ tasks: [],
291
+ };
292
+
293
+ const result = importSlice(
294
+ targetMem,
295
+ createIntentState(),
296
+ createTaskState(),
297
+ slice,
298
+ { shallowCompareExisting: true },
299
+ );
300
+
301
+ expect(result.report.skipped.memories).toEqual(["m1"]);
302
+ expect(result.report.conflicts.memories).toHaveLength(0);
303
+ });
304
+
305
+ it("re-ids on difference when enabled", () => {
306
+ let targetMem = createGraphState();
307
+ targetMem = applyCommand(targetMem, {
308
+ type: "memory.create",
309
+ item: makeItem("m1", { authority: 0.99 }),
310
+ }).state;
311
+
312
+ const slice = {
313
+ memories: [makeItem("m1", { authority: 0.1 })],
314
+ edges: [],
315
+ intents: [],
316
+ tasks: [],
317
+ };
318
+
319
+ const result = importSlice(
320
+ targetMem,
321
+ createIntentState(),
322
+ createTaskState(),
323
+ slice,
324
+ { shallowCompareExisting: true, reIdOnDifference: true },
325
+ );
326
+
327
+ expect(result.memState.items.size).toBe(2); // original + re-id'd
328
+ expect(result.memState.items.get("m1")!.authority).toBe(0.99); // original untouched
329
+ expect(result.report.created.memories).toHaveLength(1);
330
+ const newId = result.report.created.memories[0];
331
+ expect(newId).not.toBe("m1");
332
+ expect(result.memState.items.get(newId)!.authority).toBe(0.1);
333
+ });
334
+ });
335
+
336
+ // ============================================================
337
+ // Round-trip
338
+ // ============================================================
339
+
340
+ describe("export + import round-trip", () => {
341
+ it("round-trips a full chain into empty state", () => {
342
+ const { mem, intents, tasks } = buildState();
343
+ const slice = exportSlice(mem, intents, tasks, {
344
+ memory_ids: ["m1"],
345
+ include_children: true,
346
+ include_related_intents: true,
347
+ include_related_tasks: true,
348
+ });
349
+
350
+ const result = importSlice(
351
+ createGraphState(),
352
+ createIntentState(),
353
+ createTaskState(),
354
+ slice,
355
+ );
356
+
357
+ expect(result.memState.items.size).toBe(3); // m1, m2, m3
358
+ expect(result.memState.edges.size).toBe(2); // e1, e2
359
+ expect(result.intentState.intents.size).toBe(1);
360
+ expect(result.taskState.tasks.size).toBe(1);
361
+ expect(result.report.created.memories.sort()).toEqual(["m1", "m2", "m3"]);
362
+ });
363
+
364
+ it("JSON serializable round-trip", () => {
365
+ const { mem, intents, tasks } = buildState();
366
+ const slice = exportSlice(mem, intents, tasks, {
367
+ memory_ids: ["m1", "m2"],
368
+ include_related_intents: true,
369
+ include_related_tasks: true,
370
+ });
371
+
372
+ const json = JSON.stringify(slice);
373
+ const parsed = JSON.parse(json);
374
+
375
+ const result = importSlice(
376
+ createGraphState(),
377
+ createIntentState(),
378
+ createTaskState(),
379
+ parsed,
380
+ );
381
+
382
+ expect(result.memState.items.size).toBe(2);
383
+ expect(result.intentState.intents.size).toBe(1);
384
+ });
385
+ });
@@ -0,0 +1,231 @@
1
+ import { describe, it, expect, expectTypeOf } from "vitest";
2
+ import type {
3
+ MemoryItem,
4
+ Edge,
5
+ EventEnvelope,
6
+ GraphState,
7
+ MemoryCommand,
8
+ MemoryLifecycleEvent,
9
+ MemoryFilter,
10
+ } from "../src/types.js";
11
+
12
+ describe("MemoryItem", () => {
13
+ it("accepts a valid literal", () => {
14
+ const item: MemoryItem = {
15
+ id: "01HV5W1YF3F8R9H1M6V3X6X8A0",
16
+ scope: "user:laz/general",
17
+ kind: "assertion",
18
+ content: { key: "theme", value: "dark" },
19
+ author: "user:laz",
20
+ source_kind: "user_explicit",
21
+ authority: 0.99,
22
+ };
23
+ expect(item.id).toBe("01HV5W1YF3F8R9H1M6V3X6X8A0");
24
+ });
25
+
26
+ it("accepts optional fields", () => {
27
+ const item: MemoryItem = {
28
+ id: "m1",
29
+ scope: "test",
30
+ kind: "observation",
31
+ content: {},
32
+ author: "test",
33
+ source_kind: "observed",
34
+ authority: 0.5,
35
+ conviction: 0.8,
36
+ importance: 0.3,
37
+ meta: { agent_id: "agent:x", session_id: "s1", custom: true },
38
+ };
39
+ expect(item.conviction).toBe(0.8);
40
+ expect(item.meta?.custom).toBe(true);
41
+ });
42
+
43
+ it("accepts arbitrary kind and source_kind strings", () => {
44
+ const item: MemoryItem = {
45
+ id: "m2",
46
+ scope: "test",
47
+ kind: "custom_kind",
48
+ content: {},
49
+ author: "test",
50
+ source_kind: "custom_source",
51
+ authority: 0.5,
52
+ };
53
+ expect(item.kind).toBe("custom_kind");
54
+ expect(item.source_kind).toBe("custom_source");
55
+ });
56
+ });
57
+
58
+ describe("Edge", () => {
59
+ it("accepts a valid literal", () => {
60
+ const edge: Edge = {
61
+ edge_id: "e1",
62
+ from: "m1",
63
+ to: "m2",
64
+ kind: "DERIVED_FROM",
65
+ author: "system:rule_x",
66
+ source_kind: "derived_deterministic",
67
+ authority: 0.9,
68
+ active: true,
69
+ };
70
+ expect(edge.kind).toBe("DERIVED_FROM");
71
+ });
72
+
73
+ it("accepts optional weight and meta", () => {
74
+ const edge: Edge = {
75
+ edge_id: "e2",
76
+ from: "m1",
77
+ to: "m3",
78
+ kind: "SUPPORTS",
79
+ weight: 0.7,
80
+ author: "agent:reasoner",
81
+ source_kind: "agent_inferred",
82
+ authority: 0.6,
83
+ active: true,
84
+ meta: { reason: "correlation" },
85
+ };
86
+ expect(edge.weight).toBe(0.7);
87
+ });
88
+ });
89
+
90
+ describe("MemoryCommand discriminated union", () => {
91
+ it("narrows memory.create to access cmd.item", () => {
92
+ const cmd: MemoryCommand = {
93
+ type: "memory.create",
94
+ item: {
95
+ id: "m1",
96
+ scope: "test",
97
+ kind: "observation",
98
+ content: {},
99
+ author: "test",
100
+ source_kind: "observed",
101
+ authority: 1,
102
+ },
103
+ };
104
+ if (cmd.type === "memory.create") {
105
+ expectTypeOf(cmd.item).toEqualTypeOf<MemoryItem>();
106
+ expect(cmd.item.id).toBe("m1");
107
+ }
108
+ });
109
+
110
+ it("narrows memory.update to access cmd.partial and cmd.item_id", () => {
111
+ const cmd: MemoryCommand = {
112
+ type: "memory.update",
113
+ item_id: "m1",
114
+ partial: { authority: 0.5 },
115
+ author: "system:tuner",
116
+ };
117
+ if (cmd.type === "memory.update") {
118
+ expectTypeOf(cmd.item_id).toBeString();
119
+ expectTypeOf(cmd.partial).toEqualTypeOf<Partial<MemoryItem>>();
120
+ }
121
+ });
122
+
123
+ it("narrows edge.create to access cmd.edge", () => {
124
+ const cmd: MemoryCommand = {
125
+ type: "edge.create",
126
+ edge: {
127
+ edge_id: "e1",
128
+ from: "m1",
129
+ to: "m2",
130
+ kind: "SUPPORTS",
131
+ author: "test",
132
+ source_kind: "observed",
133
+ authority: 1,
134
+ active: true,
135
+ },
136
+ };
137
+ if (cmd.type === "edge.create") {
138
+ expectTypeOf(cmd.edge).toEqualTypeOf<Edge>();
139
+ }
140
+ });
141
+ });
142
+
143
+ describe("EventEnvelope", () => {
144
+ it("types payload generically", () => {
145
+ const env: EventEnvelope<{ item: MemoryItem }> = {
146
+ id: "ev1",
147
+ namespace: "memory",
148
+ type: "state.memory",
149
+ ts: "2026-04-10T19:30:00.010Z",
150
+ payload: {
151
+ item: {
152
+ id: "m1",
153
+ scope: "test",
154
+ kind: "observation",
155
+ content: {},
156
+ author: "test",
157
+ source_kind: "observed",
158
+ authority: 1,
159
+ },
160
+ },
161
+ };
162
+ expectTypeOf(env.payload.item).toEqualTypeOf<MemoryItem>();
163
+ expect(env.namespace).toBe("memory");
164
+ });
165
+
166
+ it("accepts optional trace_id", () => {
167
+ const env: EventEnvelope<null> = {
168
+ id: "ev2",
169
+ namespace: "memory",
170
+ type: "test",
171
+ ts: "2026-01-01T00:00:00Z",
172
+ trace_id: "trace-123",
173
+ payload: null,
174
+ };
175
+ expect(env.trace_id).toBe("trace-123");
176
+ });
177
+ });
178
+
179
+ describe("GraphState", () => {
180
+ it("constructs with empty Maps", () => {
181
+ const state: GraphState = { items: new Map(), edges: new Map() };
182
+ expect(state.items.size).toBe(0);
183
+ expect(state.edges.size).toBe(0);
184
+ });
185
+ });
186
+
187
+ describe("MemoryLifecycleEvent", () => {
188
+ it("has namespace memory and dot-notation type", () => {
189
+ const event: MemoryLifecycleEvent = {
190
+ namespace: "memory",
191
+ type: "memory.created",
192
+ item: {
193
+ id: "m1",
194
+ scope: "test",
195
+ kind: "observation",
196
+ content: {},
197
+ author: "test",
198
+ source_kind: "observed",
199
+ authority: 1,
200
+ },
201
+ cause_type: "memory.create",
202
+ };
203
+ expect(event.namespace).toBe("memory");
204
+ expect(event.type).toBe("memory.created");
205
+ });
206
+ });
207
+
208
+ describe("MemoryFilter", () => {
209
+ it("accepts an empty object (all fields optional)", () => {
210
+ const filter: MemoryFilter = {};
211
+ expect(filter).toEqual({});
212
+ });
213
+
214
+ it("accepts all fields including range", () => {
215
+ const filter: MemoryFilter = {
216
+ scope: "user:laz/general",
217
+ author: "user:laz",
218
+ kind: "observation",
219
+ source_kind: "observed",
220
+ range: {
221
+ authority: { min: 0.3, max: 0.9 },
222
+ conviction: { min: 0.2 },
223
+ importance: { max: 0.7 },
224
+ },
225
+ not: { or: [{ kind: "simulation" }, { kind: "hypothesis" }] },
226
+ meta: { agent_id: "agent:foo" },
227
+ or: [{ kind: "trait" }],
228
+ };
229
+ expect(filter.scope).toBe("user:laz/general");
230
+ });
231
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ "target": "ESNext",
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+ "outDir": "dist",
11
+ "rootDir": "src",
12
+ "skipLibCheck": true,
13
+ "esModuleInterop": true,
14
+ "forceConsistentCasingInFileNames": true
15
+ },
16
+ "include": ["src"],
17
+ "exclude": ["node_modules", "dist", "tests"]
18
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["tests/**/*.test.ts"],
6
+ },
7
+ });