@fgv/ts-agent-memory 5.1.0-48 → 5.1.0-49

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 (43) hide show
  1. package/dist/packlets/retrieve/linkTraversalRetriever.js +1 -1
  2. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  3. package/dist/packlets/retrieve/recencyRetriever.js +1 -1
  4. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
  5. package/dist/packlets/retrieve/retriever.js +11 -5
  6. package/dist/packlets/retrieve/retriever.js.map +1 -1
  7. package/dist/packlets/retrieve/structuredFilterRetriever.js +27 -5
  8. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  9. package/dist/packlets/retrieve/tagRetriever.js +1 -1
  10. package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
  11. package/dist/packlets/retrieve/temporalRetrievers.js +1 -1
  12. package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
  13. package/dist/packlets/store/fileTreeMemoryStore.js +100 -1
  14. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  15. package/dist/packlets/types/envelope.js.map +1 -1
  16. package/dist/ts-agent-memory.d.ts +134 -13
  17. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +1 -1
  18. package/lib/packlets/retrieve/linkTraversalRetriever.js +1 -1
  19. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  20. package/lib/packlets/retrieve/recencyRetriever.d.ts +1 -1
  21. package/lib/packlets/retrieve/recencyRetriever.js +1 -1
  22. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
  23. package/lib/packlets/retrieve/retriever.d.ts +26 -7
  24. package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
  25. package/lib/packlets/retrieve/retriever.js +11 -5
  26. package/lib/packlets/retrieve/retriever.js.map +1 -1
  27. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +26 -4
  28. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
  29. package/lib/packlets/retrieve/structuredFilterRetriever.js +27 -5
  30. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  31. package/lib/packlets/retrieve/tagRetriever.d.ts +1 -1
  32. package/lib/packlets/retrieve/tagRetriever.js +1 -1
  33. package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
  34. package/lib/packlets/retrieve/temporalRetrievers.js +1 -1
  35. package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
  36. package/lib/packlets/store/fileTreeMemoryStore.d.ts +69 -0
  37. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  38. package/lib/packlets/store/fileTreeMemoryStore.js +99 -0
  39. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  40. package/lib/packlets/types/envelope.d.ts +11 -0
  41. package/lib/packlets/types/envelope.d.ts.map +1 -1
  42. package/lib/packlets/types/envelope.js.map +1 -1
  43. package/package.json +7 -7
