@yamo/memory-mesh 3.2.2 → 3.2.4

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
@@ -47,14 +47,46 @@ The installer will:
47
47
 
48
48
  ### CLI
49
49
 
50
+ The `memory-mesh` CLI provides seven commands for full subconscious CRUD and recall:
51
+
50
52
  ```bash
51
53
  # Store a memory (automatically scrubbed & embedded)
52
- node tools/memory_mesh.mjs store --content "My important memory" --type "insight"
54
+ memory-mesh store --content "My important memory" --type insight
55
+
56
+ # Store with full provenance metadata
57
+ memory-mesh store -c "Insight text" -t decision -r "Improves latency" -h "Caching reduces p95"
58
+
59
+ # Bulk-ingest a directory (recursive, by extension)
60
+ memory-mesh pull ./docs --extension ".md,.yamo" --type documentation
61
+
62
+ # Semantic search
63
+ memory-mesh search "query about orchestration" --limit 5
64
+
65
+ # Retrieve a specific record by ID
66
+ memory-mesh get --id mem_abc123
53
67
 
54
- # Search memories
55
- node tools/memory_mesh.mjs search "query" --limit 5
68
+ # Delete a record by ID
69
+ memory-mesh delete --id mem_abc123
70
+
71
+ # Synthesize insights from recent memories
72
+ memory-mesh reflect --topic "bugs" --lookback 10
73
+
74
+ # Database health and statistics
75
+ memory-mesh stats
56
76
  ```
57
77
 
78
+ **Command Reference:**
79
+
80
+ | Command | Key Options | Description |
81
+ |---------|-------------|-------------|
82
+ | `store` | `-c/--content` (required), `-t/--type`, `-r/--rationale`, `-h/--hypothesis` | Persist a semantic memory |
83
+ | `pull` | `<path>` (required), `-e/--extension`, `-t/--type` | Bulk-ingest a directory |
84
+ | `search` | `<query>` (required), `-l/--limit` | Semantic recall |
85
+ | `get` | `-i/--id` (required) | Fetch a record by ID |
86
+ | `delete` | `-i/--id` (required) | Remove a record by ID |
87
+ | `reflect` | `-t/--topic`, `-l/--lookback` | Synthesize insights from memories |
88
+ | `stats` | — | DB health, count, embedding model |
89
+
58
90
  ### Node.js API
59
91
 
