plugmem 0.5.0 → 0.6.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 (4) hide show
  1. package/README.md +134 -13
  2. package/index.d.ts +199 -0
  3. package/index.js +3 -1
  4. package/package.json +8 -8
package/README.md CHANGED
@@ -5,10 +5,11 @@
5
5
  > Claude models, in roughly equal measure. Expect non-professional design
6
6
  > choices, rough edges, broken behavior, or mistakes. Use it at your own risk.
7
7
 
8
- A memory database for LLM agents, embedded in your Node process. It stores short
9
- facts and answers a query with a ranked block of text ready to put in a prompt.
8
+ An embeddable bitemporal memory database for local-first applications and
9
+ agents, embedded in your Node process. It stores short facts and answers a
10
+ query with ranked facts and edges plus an optional bounded rendered block.
10
11
 
11
- One file on disk, no server, no daemon. It links into your process the way
12
+ File-backed on disk, no server, no daemon. It links into your process the way
12
13
  SQLite does: the engine is [`plugmem-host`](https://docs.rs/plugmem-host/latest)
13
14
  compiled to a native addon through [napi-rs](https://napi.rs), so there is no
14
15
  WebAssembly copy of the file in RAM and no 4 GiB ceiling. Runs on Node, Deno and
@@ -159,6 +160,7 @@ const res = await db.recall({
159
160
  tags: ["work"], // filter: a fact must carry all of these
160
161
  k: 10, // cap the number of facts
161
162
  tokenBudget: 400, // cap the size of the block — your context budget
163
+ graphDepth: 3, // how far to walk from the anchors (default 2)
162
164
  });
163
165
 
164
166
  res.rendered; // string, prompt-ready
@@ -206,6 +208,8 @@ only moves arguments and results across the boundary.
206
208
  | `path()` | the file this handle resolved to (sync) |
207
209
  | `export()` | every open fact as one array (async, unbounded — see below) |
208
210
  | `exportPage(cursor?)` | the same data in bounded pages of 128 (async) |
211
+ | `exportEdges(onBatch)` | every current edge, streamed in batches (async) |
212
+ | `configWarnings()` | anything in `config.toml` nothing claimed (sync) |
209
213
 
210
214
  **Upkeep** — all async, all on a worker thread:
211
215
 
@@ -214,6 +218,8 @@ only moves arguments and results across the boundary.
214
218
  | `maintain(mode?)` | `"auto"` (default), `"compact"`, `"reindex-text"`, `"optimize-vectors"`, `"full"`. No mode ever drops a revision or an edge version |
215
219
  | `checkpoint()` | flush the journal into a fresh snapshot |
216
220
  | `verify()` | full content-integrity sweep; rejects on the first inconsistency |
221
+ | `scrub(options?)` | start a resumable byte-level check of the snapshot |
222
+ | `recover(src, dst, options?)` | module function: salvage a damaged file into a clean copy |
217
223
 
218
224
  **Read-only handles** (`{ readOnly: true }`) observe another process's writer
219
225
  over a published snapshot. The read verbs answer, the write verbs throw, and two
@@ -238,13 +244,106 @@ const res = await db.recall({ query: text, vector: own });
238
244
  Use it for vectors you already have, for a model that is not an OpenAI-shaped
239
245
  HTTP endpoint, or for a deterministic test with no network.
240
246
 
241
- ### What the Rust library has and this does not
247
+ ### Backing up: facts are only half of it
242
248
 
243
- | Not here | Why |
244
- |---|---|
245
- | `recover` | salvaging a damaged file is a path-level operation on the host's disk — the CLI's job |
246
- | `import` | the JSONL file format lives in [`plugmem-cli`](https://docs.rs/plugmem-cli/latest). A Node program holding records already uses `rememberMany` |
247
- | `scrub` | byte-level container integrity, likewise CLI-side; `verify()` covers content |
249
+ `export`/`exportPage` dump facts. An **edge** is a statement between two
250
+ entities — `kim -works_on-> plugmem` — and belongs to no single fact, so a dump
251
+ of facts alone loses the graph. `exportEdges` is the other half.
252
+
253
+ It streams: the walk runs on a worker and hands your callback one batch at a
254
+ time, so memory stays flat whether the graph has ten edges or ten million. When
255
+ a callback is slower than the walk, the *worker* waits — never the event loop.
256
+
257
+ ```javascript
258
+ const edges = [];
259
+ const count = await db.exportEdges((batch) => edges.push(...batch));
260
+ ```
261
+
262
+ `count` is `2` here, and `edges` is complete the moment the promise resolves —
263
+ no extra tick needed:
264
+
265
+ ```json
266
+ [
267
+ { "src": "kim", "rel": "works_on", "dst": "plugmem", "provenance": 0 },
268
+ { "src": "kim", "rel": "reports_to", "dst": "ann" }
269
+ ]
270
+ ```
271
+
272
+ `provenance` is the fact the edge follows from, when it was recorded with one.
273
+ It is **absent** rather than zero when there is none, so it can never be
274
+ mistaken for fact `0` — as the second edge above shows.
275
+
276
+ ### Checking a file has not rotted
277
+
278
+ `verify()` and `scrub()` ask different questions, and neither replaces the other:
279
+
280
+ - **`verify()`** — does the *content* agree with itself? Text is valid UTF-8,
281
+ each vector belongs to its fact, both directions of every edge match.
282
+ - **`scrub()`** — are the *bytes* the ones that were written? It recomputes each
283
+ section's checksum and the whole-file hash. This is what catches a flipped bit
284
+ that the structure happily accepts.
285
+
286
+ A scrub is paced by you rather than run in one go, so it stays affordable on a
287
+ live database — the model ZFS uses. Each step checks up to a budget's worth of
288
+ bytes and returns:
289
+
290
+ ```javascript
291
+ const scrub = await db.scrub(); // default budget: 1 MiB per step
292
+ let step;
293
+ while ((step = await scrub.next()) !== null) {
294
+ // step.doneBytes of step.totalBytes — progress through the snapshot file
295
+ }
296
+ ```
297
+
298
+ `next()` returns a promise because a step reads from disk, not because hashing
299
+ is slow: over a memory-mapped file the bytes are paged in as they are read, so a
300
+ step is I/O of whatever length your storage takes. On the JS thread that would
301
+ freeze the process.
302
+
303
+ Two things to know. **Holding the object holds a lock** on the snapshot
304
+ generation it is scanning, so run it to completion or `close()` it. And it is
305
+ one-shot: after it returns `null`, or throws, `active()` is `false` and you ask
306
+ the database for another.
307
+
308
+ ```javascript
309
+ const partial = await db.scrub({ budget: 16 * 1024 });
310
+ await partial.next(); // { doneBytes: 16384, totalBytes: <the file's size> }
311
+ partial.close(); // released; further next() calls return null
312
+ ```
313
+
314
+ Damage rejects with `PLUGMEM_ENGINE` naming what failed its checksum.
315
+
316
+ ### Repairing a damaged file
317
+
318
+ `recover` is a module function, not a method: it works on **paths**, and takes
319
+ the source's exclusive lock, so close your handle first.
320
+
321
+ ```javascript
322
+ import { recover } from "plugmem";
323
+
324
+ const report = await recover("memory.plugmem", "repaired.plugmem");
325
+ // { kept: 1, droppedText: 0, droppedVector: 0, droppedMetadata: 0 }
326
+ ```
327
+
328
+ **The source is never written.** It stays exactly as it was, as evidence; this
329
+ produces a repaired copy beside it, and swapping them is your decision. `dst`
330
+ must therefore be a different path — passing the same one throws.
331
+
332
+ The three `dropped` counts are the damage: each is a fact the source could not
333
+ produce intact. All zero means the image was content-clean and this was a
334
+ compaction. Memory stays proportional to the record count rather than the file,
335
+ so a database far larger than RAM can be recovered.
336
+
337
+ It handles **content** damage — the kind `verify()` reports. A snapshot whose
338
+ container will not parse at all is not salvageable here; that is what a backup
339
+ is for.
340
+
341
+ ### The one thing the Rust library has and this does not
342
+
343
+ `import`. The JSONL dump format is defined by
344
+ [`plugmem-cli`](https://docs.rs/plugmem-cli/latest), not by the engine — there is
345
+ no `import` verb to mirror. A Node program holding records already has
346
+ `rememberMany` and `link`, which is what an importer is made of.
248
347
 
249
348
  ## Errors
250
349
 
@@ -294,6 +393,10 @@ path = "/path/to/memory.plugmem"
294
393
  [engine]
295
394
  dim = 768 # embedding size (0 = vectors off)
296
395
 
396
+ [recall] # optional — every key has a tuned default
397
+ w_vec = 2.0 # trust meaning over keywords in this memory
398
+ half_life_days = 30 # and treat anything older than a month as stale
399
+
297
400
  [embedder] # optional — omit for lexical/tag/graph/time only
298
401
  kind = "ollama" # or openai / lmstudio / vllm / llamacpp
299
402
  url = "http://localhost:11434/v1/embeddings"
@@ -303,6 +406,24 @@ model = "nomic-embed-text"
303
406
  fsync = "each_op" # or "on_snapshot": faster, loses the journal tail on an OS crash
304
407
  ```
305
408
 
409
+ `[engine]` is what a database is *built* with; changing one of those on an
410
+ existing file is refused. `[recall]` and `[index]` are the opposite — reopening
411
+ with different weights is how you change the ranking, so tune them freely. All
412
+ of them are in the [full settings reference](https://github.com/m62624/plugmem/blob/main/crates/plugmem-host/SETTINGS.md).
413
+
414
+ ### When a key is misspelled
415
+
416
+ Unknown keys and sections do not stop anything, but they are not swallowed
417
+ either — a misspelled `w_vec` changes no behaviour, and silence would leave you
418
+ believing you had tuned something. **Read them once after opening**, because a
419
+ native addon has nowhere sensible to print:
420
+
421
+ ```javascript
422
+ const db = await Plugmem.open("agent.plugmem", { config: "./plugmem.toml" });
423
+ for (const warning of db.configWarnings()) console.warn(warning);
424
+ // unknown setting [recall].w_vector — did you mean `w_vec`?
425
+ ```
426
+
306
427
  With an `[embedder]`, a text-only `remember`/`recall` embeds automatically, and
307
428
  the provider's HTTP call happens outside the engine lock. The `dim` open option
308
429
  sets the embedding size when there is no config; if the config built an
@@ -393,7 +514,7 @@ processes, sharing the OS page cache.
393
514
 
394
515
  ## Many memories in one directory
395
516
 
396
- **Default: one memory, one file.** `Plugmem.open(path)` and nothing here
517
+ **Default: one logical memory backed by a local database layout.** `Plugmem.open(path)` and nothing here
397
518
  applies.
398
519
 
399
520
  The problem this solves: a process serving many conversations, tenants or
@@ -432,7 +553,7 @@ const byOwner: DbEntry[] = await ws.find("ann"); // → the same memo
432
553
  ```
433
554
 
434
555
  A name is `[a-z0-9][a-z0-9_-]*` and **cannot express a path**, so it resolves to
435
- exactly one file inside the directory — traversal is not filtered out, it is
556
+ exactly one named database inside the directory — traversal is not filtered out, it is
436
557
  unconstructible. `ws.open(name, false)` refuses a name that does not exist yet,
437
558
  which is what a read should do so a typo is diagnosed rather than answered with
438
559
  an empty result.
@@ -477,8 +598,8 @@ data.
477
598
 
478
599
  ## What it is not for
479
600
 
480
- plugmem is for a local agent's memory: one process, one file, no service to
481
- operate. Its design centre is around 100 000 active facts on one machine, and
601
+ plugmem is for local-first application and agent memory: one process, one local database,
602
+ no service to operate. Its design centre is around 100 000 active facts on one machine, and
482
603
  the benchmarks track 1M-operation profiles to show how the same engine behaves
483
604
  under heavier local load.
484
605
 
package/index.d.ts CHANGED
@@ -98,6 +98,16 @@ export interface RecallArgs {
98
98
  * the engine is still in the flat regime, below `flat_to_hnsw`.
99
99
  */
100
100
  ef?: number
101
+ /**
102
+ * How many edges the graph source may follow from an anchor entity
103
+ * (default: the configured `graph_depth`). `0` asks for the anchors' own
104
+ * facts and no neighbours.
105
+ *
106
+ * Per call for the same reason `k` and `tokenBudget` are: how wide a net
107
+ * to cast belongs to the question. "What is known around this person"
108
+ * wants more hops than "what is this person's stated preference".
109
+ */
110
+ graphDepth?: number
101
111
  /**
102
112
  * A precomputed embedding. Its length must equal the configured `dim`.
103
113
  *
@@ -123,6 +133,53 @@ export interface LinkArgs {
123
133
  */
124
134
  provenance?: number
125
135
  }
136
+ /** Options for [`recover`]. */
137
+ export interface RecoverOptions {
138
+ /**
139
+ * Embedding dimension, as `OpenOptions.dim`. It must match what the source
140
+ * database stores, so a memory with vectors needs this (or a `config`
141
+ * naming the embedder) or the salvage cannot open it.
142
+ */
143
+ dim?: number
144
+ /** Path to a `config.toml`; the standard discovery applies when omitted. */
145
+ config?: string
146
+ }
147
+ /**
148
+ * Salvages a content-corrupt memory: reads `src`, drops the facts that fail
149
+ * the content checks, and writes a clean, compacted image to `dst`.
150
+ *
151
+ * **`src` is never written.** The damaged file stays exactly as it was, as
152
+ * evidence — this produces a repaired copy beside it, and swapping them is
153
+ * your decision, not this function's. `dst` must therefore be a different
154
+ * path.
155
+ *
156
+ * **It handles *content* damage**, the kind `verify` reports: text that is not
157
+ * valid UTF-8, a vector slot that disagrees with its fact, metadata that will
158
+ * not decode. *Structural* damage — a snapshot whose container will not parse
159
+ * at all — is not salvageable here and rejects; that is what a backup is for.
160
+ *
161
+ * Memory stays proportional to the record count rather than the image: the
162
+ * two large pools are streamed through temp files, so a database far bigger
163
+ * than RAM can be recovered as long as its graph fits.
164
+ *
165
+ * **Async**: it opens, sweeps and rewrites a whole database.
166
+ *
167
+ * @throws `PLUGMEM_LOCKED` if either path is open elsewhere; `PLUGMEM_ENGINE`
168
+ * if `dst` resolves to the same file as `src`, or the source will not parse;
169
+ * `PLUGMEM_OPEN` for an IO failure on either path.
170
+ */
171
+ export declare function recover(src: string, dst: string, options?: RecoverOptions | undefined | null): Promise<RecoverReport>
172
+ /** Options for `Plugmem#scrub`. */
173
+ export interface ScrubOptions {
174
+ /**
175
+ * Bytes to hash per step, at most. Default: the engine's own (1 MiB).
176
+ *
177
+ * This is the knob trading responsiveness for throughput: smaller steps
178
+ * return to JavaScript more often, larger ones spend less time crossing
179
+ * back and forth. It changes no answer, only the grain.
180
+ */
181
+ budget?: number
182
+ }
126
183
  /** One similar / potentially-conflicting live fact surfaced by `remember`. */
127
184
  export interface Similar {
128
185
  /** The existing fact's id. */
@@ -263,6 +320,52 @@ export interface ExportedFact {
263
320
  /** Validity start (unix ms; preserved on import). */
264
321
  validFrom: number
265
322
  }
323
+ /**
324
+ * One exported edge — the shape `exportEdges` streams, and the same fields the
325
+ * CLI's JSONL dump writes for an edge.
326
+ *
327
+ * Edges are not part of a fact's dump: a fact names its tags and metadata, but
328
+ * an edge is a statement *between* two entities and outlives any single fact.
329
+ * That is why a complete backup is the two streams together.
330
+ */
331
+ export interface ExportedEdge {
332
+ /** Source entity name. */
333
+ src: string
334
+ /** The relation, verbatim. */
335
+ rel: string
336
+ /** Destination entity name. */
337
+ dst: string
338
+ /**
339
+ * The fact this edge follows from, if it was recorded with one. Absent
340
+ * rather than a sentinel, so "no provenance" cannot be mistaken for fact 0.
341
+ */
342
+ provenance?: number
343
+ }
344
+ /**
345
+ * What a `recover` salvaged, and what it had to leave behind.
346
+ *
347
+ * The three `dropped` counts are the damage: each is a fact the source could
348
+ * not produce intact, so a non-zero total means the recovered copy is smaller
349
+ * than the original claimed to be. Zeroes across the board mean the image was
350
+ * content-clean and this was a compaction.
351
+ */
352
+ export interface RecoverReport {
353
+ /** Facts written to the destination — the survivors. */
354
+ kept: number
355
+ /** Dropped: the stored text was not valid UTF-8. */
356
+ droppedText: number
357
+ /** Dropped: the vector slot was out of range or disagreed with the fact. */
358
+ droppedVector: number
359
+ /** Dropped: the metadata blob did not decode to a well-formed map. */
360
+ droppedMetadata: number
361
+ }
362
+ /** How far a `Scrub` has got. */
363
+ export interface ScrubProgress {
364
+ /** Bytes checksummed so far; equals `totalBytes` on the last step. */
365
+ doneBytes: number
366
+ /** The generation file's length — the total to checksum. */
367
+ totalBytes: number
368
+ }
266
369
  /** One bounded page returned by `exportPage`. */
267
370
  export interface ExportPage {
268
371
  /** Open facts in fact-id order; never longer than the native page bound. */
@@ -498,6 +601,18 @@ export declare class Plugmem {
498
601
  * snapshot (`PLUGMEM_NEEDS_CHECKPOINT`), or on an IO error.
499
602
  */
500
603
  static open(path?: string | undefined | null, options?: OpenOptions | undefined | null): Promise<Plugmem>
604
+ /**
605
+ * What `config.toml` said that nothing claimed — a misspelled key, a
606
+ * misspelled section — one human-readable line each, empty when the file
607
+ * was clean.
608
+ *
609
+ * It is a value rather than a printed warning because a native addon has
610
+ * nowhere sensible to print: stderr belongs to the host application, which
611
+ * may be a server that logs as JSON. **Read it once after opening and log
612
+ * it your own way** — ignoring it puts you back where a typo silently
613
+ * changes nothing.
614
+ */
615
+ configWarnings(): Array<string>
501
616
  /**
502
617
  * The file this memory is open on.
503
618
  *
@@ -594,6 +709,50 @@ export declare class Plugmem {
594
709
  * mutate it during a snapshot-style backup; a read-only handle is stable.
595
710
  */
596
711
  exportPage(cursor?: number | undefined | null): Promise<ExportPage>
712
+ /**
713
+ * Streams every current edge to `onBatch`, in batches, and resolves with
714
+ * the number streamed.
715
+ *
716
+ * **The other half of a backup.** `export`/`exportPage` dump facts; an edge
717
+ * is a statement between two entities and belongs to no single fact, so a
718
+ * dump of facts alone silently loses the graph.
719
+ *
720
+ * **Async and bounded.** The walk runs on a libuv worker; batches reach
721
+ * `onBatch` on the JS thread through a threadsafe function with a queue of
722
+ * four. When the callback is slower than the walk, the *worker* waits — the
723
+ * event loop never does, and peak memory is four batches whatever the
724
+ * database's size.
725
+ *
726
+ * **When the promise resolves, every batch has been delivered.** Worth
727
+ * saying because a threadsafe-function call only queues work for the JS
728
+ * thread, so the natural implementation resolves early and hands you a
729
+ * half-filled accumulator on some runs and a full one on others. Each
730
+ * batch is acknowledged from the JS thread and the worker waits for the
731
+ * receipts, so reading your results straight after the `await` is correct.
732
+ *
733
+ * `onBatch` throwing is not caught here: it surfaces as an uncaught error,
734
+ * as it would from any callback Node invokes on your behalf.
735
+ */
736
+ exportEdges(onBatch: (edges: ExportedEdge[]) => void): Promise<number>
737
+ /**
738
+ * Starts a resumable byte-level check of the current published snapshot,
739
+ * and resolves with the [`Scrub`](crate::scrub::Scrub) that paces it.
740
+ *
741
+ * The counterpart to `verify`, not a replacement: `verify` asks whether
742
+ * the *content* agrees with itself, this asks whether the *bytes* are the
743
+ * ones that were written. Only the second catches a flipped bit that the
744
+ * structure accepts.
745
+ *
746
+ * Available on a writer as well as a read-only handle: a scrub reads the
747
+ * published generation from disk and has no opinion about which handle
748
+ * asked. It does need something published — checkpoint once first.
749
+ *
750
+ * **The returned object holds a shared lock** on the generation it scans
751
+ * for as long as it lives, so run it to completion or `close()` it.
752
+ *
753
+ * @throws `PLUGMEM_NEEDS_CHECKPOINT` when nothing has been published yet.
754
+ */
755
+ scrub(options?: ScrubOptions | undefined | null): Promise<Scrub>
597
756
  /** One fact's tags, or an empty array for an unknown or tombstoned id. */
598
757
  tagsOf(id: number): Array<string>
599
758
  /**
@@ -638,6 +797,46 @@ export declare class Plugmem {
638
797
  */
639
798
  close(): void
640
799
  }
800
+ /**
801
+ * A resumable byte-level check of one snapshot generation.
802
+ *
803
+ * **Holding this object holds a lock.** It pins the generation it is scanning
804
+ * with a shared lock for its whole life, so the writer's garbage collection
805
+ * cannot reclaim that generation under it. Finish the scan, or `close()` it —
806
+ * do not park one indefinitely.
807
+ *
808
+ * One-shot: once it has returned `null`, or thrown, it is done. Ask the
809
+ * database for another to scan again.
810
+ */
811
+ export declare class Scrub {
812
+ /**
813
+ * Hashes the next slice and resolves with the progress so far, or `null`
814
+ * when the scan is complete.
815
+ *
816
+ * **Async**: see the module note — a step is disk I/O, not arithmetic.
817
+ *
818
+ * Concurrent calls are serialized rather than refused: the cursor has one
819
+ * position, so two overlapping steps would be two different slices of the
820
+ * same scan, which is what a caller pacing it from two places asked for.
821
+ *
822
+ * @throws on the first mismatch, naming what failed its checksum. The
823
+ * scrub is finished at that point; a further call resolves `null`.
824
+ */
825
+ next(): Promise<ScrubProgress | null>
826
+ /**
827
+ * Releases the pinned generation now, abandoning an unfinished scan.
828
+ *
829
+ * Idempotent, and the same bargain as `Plugmem#close`: waiting for the
830
+ * garbage collector to do it means the writer cannot reclaim that
831
+ * generation until it happens.
832
+ */
833
+ close(): void
834
+ /**
835
+ * Whether this scrub still has work — `false` once it finished, failed or
836
+ * was closed. Cheap: it inspects the handle, not the file.
837
+ */
838
+ active(): boolean
839
+ }
641
840
  /**
642
841
  * A directory of named memories — the napi mirror of
643
842
  * [`plugmem_host::Workspace`].
package/index.js CHANGED
@@ -310,9 +310,11 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { Plugmem, MaintainMode, Workspace, version, about, settingsHelp, skill, skillFull, skillVersion } = nativeBinding
313
+ const { Plugmem, recover, Scrub, MaintainMode, Workspace, version, about, settingsHelp, skill, skillFull, skillVersion } = nativeBinding
314
314
 
315
315
  module.exports.Plugmem = Plugmem
316
+ module.exports.recover = recover
317
+ module.exports.Scrub = Scrub
316
318
  module.exports.MaintainMode = MaintainMode
317
319
  module.exports.Workspace = Workspace
318
320
  module.exports.version = version
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plugmem",
3
- "version": "0.5.0",
4
- "description": "Native Node.js addon for plugmem: an embedded long-term memory engine for LLM agents (remember / recall / revise / forget over one local file).",
3
+ "version": "0.6.0",
4
+ "description": "Native Node.js addon for plugmem: an embedded bitemporal memory and retrieval engine for local-first applications and agents (remember / recall / revise / forget over one local database).",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/m62624/plugmem.git"
@@ -41,11 +41,11 @@
41
41
  "typecheck": "tsc -p tsconfig.json"
42
42
  },
43
43
  "optionalDependencies": {
44
- "plugmem-linux-x64-gnu": "0.5.0",
45
- "plugmem-linux-arm64-gnu": "0.5.0",
46
- "plugmem-darwin-x64": "0.5.0",
47
- "plugmem-darwin-arm64": "0.5.0",
48
- "plugmem-win32-x64-msvc": "0.5.0",
49
- "plugmem-win32-arm64-msvc": "0.5.0"
44
+ "plugmem-linux-x64-gnu": "0.6.0",
45
+ "plugmem-linux-arm64-gnu": "0.6.0",
46
+ "plugmem-darwin-x64": "0.6.0",
47
+ "plugmem-darwin-arm64": "0.6.0",
48
+ "plugmem-win32-x64-msvc": "0.6.0",
49
+ "plugmem-win32-arm64-msvc": "0.6.0"
50
50
  }
51
51
  }