@@ -133,6 +133,14 @@ export interface IMemoryEnvelope {
133
133
  * Absent when the kind has no registered projector (or the projector threw on
134
134
  * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view
135
135
  * sort by this value descending, placing records with an absent `rank` last.
136
+ *
137
+ * **The projector runs on the write path only — registering one does not rank
138
+ * records already in the store.** Because absent sorts last, those records land
139
+ * below every subsequently-written one regardless of what the projector would
140
+ * have scored them, so the result is not a partial ordering but one inverted
141
+ * with respect to the projector's intent, with nothing failing to say so. Call
142
+ * `IMemoryStore.reconcileRank` after registering a projector against a
143
+ * populated store.
136
144
  */
137
145
  readonly rank?: number;
138
146
  /** Structured provenance (never a flat enum). */
@@ -166,6 +174,9 @@ export interface IMemoryRecord<TBody = unknown> {
166
174
  * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host
167
175
  * owns what the number means. A projector that throws is treated as "no rank
168
176
  * for this record" (logged at `warn`), never failing the write.
177
+ *
178
+ * Runs on writes only. To apply a newly-registered projector to records that
179
+ * already exist, call `IMemoryStore.reconcileRank`.
169
180
  * @public
170
181
  */
171
182
  export type RankProjector = (record: IMemoryRecord<unknown>) => number;
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAmEH,sCAEC;AAZD;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,MAAmB;IAC/C,OAAO,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;AACzC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { EntityId, Kind, LinkType, MemoryId, MemoryScopeKey, Tag } from './ids';\n\n/**\n * Origin of a provenance attribution. Open vocabulary: the three named\n * sources are conventional, but the `(string & {})` arm admits any other\n * source string without resignature.\n * @public\n */\nexport type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {});\n\n/**\n * Structured provenance for a record or an edge. Never a flat enum — the\n * `[key: string]: unknown` index signature lets a consumer attach an opaque\n * domain payload (e.g. PersonAIlity's sentiment / epistemic blocks) without\n * changing this interface, while still satisfying the no-`any` rule.\n * @public\n */\nexport interface IProvenance {\n /** Where the attribution came from. */\n readonly source: ProvenanceSource;\n /** Optional human or agent identifier responsible for the write. */\n readonly by?: string;\n /** Optional model identifier, when a model produced the content. */\n readonly model?: string;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /**\n * Scope-qualified back-link to the source record. Enables the cross-kind\n * provenance spine. A scope-qualified {@link IEdgeTarget} (not a bare\n * {@link MemoryId}) because per-scope codecs (e.g. the MTM codec's `turn-<n>`\n * stems) legally reuse a stem across scopes, so a bare id would be ambiguous —\n * the same reason {@link IEdge.target} is scope-qualified.\n */\n readonly derivedFrom?: IEdgeTarget;\n /** Opaque extension payload — consumer-owned, never interpreted by the store. */\n readonly [key: string]: unknown;\n}\n\n/**\n * The physical address of a linked-to record: the `(scope, id)` pair that\n * uniquely identifies it. Both components are required because a bare\n * {@link MemoryId} is NOT unique across scopes — per-scope codecs (e.g. the\n * medium-term codec's `turn-<n>` stems) legally mint the same stem under\n * different scopes, so an edge that carried only the id would be ambiguous.\n * `(scope, id)` matches the store's `getById(scope, id)` addressing and the\n * index's composite primary key.\n * @public\n */\nexport interface IEdgeTarget {\n /** The scope the target record lives under. */\n readonly scope: MemoryScopeKey;\n /** The target record's stable file-stem id (unique WITHIN {@link IEdgeTarget.scope}). */\n readonly id: MemoryId;\n}\n\n/**\n * The canonical composite-key string for an {@link IEdgeTarget}: scope + id,\n * NUL-separated. NUL is excluded from both components (scope segments are\n * filename-safe; {@link MemoryId} is portable-filename-safe), so it is a\n * collision-proof separator. This is the ONE canonicalization every consumer\n * that keys on a scoped target uses — the backlink index, the cycle guard, and\n * the ingest edge-validation path all route through it so their notions of\n * \"same target\" cannot drift.\n * @public\n */\nexport function edgeTargetKey(target: IEdgeTarget): string {\n return `${target.scope}\\0${target.id}`;\n}\n\n/**\n * An attributed link between two records. Carries the relation type, the\n * scope-qualified {@link IEdgeTarget | target}, and optional confidence /\n * provenance / world-truth validity. Replaces bare string references (e.g.\n * PersonAIlity's `IMtmRef` becomes an `IEdge` with `type: LinkType('mtm-ref')`).\n * @public\n */\nexport interface IEdge {\n /** Open-vocabulary relation type. */\n readonly type: LinkType;\n /** The scope-qualified address of the linked-to record. */\n readonly target: IEdgeTarget;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Optional structured provenance for the link itself. */\n readonly provenance?: IProvenance;\n /** World-truth validity start (epoch ms). Present only on temporal edges. */\n readonly valid_at?: number;\n /**\n * World-truth validity end (epoch ms). `null` = still valid; absent = no\n * temporal extent.\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent (no temporal extent); design-lock §2.3\n readonly invalid_at?: number | null;\n}\n\n/**\n * Optional bi-temporal validity block on an envelope. Present only on\n * temporal kinds; absent = zero cost for atemporal kinds.\n * @public\n */\nexport interface ITemporalBlock {\n /** World-truth validity start (epoch ms). */\n readonly valid_at?: number;\n /** World-truth validity end (epoch ms). `null` = still valid. */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent; design-lock §2.4\n readonly invalid_at?: number | null;\n}\n\n/**\n * The invariant identity + transaction-time envelope carried by every memory\n * record, independent of the per-kind body.\n * @public\n */\nexport interface IMemoryEnvelope {\n // --- Core identity ---\n /** Stable file-stem identifier. MUST equal the on-disk filename stem. */\n readonly id: MemoryId;\n /** Consumer-supplied domain key. Equals {@link IMemoryEnvelope.id | id} for non-temporal kinds. */\n readonly entityId: EntityId;\n /** Consumer-registered kind; dispatches the body Converter. */\n readonly kind: Kind;\n /** Open-vocabulary tags. */\n readonly tags: ReadonlyArray<Tag>;\n /** Attributed outbound edges. */\n readonly links: ReadonlyArray<IEdge>;\n\n // --- Transaction-time metadata (always present) ---\n /** Epoch ms of the first write. Immutable after creation. */\n readonly created: number;\n /** Epoch ms of the most recent write. */\n readonly updated: number;\n /**\n * Monotonic write counter within the store instance, assigned by the store\n * on every successful put. Enables stable cursor paging over observation\n * records without a full walk.\n */\n readonly seq: number;\n /**\n * Content hash over the canonical `{ kind, body, links }`. The dedup key:\n * an exact match is a no-op upsert that returns the existing record.\n */\n readonly contentHash: string;\n /**\n * Store-computed host-defined ordering value, produced by the kind's\n * {@link RankProjector} on every put/update and stamped into the envelope in\n * the same pass that recomputes {@link IMemoryEnvelope.contentHash | contentHash}.\n * Absent when the kind has no registered projector (or the projector threw on\n * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view\n * sort by this value descending, placing records with an absent `rank` last.\n */\n readonly rank?: number;\n /** Structured provenance (never a flat enum). */\n readonly provenance: IProvenance;\n\n // --- Optional temporal block ---\n /** Bi-temporal validity. Present only on temporal kinds. */\n readonly temporal?: ITemporalBlock;\n\n /**\n * Vector-index entry reference, set by the vector index on write. `null` =\n * not embedded; absent = same as `null` (backwards-compat seam).\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is the explicit \"not embedded\" sentinel distinct from absent (backwards-compat seam); design-lock §2.5\n readonly embeddingRef?: string | null;\n}\n\n/**\n * A complete memory record: the invariant {@link IMemoryEnvelope} plus the\n * typed, per-kind body. The store's public surface uses\n * `IMemoryRecord<unknown>`; consumers narrow `TBody` by checking\n * `envelope.kind` and validating through the registered Converter.\n * @public\n */\nexport interface IMemoryRecord<TBody = unknown> {\n /** The invariant identity + transaction-time envelope. */\n readonly envelope: IMemoryEnvelope;\n /** The per-kind, Converter-validated body. */\n readonly body: TBody;\n}\n\n/**\n * A per-kind host projection from a fully-resolved (post-merge) memory record\n * to a numeric ordering value. Registered per kind at store construction (see\n * `rankProjectors`); the store runs it on every put/update over the same\n * resolved record whose `contentHash` it computes, stamping the result into\n * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host\n * owns what the number means. A projector that throws is treated as \"no rank\n * for this record\" (logged at `warn`), never failing the write.\n * @public\n */\nexport type RankProjector = (record: IMemoryRecord<unknown>) => number;\n"]}
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAmEH,sCAEC;AAZD;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,MAAmB;IAC/C,OAAO,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;AACzC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { EntityId, Kind, LinkType, MemoryId, MemoryScopeKey, Tag } from './ids';\n\n/**\n * Origin of a provenance attribution. Open vocabulary: the three named\n * sources are conventional, but the `(string & {})` arm admits any other\n * source string without resignature.\n * @public\n */\nexport type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {});\n\n/**\n * Structured provenance for a record or an edge. Never a flat enum — the\n * `[key: string]: unknown` index signature lets a consumer attach an opaque\n * domain payload (e.g. PersonAIlity's sentiment / epistemic blocks) without\n * changing this interface, while still satisfying the no-`any` rule.\n * @public\n */\nexport interface IProvenance {\n /** Where the attribution came from. */\n readonly source: ProvenanceSource;\n /** Optional human or agent identifier responsible for the write. */\n readonly by?: string;\n /** Optional model identifier, when a model produced the content. */\n readonly model?: string;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /**\n * Scope-qualified back-link to the source record. Enables the cross-kind\n * provenance spine. A scope-qualified {@link IEdgeTarget} (not a bare\n * {@link MemoryId}) because per-scope codecs (e.g. the MTM codec's `turn-<n>`\n * stems) legally reuse a stem across scopes, so a bare id would be ambiguous —\n * the same reason {@link IEdge.target} is scope-qualified.\n */\n readonly derivedFrom?: IEdgeTarget;\n /** Opaque extension payload — consumer-owned, never interpreted by the store. */\n readonly [key: string]: unknown;\n}\n\n/**\n * The physical address of a linked-to record: the `(scope, id)` pair that\n * uniquely identifies it. Both components are required because a bare\n * {@link MemoryId} is NOT unique across scopes — per-scope codecs (e.g. the\n * medium-term codec's `turn-<n>` stems) legally mint the same stem under\n * different scopes, so an edge that carried only the id would be ambiguous.\n * `(scope, id)` matches the store's `getById(scope, id)` addressing and the\n * index's composite primary key.\n * @public\n */\nexport interface IEdgeTarget {\n /** The scope the target record lives under. */\n readonly scope: MemoryScopeKey;\n /** The target record's stable file-stem id (unique WITHIN {@link IEdgeTarget.scope}). */\n readonly id: MemoryId;\n}\n\n/**\n * The canonical composite-key string for an {@link IEdgeTarget}: scope + id,\n * NUL-separated. NUL is excluded from both components (scope segments are\n * filename-safe; {@link MemoryId} is portable-filename-safe), so it is a\n * collision-proof separator. This is the ONE canonicalization every consumer\n * that keys on a scoped target uses — the backlink index, the cycle guard, and\n * the ingest edge-validation path all route through it so their notions of\n * \"same target\" cannot drift.\n * @public\n */\nexport function edgeTargetKey(target: IEdgeTarget): string {\n return `${target.scope}\\0${target.id}`;\n}\n\n/**\n * An attributed link between two records. Carries the relation type, the\n * scope-qualified {@link IEdgeTarget | target}, and optional confidence /\n * provenance / world-truth validity. Replaces bare string references (e.g.\n * PersonAIlity's `IMtmRef` becomes an `IEdge` with `type: LinkType('mtm-ref')`).\n * @public\n */\nexport interface IEdge {\n /** Open-vocabulary relation type. */\n readonly type: LinkType;\n /** The scope-qualified address of the linked-to record. */\n readonly target: IEdgeTarget;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Optional structured provenance for the link itself. */\n readonly provenance?: IProvenance;\n /** World-truth validity start (epoch ms). Present only on temporal edges. */\n readonly valid_at?: number;\n /**\n * World-truth validity end (epoch ms). `null` = still valid; absent = no\n * temporal extent.\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent (no temporal extent); design-lock §2.3\n readonly invalid_at?: number | null;\n}\n\n/**\n * Optional bi-temporal validity block on an envelope. Present only on\n * temporal kinds; absent = zero cost for atemporal kinds.\n * @public\n */\nexport interface ITemporalBlock {\n /** World-truth validity start (epoch ms). */\n readonly valid_at?: number;\n /** World-truth validity end (epoch ms). `null` = still valid. */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent; design-lock §2.4\n readonly invalid_at?: number | null;\n}\n\n/**\n * The invariant identity + transaction-time envelope carried by every memory\n * record, independent of the per-kind body.\n * @public\n */\nexport interface IMemoryEnvelope {\n // --- Core identity ---\n /** Stable file-stem identifier. MUST equal the on-disk filename stem. */\n readonly id: MemoryId;\n /** Consumer-supplied domain key. Equals {@link IMemoryEnvelope.id | id} for non-temporal kinds. */\n readonly entityId: EntityId;\n /** Consumer-registered kind; dispatches the body Converter. */\n readonly kind: Kind;\n /** Open-vocabulary tags. */\n readonly tags: ReadonlyArray<Tag>;\n /** Attributed outbound edges. */\n readonly links: ReadonlyArray<IEdge>;\n\n // --- Transaction-time metadata (always present) ---\n /** Epoch ms of the first write. Immutable after creation. */\n readonly created: number;\n /** Epoch ms of the most recent write. */\n readonly updated: number;\n /**\n * Monotonic write counter within the store instance, assigned by the store\n * on every successful put. Enables stable cursor paging over observation\n * records without a full walk.\n */\n readonly seq: number;\n /**\n * Content hash over the canonical `{ kind, body, links }`. The dedup key:\n * an exact match is a no-op upsert that returns the existing record.\n */\n readonly contentHash: string;\n /**\n * Store-computed host-defined ordering value, produced by the kind's\n * {@link RankProjector} on every put/update and stamped into the envelope in\n * the same pass that recomputes {@link IMemoryEnvelope.contentHash | contentHash}.\n * Absent when the kind has no registered projector (or the projector threw on\n * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view\n * sort by this value descending, placing records with an absent `rank` last.\n *\n * **The projector runs on the write path only — registering one does not rank\n * records already in the store.** Because absent sorts last, those records land\n * below every subsequently-written one regardless of what the projector would\n * have scored them, so the result is not a partial ordering but one inverted\n * with respect to the projector's intent, with nothing failing to say so. Call\n * `IMemoryStore.reconcileRank` after registering a projector against a\n * populated store.\n */\n readonly rank?: number;\n /** Structured provenance (never a flat enum). */\n readonly provenance: IProvenance;\n\n // --- Optional temporal block ---\n /** Bi-temporal validity. Present only on temporal kinds. */\n readonly temporal?: ITemporalBlock;\n\n /**\n * Vector-index entry reference, set by the vector index on write. `null` =\n * not embedded; absent = same as `null` (backwards-compat seam).\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is the explicit \"not embedded\" sentinel distinct from absent (backwards-compat seam); design-lock §2.5\n readonly embeddingRef?: string | null;\n}\n\n/**\n * A complete memory record: the invariant {@link IMemoryEnvelope} plus the\n * typed, per-kind body. The store's public surface uses\n * `IMemoryRecord<unknown>`; consumers narrow `TBody` by checking\n * `envelope.kind` and validating through the registered Converter.\n * @public\n */\nexport interface IMemoryRecord<TBody = unknown> {\n /** The invariant identity + transaction-time envelope. */\n readonly envelope: IMemoryEnvelope;\n /** The per-kind, Converter-validated body. */\n readonly body: TBody;\n}\n\n/**\n * A per-kind host projection from a fully-resolved (post-merge) memory record\n * to a numeric ordering value. Registered per kind at store construction (see\n * `rankProjectors`); the store runs it on every put/update over the same\n * resolved record whose `contentHash` it computes, stamping the result into\n * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host\n * owns what the number means. A projector that throws is treated as \"no rank\n * for this record\" (logged at `warn`), never failing the write.\n *\n * Runs on writes only. To apply a newly-registered projector to records that\n * already exist, call `IMemoryStore.reconcileRank`.\n * @public\n */\nexport type RankProjector = (record: IMemoryRecord<unknown>) => number;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-agent-memory",
3
- "version": "5.1.0-48",
3
+ "version": "5.1.0-49",
4
4
  "description": "FileTree-backed storage and retrieval substrate for agent memory and knowledge",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-agent-memory.d.ts",
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "tslib": "^2.8.1",
48
- "@fgv/ts-extras": "5.1.0-48",
49
- "@fgv/ts-json": "5.1.0-48",
50
- "@fgv/ts-json-base": "5.1.0-48",
51
- "@fgv/ts-utils": "5.1.0-48"
48
+ "@fgv/ts-extras": "5.1.0-49",
49
+ "@fgv/ts-json-base": "5.1.0-49",
50
+ "@fgv/ts-utils": "5.1.0-49",
51
+ "@fgv/ts-json": "5.1.0-49"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@microsoft/api-extractor": "^7.55.2",
@@ -75,8 +75,8 @@
75
75
  "@rushstack/heft-node-rig": "2.11.27",
76
76
  "@types/heft-jest": "1.0.6",
77
77
  "eslint-plugin-tsdoc": "~0.5.2",
78
- "@fgv/heft-dual-rig": "5.1.0-48",
79
- "@fgv/ts-utils-jest": "5.1.0-48"
78
+ "@fgv/heft-dual-rig": "5.1.0-49",
79
+ "@fgv/ts-utils-jest": "5.1.0-49"
80
80
  },
81
81
  "scripts": {
82
82
  "build": "heft build --clean",