60
92
  ```javascript
@@ -173,7 +205,7 @@ docker run -v $(pwd)/data:/app/runtime/data \
173
205
 
174
206
  ## About YAMO Protocol
175
207
 
176
- Memory Mesh is built on the **YAMO (Yet Another Markup for Orchestration) Protocol** - a structured language for transparent AI agent collaboration with immutable provenance tracking.
208
+ Memory Mesh is built on the **YAMO (Yet Another Model Ontology) Protocol** - a structured language for transparent AI agent collaboration with immutable provenance tracking.
177
209
 
178
210
  **YAMO Protocol Features:**
179
211
  - **Structured Agent Workflows**: Semicolon-terminated constraints, explicit handoff chains
@@ -21,7 +21,7 @@ const program = new Command();
21
21
  program
22
22
  .name('memory-mesh')
23
23
  .description('YAMO Semantic Subconscious - Protocol-Native CLI')
24
- .version('3.2.0');
24
+ .version('3.2.3');
25
25
 
26
26
  // Helper for beautiful logging
27
27
  const ui = {
@@ -194,4 +194,85 @@ program
194
194
  }
195
195
  });
196
196
 
197
+ // 5. Get Command
198
+ program
199
+ .command('get')
200
+ .description('Retrieve a memory record by ID')
201
+ .requiredOption('-i, --id <id>', 'Memory record ID')
202
+ .action(async (options) => {
203
+ const mesh = new MemoryMesh();
204
+ try {
205
+ const record = await mesh.get(options.id);
206
+ if (!record) {
207
+ ui.warn(`Record not found: ${options.id}`);
208
+ process.exit(1);
209
+ }
210
+ const meta = typeof record.metadata === 'string' ? JSON.parse(record.metadata) : (record.metadata || {});
211
+ ui.header(`Memory ${options.id}`);
212
+ console.log(`${pc.bold('ID:')} ${pc.dim(record.id)}`);
213
+ console.log(`${pc.bold('Type:')} ${pc.dim(meta.type || 'event')}`);
214
+ console.log(`${pc.bold('Created:')} ${pc.dim(record.created_at)}`);
215
+ console.log(`\n${pc.white(record.content)}`);
216
+ } catch (err) {
217
+ ui.error(`Get failed: ${err.message}`);
218
+ process.exit(1);
219
+ } finally {
220
+ await mesh.close();
221
+ }
222
+ });
223
+
224
+ // 6. Delete Command
225
+ program
226
+ .command('delete')
227
+ .description('Permanently remove a memory record by ID')
228
+ .requiredOption('-i, --id <id>', 'Memory record ID to delete')
229
+ .action(async (options) => {
230
+ const mesh = new MemoryMesh();
231
+ try {
232
+ await mesh.delete(options.id);
233
+ ui.success(`Deleted record ${pc.bold(options.id)}`);
234
+ } catch (err) {
235
+ ui.error(`Delete failed: ${err.message}`);
236
+ process.exit(1);
237
+ } finally {
238
+ await mesh.close();
239
+ }
240
+ });
241
+
242
+ // 7. Reflect Command
243
+ program
244
+ .command('reflect')
245
+ .description('Synthesize insights from stored memories')
246
+ .option('-t, --topic <topic>', 'Focus the reflection on a specific topic')
247
+ .option('-l, --lookback <number>', 'Number of memories to review', '10')
248
+ .action(async (options) => {
249
+ const mesh = new MemoryMesh();
250
+ try {
251
+ ui.info(`Reflecting on ${options.topic ? `"${pc.italic(options.topic)}"` : 'recent memories'}...`);
252
+ const result = await mesh.reflect({
253
+ topic: options.topic,
254
+ lookback: parseInt(options.lookback),
255
+ });
256
+ ui.header('Reflection');
257
+ if (result.reflection) {
258
+ console.log(pc.white(result.reflection));
259
+ console.log(`\n${pc.bold('Confidence:')} ${pc.cyan((result.confidence * 100).toFixed(0))}%`);
260
+ } else {
261
+ console.log(pc.dim(`Reviewed ${result.count} memories${result.topic ? ` on topic: ${result.topic}` : ''}`));
262
+ console.log(`\n${pc.bold('Prompt for LLM:')}\n${pc.white(result.prompt)}`);
263
+ if (result.context?.length) {
264
+ console.log('');
265
+ result.context.forEach((m, i) => {
266
+ console.log(`${pc.cyan(`Memory ${i + 1}:`)} ${pc.white(m.content.substring(0, 200))}${m.content.length > 200 ? '...' : ''}`);
267
+ });
268
+ }
269
+ }
270
+ } catch (err) {
271
+ ui.error(`Reflect failed: ${err.message}`);
272
+ process.exit(1);
273
+ } finally {
274
+ await mesh.close();
275
+ }
276
+ });
277
+
197
278
  program.parse();
@@ -288,8 +288,16 @@ export class MemoryMesh {
288
288
  const skillSchema = createSynthesizedSkillSchema(this.vectorDimension);
289
289
  this.skillTable = await this.client.db.createTable("synthesized_skills", [], {
290
290
  schema: skillSchema,
291
+ storageOptions: { new_table_data_storage_version: "stable" },
291
292
  });
292
293
  }
294
+ // Migrate manifest paths to V2 layout (idempotent)
295
+ try {
296
+ await this.skillTable.migrateManifestPathsV2();
297
+ }
298
+ catch {
299
+ // Already migrated or not a local table — ignore
300
+ }
293
301
  if (process.env.YAMO_DEBUG === "true") {
294
302
  logger.debug("YAMO blocks and synthesized skills tables initialized");
295
303
  }
@@ -1808,6 +1816,23 @@ export async function run() {
1808
1816
  else if (action === "stats") {
1809
1817
  process.stdout.write(`[MemoryMesh] Database Statistics:\n${JSON.stringify({ status: "ok", stats: await mesh.stats() }, null, 2)}\n`);
1810
1818
  }
1819
+ else if (action === "get") {
1820
+ const record = await mesh.get(input.id);
1821
+ if (!record) {
1822
+ process.stdout.write(`[MemoryMesh] Record not found: ${input.id}\n${JSON.stringify({ status: "not_found", id: input.id })}\n`);
1823
+ }
1824
+ else {
1825
+ process.stdout.write(`[MemoryMesh] Record ${record.id}\n${JSON.stringify({ status: "ok", record }, null, 2)}\n`);
1826
+ }
1827
+ }
1828
+ else if (action === "delete") {
1829
+ await mesh.delete(input.id);
1830
+ process.stdout.write(`[MemoryMesh] Deleted record ${input.id}\n${JSON.stringify({ status: "ok", id: input.id })}\n`);
1831
+ }
1832
+ else if (action === "reflect") {
1833
+ const result = await mesh.reflect({ topic: input.topic, lookback: input.lookback });
1834
+ process.stdout.write(`[MemoryMesh] Reflection complete.\n${JSON.stringify({ status: "ok", result }, null, 2)}\n`);
1835
+ }
1811
1836
  else {
1812
1837
  logger.error({ action }, "Unknown action");
1813
1838
  process.exit(1);
@@ -320,8 +320,16 @@ export class MemoryMesh {
320
320
  const skillSchema = createSynthesizedSkillSchema(this.vectorDimension);
321
321
  this.skillTable = await this.client.db.createTable("synthesized_skills", [], {
322
322
  schema: skillSchema,
323
+ storageOptions: { new_table_data_storage_version: "stable" },
323
324
  });
324
325
  }
326
+ // Migrate manifest paths to V2 layout (idempotent)
327
+ try {
328
+ await this.skillTable.migrateManifestPathsV2();
329
+ }
330
+ catch {
331
+ // Already migrated or not a local table — ignore
332
+ }
325
333
  if (process.env.YAMO_DEBUG === "true") {
326
334
  logger.debug("YAMO blocks and synthesized skills tables initialized");
327
335
  }
@@ -1895,6 +1903,22 @@ export async function run() {
1895
1903
  else if (action === "stats") {
1896
1904
  process.stdout.write(`[MemoryMesh] Database Statistics:\n${JSON.stringify({ status: "ok", stats: await mesh.stats() }, null, 2)}\n`);
1897
1905
  }
1906
+ else if (action === "get") {
1907
+ const record = await mesh.get(input.id);
1908
+ if (!record) {
1909
+ process.stdout.write(`[MemoryMesh] Record not found: ${input.id}\n${JSON.stringify({ status: "not_found", id: input.id })}\n`);
1910
+ } else {
1911
+ process.stdout.write(`[MemoryMesh] Record ${record.id}\n${JSON.stringify({ status: "ok", record }, null, 2)}\n`);
1912
+ }
1913
+ }
1914
+ else if (action === "delete") {
1915
+ await mesh.delete(input.id);
1916
+ process.stdout.write(`[MemoryMesh] Deleted record ${input.id}\n${JSON.stringify({ status: "ok", id: input.id })}\n`);
1917
+ }
1918
+ else if (action === "reflect") {
1919
+ const result = await mesh.reflect({ topic: input.topic, lookback: input.lookback });
1920
+ process.stdout.write(`[MemoryMesh] Reflection complete.\n${JSON.stringify({ status: "ok", result }, null, 2)}\n`);
1921
+ }
1898
1922
  else {
1899
1923
  logger.error({ action }, "Unknown action");
1900
1924
  process.exit(1);
@@ -57,6 +57,14 @@ export declare function createSynthesizedSkillSchema(vectorDim?: number): arrow.
57
57
  * @returns {boolean} True if V2 schema detected
58
58
  */
59
59
  export declare function isSchemaV2(schema: any): any;
60
+ /**
61
+ * Migrate an existing table to V2:
62
+ * 1. Migrate manifest paths to V2 layout (efficient versioning, idempotent)
63
+ * 2. Add nullable V2 columns to memory_entries-style tables if not already present
64
+ *
65
+ * Safe to call on any table — non-memory tables skip the schema column additions.
66
+ */
67
+ export declare function migrateTableV2(table: any): Promise<void>;
60
68
  /**
61
69
  * Memory table schema using Apache Arrow format (default 384 dimensions)
62
70
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -113,6 +121,7 @@ declare const _default: {
113
121
  createMemorySchema: typeof createMemorySchema;
114
122
  createMemorySchemaV2: typeof createMemorySchemaV2;
115
123
  isSchemaV2: typeof isSchemaV2;
124
+ migrateTableV2: typeof migrateTableV2;
116
125
  getEmbeddingDimension: typeof getEmbeddingDimension;
117
126
  DEFAULT_VECTOR_DIMENSION: number;
118
127
  EMBEDDING_DIMENSIONS: {
@@ -112,6 +112,47 @@ export function createSynthesizedSkillSchema(vectorDim = DEFAULT_VECTOR_DIMENSIO
112
112
  export function isSchemaV2(schema) {
113
113
  return schema.fields.some((f) => f.name === "session_id");
114
114
  }
115
+ /**
116
+ * Migrate an existing table to V2:
117
+ * 1. Migrate manifest paths to V2 layout (efficient versioning, idempotent)
118
+ * 2. Add nullable V2 columns to memory_entries-style tables if not already present
119
+ *
120
+ * Safe to call on any table — non-memory tables skip the schema column additions.
121
+ */
122
+ export async function migrateTableV2(table) {
123
+ // Step 1: manifest path migration (idempotent on already-migrated tables)
124
+ try {
125
+ await table.migrateManifestPathsV2();
126
+ }
127
+ catch {
128
+ // Already migrated or not a local table — ignore
129
+ }
130
+ // Step 2: add V2 schema columns if this is a memory_entries-style table (V1)
131
+ // Guard: schema() may not exist on mock tables in tests
132
+ if (typeof table.schema !== "function")
133
+ return;
134
+ let schema;
135
+ try {
136
+ schema = await table.schema();
137
+ }
138
+ catch {
139
+ return; // Can't inspect schema — skip
140
+ }
141
+ if (isSchemaV2(schema))
142
+ return;
143
+ // Only add V2 columns if the table has the V1 memory_entries shape
144
+ const fieldNames = schema.fields.map((f) => f.name);
145
+ if (!fieldNames.includes("content") || !fieldNames.includes("vector"))
146
+ return;
147
+ await table.addColumns([
148
+ { name: "session_id", valueSql: "cast(null as string)" },
149
+ { name: "agent_id", valueSql: "cast(null as string)" },
150
+ { name: "memory_type", valueSql: "cast(null as string)" },
151
+ { name: "importance_score", valueSql: "cast(null as float)" },
152
+ { name: "access_count", valueSql: "cast(null as int)" },
153
+ { name: "last_accessed", valueSql: "cast(null as timestamp)" },
154
+ ]);
155
+ }
115
156
  /**
116
157
  * Memory table schema using Apache Arrow format (default 384 dimensions)
117
158
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -153,16 +194,21 @@ export async function createMemoryTable(db, tableName = "memory_entries") {
153
194
  */
154
195
  export async function createMemoryTableWithDimension(db, tableName, vectorDim) {
155
196
  try {
156
- // Check if table already exists
157
197
  const existingTables = await db.tableNames();
198
+ let table;
158
199
  if (existingTables.includes(tableName)) {
159
- return await db.openTable(tableName);
200
+ table = await db.openTable(tableName);
201
+ }
202
+ else {
203
+ // New tables use V2 schema and stable storage format
204
+ const schema = createMemorySchemaV2(vectorDim);
205
+ table = await db.createTable(tableName, [], {
206
+ schema,
207
+ storageOptions: { new_table_data_storage_version: "stable" },
208
+ });
160
209
  }
161
- // Create schema with specified dimension
162
- const schema = createMemorySchema(vectorDim);
163
- // Create table with schema
164
- // LanceDB v0.23.0+ accepts empty array as initial data with schema option
165
- const table = await db.createTable(tableName, [], { schema }); // Cast to any because lancedb types might be strict about options
210
+ // Migrate existing tables to V2 (manifest paths + schema columns, idempotent)
211
+ await migrateTableV2(table);
166
212
  return table;
167
213
  }
168
214
  catch (error) {
@@ -178,6 +224,7 @@ export default {
178
224
  createMemorySchema,
179
225
  createMemorySchemaV2,
180
226
  isSchemaV2,
227
+ migrateTableV2,
181
228
  getEmbeddingDimension,
182
229
  DEFAULT_VECTOR_DIMENSION,
183
230
  EMBEDDING_DIMENSIONS,
@@ -112,6 +112,44 @@ export function createSynthesizedSkillSchema(vectorDim = DEFAULT_VECTOR_DIMENSIO
112
112
  export function isSchemaV2(schema) {
113
113
  return schema.fields.some((f) => f.name === "session_id");
114
114
  }
115
+ /**
116
+ * Migrate an existing table to V2:
117
+ * 1. Migrate manifest paths to V2 layout (efficient versioning, idempotent)
118
+ * 2. Add nullable V2 columns to memory_entries-style tables if not already present
119
+ *
120
+ * Safe to call on any table — non-memory tables skip the schema column additions.
121
+ */
122
+ export async function migrateTableV2(table) {
123
+ // Step 1: manifest path migration (idempotent on already-migrated tables)
124
+ try {
125
+ await table.migrateManifestPathsV2();
126
+ }
127
+ catch {
128
+ // Already migrated or not a local table — ignore
129
+ }
130
+ // Step 2: add V2 schema columns if this is a memory_entries-style table (V1)
131
+ // Guard: schema() may not exist on mock tables in tests
132
+ if (typeof table.schema !== "function") return;
133
+ let schema;
134
+ try {
135
+ schema = await table.schema();
136
+ }
137
+ catch {
138
+ return; // Can't inspect schema — skip
139
+ }
140
+ if (isSchemaV2(schema)) return;
141
+ // Only add V2 columns if the table has the V1 memory_entries shape
142
+ const fieldNames = schema.fields.map((f) => f.name);
143
+ if (!fieldNames.includes("content") || !fieldNames.includes("vector")) return;
144
+ await table.addColumns([
145
+ { name: "session_id", valueSql: "cast(null as string)" },
146
+ { name: "agent_id", valueSql: "cast(null as string)" },
147
+ { name: "memory_type", valueSql: "cast(null as string)" },
148
+ { name: "importance_score", valueSql: "cast(null as float)" },
149
+ { name: "access_count", valueSql: "cast(null as int)" },
150
+ { name: "last_accessed", valueSql: "cast(null as timestamp)" },
151
+ ]);
152
+ }
115
153
  /**
116
154
  * Memory table schema using Apache Arrow format (default 384 dimensions)
117
155
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -153,16 +191,21 @@ export async function createMemoryTable(db, tableName = "memory_entries") {
153
191
  */
154
192
  export async function createMemoryTableWithDimension(db, tableName, vectorDim) {
155
193
  try {
156
- // Check if table already exists
157
194
  const existingTables = await db.tableNames();
195
+ let table;
158
196
  if (existingTables.includes(tableName)) {
159
- return await db.openTable(tableName);
197
+ table = await db.openTable(tableName);
198
+ }
199
+ else {
200
+ // New tables use V2 schema and stable storage format
201
+ const schema = createMemorySchemaV2(vectorDim);
202
+ table = await db.createTable(tableName, [], {
203
+ schema,
204
+ storageOptions: { new_table_data_storage_version: "stable" },
205
+ });
160
206
  }
161
- // Create schema with specified dimension
162
- const schema = createMemorySchema(vectorDim);
163
- // Create table with schema
164
- // LanceDB v0.23.0+ accepts empty array as initial data with schema option
165
- const table = await db.createTable(tableName, [], { schema }); // Cast to any because lancedb types might be strict about options
207
+ // Migrate existing tables to V2 (manifest paths + schema columns, idempotent)
208
+ await migrateTableV2(table);
166
209
  return table;
167
210
  }
168
211
  catch (error) {
@@ -178,6 +221,7 @@ export default {
178
221
  createMemorySchema,
179
222
  createMemorySchemaV2,
180
223
  isSchemaV2,
224
+ migrateTableV2,
181
225
  getEmbeddingDimension,
182
226
  DEFAULT_VECTOR_DIMENSION,
183
227
  EMBEDDING_DIMENSIONS,
@@ -40,15 +40,25 @@ export function createYamoSchema() {
40
40
  */
41
41
  export async function createYamoTable(db, tableName = "yamo_blocks") {
42
42
  try {
43
- // Check if table already exists
44
43
  const existingTables = await db.tableNames();
44
+ let table;
45
45
  if (existingTables.includes(tableName)) {
46
- // Table exists, open it
47
- return await db.openTable(tableName);
46
+ table = await db.openTable(tableName);
47
+ }
48
+ else {
49
+ const schema = createYamoSchema();
50
+ table = await db.createTable(tableName, [], {
51
+ schema,
52
+ storageOptions: { new_table_data_storage_version: "stable" },
53
+ });
54
+ }
55
+ // Migrate manifest paths to V2 layout (idempotent)
56
+ try {
57
+ await table.migrateManifestPathsV2();
58
+ }
59
+ catch {
60
+ // Already migrated or not a local table — ignore
48
61
  }
49
- // Create new table with YAMO schema
50
- const schema = createYamoSchema();
51
- const table = await db.createTable(tableName, [], { schema });
52
62
  return table;
53
63
  }
54
64
  catch (error) {
@@ -40,15 +40,25 @@ export function createYamoSchema() {
40
40
  */
41
41
  export async function createYamoTable(db, tableName = "yamo_blocks") {
42
42
  try {
43
- // Check if table already exists
44
43
  const existingTables = await db.tableNames();
44
+ let table;
45
45
  if (existingTables.includes(tableName)) {
46
- // Table exists, open it
47
- return await db.openTable(tableName);
46
+ table = await db.openTable(tableName);
47
+ }
48
+ else {
49
+ const schema = createYamoSchema();
50
+ table = await db.createTable(tableName, [], {
51
+ schema,
52
+ storageOptions: { new_table_data_storage_version: "stable" },
53
+ });
54
+ }
55
+ // Migrate manifest paths to V2 layout (idempotent)
56
+ try {
57
+ await table.migrateManifestPathsV2();
58
+ }
59
+ catch {
60
+ // Already migrated or not a local table — ignore
48
61
  }
49
- // Create new table with YAMO schema
50
- const schema = createYamoSchema();
51
- const table = await db.createTable(tableName, [], { schema });
52
62
  return table;
53
63
  }
54
64
  catch (error) {
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@yamo/memory-mesh",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "description": "Portable semantic memory system with Layer 0 Scrubber for YAMO agents (v3 Singularity Edition)",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/yamo-protocol/yamo-memory-mesh"
8
+ },
5
9
  "type": "module",
6
10
  "main": "lib/memory/index.js",
7
11
  "types": "lib/memory/index.d.ts",
@@ -23,16 +27,16 @@
23
27
  "prepublishOnly": "npm run build"
24
28
  },
25
29
  "dependencies": {
26
- "@lancedb/lancedb": "^0.23.0",
27
- "@xenova/transformers": "^2.17.0",
28
- "apache-arrow": "^17.0.0",
30
+ "@lancedb/lancedb": "^0.26.2",
31
+ "@xenova/transformers": "^2.17.2",
32
+ "apache-arrow": "^18.1.0",
29
33
  "commander": "^14.0.3",
30
- "onnxruntime-node": "^1.18.0",
34
+ "onnxruntime-node": "^1.24.3",
31
35
  "pino": "^10.3.1",
32
36
  "pino-pretty": "^13.1.3",
33
37
  "cli-progress": "^3.12.0",
34
38
  "picocolors": "^1.1.1",
35
- "glob": "^13.0.5"
39
+ "glob": "^13.0.6"
36
40
  },
37
41
  "author": "Soverane Labs",
38
42
  "license": "MIT",
@@ -40,9 +44,9 @@
40
44
  "node": ">=18.0.0"
41
45
  },
42
46
  "devDependencies": {
43
- "@types/node": "^25.0.9",
47
+ "@types/node": "^25.4.0",
44
48
  "cohere-ai": "^7.20.0",
45
- "openai": "^6.16.0",
49
+ "openai": "^6.27.0",
46
50
  "typescript": "^5.9.3"
47
51
  }
48
52
  }