@metta-ts/edsl 1.0.3 → 1.0.5

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
@@ -1,6 +1,6 @@
1
1
  # @metta-ts/edsl
2
2
 
3
- A typed TypeScript eDSL for [MeTTa TS](https://github.com/MesTTo/Meta-TypeScript-Talk). Write MeTTa with typed term builders and special-form combinators, or a tagged-template surface, and run it on the real interpreter. Any TypeScript value drops in as a grounded atom automatically.
3
+ A typed TypeScript eDSL for [MeTTa TS](https://github.com/MesTTo/Meta-TypeScript-Talk). Mint symbols, functors, and logic variables from proxies, build MeTTa with combinators or a tagged template, and run it on the real interpreter. Any TypeScript value drops in as a grounded atom automatically, and TypeScript functions bridge in both directions.
4
4
 
5
5
  It is a thin layer over [`@metta-ts/hyperon`](https://github.com/MesTTo/Meta-TypeScript-Talk/tree/main/packages/hyperon): every builder produces an ordinary atom that runs on the existing engine, so you get MeTTa's full semantics: rewrite rules, nondeterminism, pattern matching, and types.
6
6
 
@@ -13,39 +13,87 @@ npm install @metta-ts/edsl
13
13
  ## Usage
14
14
 
15
15
  ```ts
16
- import { mettaDB, S, v, rel, iff, gt, lt, mul, sub, m, ValueAtom, type GroundedAtom } from "@metta-ts/edsl";
16
+ import { mettaDB, names, vars, If, gt, lt, mul, sub, m } from "@metta-ts/edsl";
17
17
 
18
18
  const db = mettaDB();
19
19
 
20
- // Facts + a typed match query (rows are typed by the variables).
21
- db.add(rel("Likes")(S.Ada, S.Coffee), rel("Likes")(S.Ada, S.Chocolate));
22
- const thing = v<string>("thing");
23
- db.query(rel("Likes")(S.Ada, thing), { thing }); // [{ thing: "Coffee" }, { thing: "Chocolate" }]
20
+ // `names()` mints symbols and functors on demand; `vars()` mints logic variables. No name is written
21
+ // twice: the JS binding IS the name. A bare name grounds to its symbol; a called name applies it.
22
+ const { Likes, fact, Ada, Coffee, Chocolate } = names();
23
+ const { thing, x } = vars();
24
+
25
+ // Facts + a match query. With no explicit vars, the row keys are inferred from the pattern.
26
+ db.add(Likes(Ada, Coffee), Likes(Ada, Chocolate));
27
+ db.query(Likes(Ada, thing)); // [{ thing: "Coffee" }, { thing: "Chocolate" }]
24
28
 
25
29
  // Rewrite rules + grounded arithmetic, recursion, nondeterminism.
26
- const x = v<number>("x");
27
- db.rule(rel("fact")(x), iff(gt(x, 0), mul(x, rel("fact")(sub(x, 1))), 1));
28
- db.evalJs(rel("fact")(5)); // [120]
29
-
30
- // Pass a TypeScript object straight in (auto-grounded), operated on by a TS function.
31
- db.op("balance-of", (args) => [ValueAtom((args[0] as GroundedAtom).jsValue<{ balance: number }>().balance)]);
32
- const account = { owner: "Tom", balance: 100 };
33
- db.evalJs(rel("balance-of")(account)); // [100]
34
- db.evalJs(m`(balance-of ${account})`); // [100], same, via the template
35
-
36
- // Async grounded ops, awaited.
37
- db.asyncOp("fetch", async () => [ValueAtom(await getTemp())]);
38
- await db.evalJsAsync(rel("fetch")());
30
+ db.rule(fact(x), If(gt(x, 0), mul(x, fact(sub(x, 1))), 1));
31
+ db.evalJs(fact(5)); // [120]
32
+
33
+ // Grounded functions: a plain typed function, args auto-unwrapped, result auto-grounded.
34
+ db.fn("balance-of", (a: { balance: number }) => a.balance);
35
+ db.evalJs(m`(balance-of ${{ owner: "Tom", balance: 100 }})`); // [100]
36
+
37
+ // Call MeTTa functions from TypeScript, quick or typed.
38
+ db.call.fact(5); // [120]
39
+ const factorial = db.import<[number], number>("fact");
40
+ factorial(6); // 720
41
+ ```
42
+
43
+ ## The two term surfaces
44
+
45
+ - **Proxies + combinators.** `names()` and `vars()` mint names and variables (`const { parent, x } = ...`), and the capitalized combinators build the special forms: `If`, `Case`, `Let`, `LetStar`, `Match`, `Superpose`, `Collapse`, `Empty`, `Unify`, `Sealed`, `Quote`. Lowercase builders cover the grounded ops: `add`/`sub`/`mul`/`div`/`mod`, `eq`/`gt`/`lt`/`ge`/`le`, `and`/`or`/`not`, `carAtom`/`cdrAtom`/`consAtom`/`deconsAtom`, and `list`/`nil`/`e`. Builders compose, so nested patterns and repeated variables are just nested calls.
46
+ - **The tagged template `m\`...\`` (and `mAll` for several atoms)** runs the real parser, so it expresses every MeTTa form, and `${value}` auto-grounds, which is the easiest way to drop a TS object in.
47
+
48
+ ## The runner and the host bridge
49
+
50
+ `mettaDB()` keeps MeTTa's two query mechanisms distinct: `query(pattern)` does `match &self` over stored atoms and returns binding rows (keys inferred from the pattern, or typed by an explicit `vars` map); `eval(atom)` (and `evalJs`, `evalAsync`, `evalJsAsync`) rewrites with the `=` rules and returns the nondeterministic results.
51
+
52
+ The host bridge runs both directions:
53
+
54
+ - **TypeScript into MeTTa (grounded functions).** `db.fn("name", fn)` registers a plain typed function with arguments auto-unwrapped to JS and the result auto-grounded; `db.fns({ ... })` registers several at once keyed by name; `db.asyncFn` awaits an async function. The raw `db.op`/`db.asyncOp` stay for full atom control (multiple results, custom matching).
55
+ - **MeTTa into TypeScript (backward import).** `db.call.<name>(...)` builds and evaluates `(<name> ...args)` and returns every result unwrapped to JS; use bracket access for hyphenated names (`db.call["is-even"](4)`). `db.import("name")` returns a callable.
56
+
57
+ ### Typing the host bridge
58
+
59
+ Pass a schema to `mettaDB` and `call`, `import`, and `fn` become statically typed; with no schema they stay permissive. Both an `interface` and a `type` schema work.
60
+
61
+ ```ts
62
+ interface Api {
63
+ fact: (n: number) => number;
64
+ isEven: (n: number) => boolean;
65
+ }
66
+ const db = mettaDB<Api>();
67
+ db.call.fact(5); // number[]
68
+ const factorial = db.import("fact"); // (n: number) => number | undefined
69
+ db.fn("fact", (n: number) => n + 1); // checked against the schema
70
+ // db.fn("fact", (s: string) => s) // compile error: wrong signature
39
71
  ```
40
72
 
41
- ## The two surfaces
73
+ `ground(x)` is the primitive behind auto-grounding, and `patternVars(atom)` returns the free variables of a pattern (what `query` uses to infer row keys).
42
74
 
43
- - Typed builders construct terms with static types: `S`/`v`/`e`/`rel`, `rule`/`decl`/`arrow`, the special forms `iff`/`caseOf`/`lett`/`letStar`/`matchSelf`/`superpose`/`collapse`/`empty`/`unify`, the grounded ops `add`/`sub`/`mul`/`div`/`mod`, `eq`/`gt`/`lt`/`ge`/`le`, `and`/`or`/`not`, `carAtom`/`cdrAtom`/`consAtom`, and `list`/`nil`. Builders compose, so nested patterns and repeated variables are just nested calls.
44
- - The tagged template `m\`...\`` (and `mAll` for several atoms) runs the real parser, so it expresses every MeTTa form, and `${value}` auto-grounds (the easiest way to drop a TS object in).
75
+ ## Typed source queries
45
76
 
46
- ## The runner
77
+ `db.q("...")` runs `match &self` from a plain MeTTa source string and types the result rows by the pattern's `$`-variables, extracted at compile time. The keys are known and autocompleted, and a key that is not a variable in the source is a compile error.
78
+
79
+ ```ts
80
+ const rows = db.q("(Likes Ada $thing)"); // Array<{ thing: unknown }>
81
+ rows[0]!.thing; // ok, autocompleted
82
+ // rows[0]!.other // compile error: not a variable in the source
83
+ ```
47
84
 
48
- `mettaDB()` keeps MeTTa's two query mechanisms distinct: `query(pattern, vars)` does `match &self` over stored atoms and returns typed binding rows; `eval(atom)` (and `evalJs`, `evalAsync`, `evalJsAsync`) rewrites with the `=` rules and returns the nondeterministic results. `op`/`asyncOp` register TypeScript functions as grounded operations. `ground(x)` is the primitive behind auto-grounding.
85
+ This types the variable *structure*, not the result *values* (those come from runtime rewriting, which the type system cannot evaluate), so values are `unknown`. It works on a plain string, not the `m\`\`` tag: TypeScript widens a tagged template's text to `string`, which discards the literal the type-level parser needs. For a builder-form query with the same auto-inferred keys, use `db.query(pattern)`.
86
+
87
+ ## JSON and dict-spaces
88
+
89
+ `db.useJson()` enables the JSON module, then the `jsonEncode`/`jsonDecode`/`dictSpace`/`getKeys`/`getValue` builders bridge JSON and MeTTa spaces. `json-decode` turns a JSON object into a dict-space of `(key value)` pairs, so a fetched payload becomes a queryable space.
90
+
91
+ ```ts
92
+ const db = mettaDB().useJson();
93
+ db.evalJs(jsonEncode(42)); // ["42"]
94
+ const doc = jsonDecode('{"name": "Ada", "age": 36}'); // a dict-space
95
+ db.evalFirst(getValue(doc, "name")); // "Ada" (JSON keys decode to strings)
96
+ ```
49
97
 
50
98
  ## License
51
99
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Atom, VariableAtom, SymbolAtom, ExpressionAtom, MeTTa } from '@metta-ts/hyperon';
1
+ import { Atom, ExpressionAtom, SymbolAtom, VariableAtom, MeTTa } from '@metta-ts/hyperon';
2
2
  export { Atom, GroundedAtom, ValueAtom, atomToJs } from '@metta-ts/hyperon';
3
3
 
4
4
  /** A typed variable. The phantom `T` is the JS type its binding unwraps to in a query result; it is a
@@ -6,25 +6,43 @@ export { Atom, GroundedAtom, ValueAtom, atomToJs } from '@metta-ts/hyperon';
6
6
  type Var<T = unknown> = VariableAtom & {
7
7
  readonly __varType?: T;
8
8
  };
9
- /** Anything a builder accepts in term position: an atom (incl. a {@link Var}), or a JS value to ground. */
10
- type Term = Atom | number | string | boolean | bigint | object | null | undefined;
9
+ /** Brand marking a functor/symbol builder minted by {@link names}. A branded builder is a callable
10
+ * object (TS call-signature pattern) whose brand carries its head symbol, so {@link ground} can turn a
11
+ * bare, uncalled builder into that symbol. A real `unique symbol` (runtime value and type-level key)
12
+ * cannot collide with user data. */
13
+ declare const HEAD: unique symbol;
14
+ /** A name minted by {@link names}: call it to apply the functor (`parent(a, b)` -> `(parent a b)`), or
15
+ * use it bare as a term, where it grounds to its symbol (`Ada` -> the symbol `Ada`). */
16
+ type Name = ((...args: Term[]) => ExpressionAtom) & {
17
+ readonly [HEAD]: SymbolAtom;
18
+ };
19
+ /** Anything a builder accepts in term position: an atom (incl. a {@link Var}), a {@link Name}, or a JS
20
+ * value to ground. `Name` is a function, hence covered by `object`, but is listed for intent. */
21
+ type Term = Atom | Name | number | string | boolean | bigint | object | null | undefined;
11
22
  /** Extract a {@link Var}'s phantom type (defaults to `unknown`). */
12
23
  type VarValue<X> = X extends Var<infer T> ? T : unknown;
13
- /** A fresh typed variable: `v("x")` or `v<number>("n")`. */
14
- declare const v: <T = unknown>(name: string) => Var<T>;
15
- /** `S` builds a symbol two ways: as a function `S("foo")` or as a property `S.foo`. */
16
- type SymbolBuilder = ((name: string) => SymbolAtom) & {
17
- readonly [key: string]: SymbolAtom;
18
- };
19
- declare const S: SymbolBuilder;
20
- /** Coerce a {@link Term} to an atom: atoms and variables pass through; every other JS value is grounded. */
24
+ /** Coerce a {@link Term} to an atom: atoms and variables pass through; a bare builder becomes its head
25
+ * symbol; every other JS value is grounded. */
21
26
  declare function ground(x: Term): Atom;
27
+ /** A proxy that mints a {@link Name} per property, memoised so `p.parent` is stable within one scope:
28
+ * `const { parent, Ada, Bob } = names()`. Symbols and functors share this one namespace; a name is a
29
+ * symbol when used bare and a functor when applied. Optionally type the known names:
30
+ * `names<{ parent: unknown; Ada: unknown }>()` restricts the keys. */
31
+ type Names<K extends string = string> = Record<K, Name>;
32
+ declare function names<K extends string = string>(): Names<K>;
33
+ /** A proxy that mints a fresh {@link Var} per property, memoised so `q.x` is the same variable
34
+ * everywhere in one scope: `const { x, y } = vars()`. Type the bindings with a record:
35
+ * `const { n, name } = vars<{ n: number; name: string }>()`. */
36
+ type Vars<T extends Record<string, unknown> = Record<string, unknown>> = {
37
+ readonly [K in keyof T]: Var<T[K]>;
38
+ };
39
+ declare function vars<T extends Record<string, unknown> = Record<string, unknown>>(): Vars<T>;
40
+ /** Collect the distinct variables occurring in a pattern, in first-seen order. Backs auto-inferred
41
+ * query rows: the free variables ARE the columns. */
42
+ declare function patternVars(atom: Atom): Var[];
22
43
  /** A raw expression (tuple) from its items, each auto-grounded: `e(x, y, x)` builds `($x $y $x)`. Use it
23
- * for patterns that are not headed by a functor, e.g. repeated-variable patterns or pair structures. */
44
+ * for patterns not headed by a functor, e.g. repeated-variable patterns or pair structures. */
24
45
  declare const e: (...items: Term[]) => ExpressionAtom;
25
- /** A functor builder: `rel("parent")` returns `(a, b) => (parent a b)`, auto-grounding each argument.
26
- * Builders compose, so nested patterns like `rel("swap")(rel("Pair")(x, y))` are just function calls. */
27
- declare function rel(name: string): (...args: Term[]) => ExpressionAtom;
28
46
  /** The empty expression `()`, MeTTa's conventional empty/nil list. */
29
47
  declare const nil: () => ExpressionAtom;
30
48
  /** A Lisp-style cons list: `list([a, b, c])` builds `(:: a (:: b (:: c ())))`. Override the constructor
@@ -41,23 +59,28 @@ declare const decl: (subject: Term, type: Term) => ExpressionAtom;
41
59
  /** A function type `(-> A B ... R)`. */
42
60
  declare const arrow: (...types: Term[]) => ExpressionAtom;
43
61
  /** `(if cond then else)`. Only the taken branch is evaluated. */
44
- declare const iff: (cond: Term, then: Term, els: Term) => ExpressionAtom;
62
+ declare const If: (cond: Term, then: Term, els: Term) => ExpressionAtom;
45
63
  /** `(case scrutinee ((pat body) ...))`, sequential mutually-exclusive pattern matching. */
46
- declare const caseOf: (scrutinee: Term, cases: ReadonlyArray<readonly [Term, Term]>) => ExpressionAtom;
64
+ declare const Case: (scrutinee: Term, cases: ReadonlyArray<readonly [Term, Term]>) => ExpressionAtom;
47
65
  /** `(let pattern value body)`: unify `value` against `pattern`, then evaluate `body`. */
48
- declare const lett: (pattern: Term, value: Term, body: Term) => ExpressionAtom;
66
+ declare const Let: (pattern: Term, value: Term, body: Term) => ExpressionAtom;
49
67
  /** `(let* ((pat val) ...) body)`: sequential lets. */
50
- declare const letStar: (bindings: ReadonlyArray<readonly [Term, Term]>, body: Term) => ExpressionAtom;
68
+ declare const LetStar: (bindings: ReadonlyArray<readonly [Term, Term]>, body: Term) => ExpressionAtom;
51
69
  /** `(match space pattern template)`. Defaults to `&self`, the program's own space. */
52
- declare const matchSelf: (pattern: Term, template: Term, space?: Term) => ExpressionAtom;
70
+ declare const Match: (pattern: Term, template: Term, space?: Term) => ExpressionAtom;
53
71
  /** `(superpose (a b ...))`: a nondeterministic choice among the items. */
54
- declare const superpose: (...items: Term[]) => ExpressionAtom;
72
+ declare const Superpose: (...items: Term[]) => ExpressionAtom;
55
73
  /** `(collapse x)`: gather all nondeterministic results of `x` into a single expression. */
56
- declare const collapse: (x: Term) => ExpressionAtom;
74
+ declare const Collapse: (x: Term) => ExpressionAtom;
57
75
  /** `(empty)`: no results, which prunes a branch. */
58
- declare const empty: () => ExpressionAtom;
76
+ declare const Empty: () => ExpressionAtom;
59
77
  /** `(unify a b then else)`: low-level unification with then/else continuations. */
60
- declare const unify: (a: Term, b: Term, then: Term, els: Term) => ExpressionAtom;
78
+ declare const Unify: (a: Term, b: Term, then: Term, els: Term) => ExpressionAtom;
79
+ /** `(sealed (vars...) body)`: alpha-rename `body`'s variables (except `vars`) to fresh names, so a
80
+ * template can be reused without variable capture. */
81
+ declare const Sealed: (vars: ReadonlyArray<Term>, body: Term) => ExpressionAtom;
82
+ /** `(quote x)`: hold `x` as data so the interpreter does not evaluate it. */
83
+ declare const Quote: (x: Term) => ExpressionAtom;
61
84
  /** Arithmetic grounded operations. */
62
85
  declare const add: (a: Term, b: Term) => ExpressionAtom;
63
86
  declare const sub: (a: Term, b: Term) => ExpressionAtom;
@@ -80,15 +103,13 @@ declare const cdrAtom: (x: Term) => ExpressionAtom;
80
103
  declare const consAtom: (head: Term, tail: Term) => ExpressionAtom;
81
104
  /** `(decons-atom expr)`: split a non-empty expression into `(head tail)`. */
82
105
  declare const deconsAtom: (x: Term) => ExpressionAtom;
83
- /** `(quote x)`: hold `x` as data so the interpreter does not evaluate it. */
84
- declare const quote: (x: Term) => ExpressionAtom;
85
106
  /** Type introspection. `getType` reports an atom's declared/inferred type; `getMetatype` reports its
86
107
  * meta-type (`Symbol`/`Variable`/`Expression`/`Grounded`). */
87
108
  declare const getType: (x: Term) => ExpressionAtom;
88
109
  declare const getMetatype: (x: Term) => ExpressionAtom;
89
- /** Assertions for eDSL tests. Each returns the unit atom `()` on success and an
90
- * `(Error ...)` atom on failure, matching Hyperon's stdlib. `assertEqual` compares evaluated results;
91
- * `assertAlphaEqual` compares up to a consistent renaming of variables. */
110
+ /** Assertions for eDSL tests. Each returns the unit atom `()` on success and an `(Error ...)` atom on
111
+ * failure, matching Hyperon's stdlib. `assertEqual` compares evaluated results; `assertAlphaEqual`
112
+ * compares up to a consistent renaming of variables. */
92
113
  declare const assertEqual: (a: Term, b: Term) => ExpressionAtom;
93
114
  declare const assertAlphaEqual: (a: Term, b: Term) => ExpressionAtom;
94
115
  /** Set operations over the (collapsed) results of their arguments, deduplicating modulo equality.
@@ -99,21 +120,67 @@ declare const intersection: (a: Term, b: Term) => ExpressionAtom;
99
120
  declare const subtraction: (a: Term, b: Term) => ExpressionAtom;
100
121
  /** `(println! x)`: print `x` (a side effect); returns the unit atom `()`. */
101
122
  declare const println: (x: Term) => ExpressionAtom;
102
- /** `(sealed (vars...) body)`: alpha-rename `body`'s variables (except `vars`) to fresh names, so a
103
- * template can be reused without variable capture. */
104
- declare const sealed: (vars: ReadonlyArray<Term>, body: Term) => ExpressionAtom;
123
+ /** `(json-encode x)`: encode a MeTTa atom (string, number, expression, dict-space, or a mix) to a JSON
124
+ * string. */
125
+ declare const jsonEncode: (x: Term) => ExpressionAtom;
126
+ /** `(json-decode s)`: decode a JSON string to MeTTa (array to expression, object to a dict-space of
127
+ * `(key value)` pairs, string to string, number to number). */
128
+ declare const jsonDecode: (x: Term) => ExpressionAtom;
129
+ /** `(dict-space ((k v) ...))`: build a grounded Space of `(key value)` pairs from key-value tuples. */
130
+ declare const dictSpace: (pairs: ReadonlyArray<readonly [Term, Term]>) => ExpressionAtom;
131
+ /** `(get-keys space)`: every key in a dict-space, one result per key. */
132
+ declare const getKeys: (x: Term) => ExpressionAtom;
133
+ /** `(get-value space key)`: the value tied to `key` in a dict-space, empty if absent. */
134
+ declare const getValue: (a: Term, b: Term) => ExpressionAtom;
105
135
 
106
136
  /** Parse a MeTTa template into the atoms it contains, with `${...}` holes auto-grounded. */
107
137
  declare function mAll(strings: TemplateStringsArray, ...values: Term[]): Atom[];
108
138
  /** Parse a MeTTa template into one top-level atom. Throws otherwise; use {@link mAll} for several. */
109
139
  declare function m(strings: TemplateStringsArray, ...values: Term[]): Atom;
140
+ /** Parse one atom from a plain source string (no interpolation). Throws unless the source is exactly one
141
+ * atom. Backs the typed source query {@link MettaDB.q}. */
142
+ declare function parseSource(src: string): Atom;
143
+
144
+ /** Characters allowed in a MeTTa variable name after the `$`. */
145
+ type IdentChar = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "_" | "-";
146
+ /** The leading identifier of `S` (characters up to the first non-identifier character). */
147
+ type IdentHead<S extends string, Acc extends string = ""> = S extends `${infer C}${infer R}` ? C extends IdentChar ? IdentHead<R, `${Acc}${C}`> : Acc : Acc;
148
+ /** `S` with its leading identifier removed. */
149
+ type AfterIdent<S extends string> = S extends `${infer C}${infer R}` ? C extends IdentChar ? AfterIdent<R> : S : S;
150
+ /** The union of every `$`-prefixed variable name in the source string `S` (a bare `$` yields nothing). */
151
+ type SourceVars<S extends string> = S extends `${string}$${infer Rest}` ? (IdentHead<Rest> extends "" ? never : IdentHead<Rest>) | SourceVars<AfterIdent<Rest>> : never;
152
+ /** A typed query row: each variable in the source mapped to its (runtime-unwrapped) JS value. */
153
+ type SourceRow<S extends string> = {
154
+ [K in SourceVars<S>]: unknown;
155
+ };
110
156
 
111
- /** One typed binding row from a {@link MettaDB.query}: each requested variable mapped to its JS value. */
157
+ /** One typed binding row from {@link MettaDB.query} with explicit vars: each requested variable mapped
158
+ * to its JS value. */
112
159
  type Row<V extends Record<string, Var>> = {
113
160
  [K in keyof V]: VarValue<V[K]>;
114
161
  };
115
- /** A typed MeTTa runner. Build it with {@link mettaDB}. */
116
- declare class MettaDB {
162
+ /** Any function, used as the permissive default for names outside a schema. */
163
+ type AnyFn = (...args: never[]) => unknown;
164
+ /** A schema mapping MeTTa function names to their TypeScript signatures, for a typed runner:
165
+ * `mettaDB<{ fact: (n: number) => number }>()`. Both an `interface` and a `type` work. */
166
+ type FnSchema = Record<string, AnyFn>;
167
+ /** The argument tuple / return type of a schema entry (like `Parameters`/`ReturnType`, but tolerant of
168
+ * a non-function member, which extracts as `never`). */
169
+ type FnArgs<F> = F extends (...a: infer A) => unknown ? A : never;
170
+ type FnRet<F> = F extends (...a: never[]) => infer R ? R : never;
171
+ /** A MeTTa function imported as a typed TypeScript callable (see {@link MettaDB.import}). Returns the
172
+ * first result unwrapped to JS, or `undefined` when the call produces no result. */
173
+ type ImportedFn<Args extends unknown[], Ret> = (...args: Args) => Ret | undefined;
174
+ /** Proxy surface for calling MeTTa functions by name. A name in the schema `S` is typed by its
175
+ * signature (`db.call.fact(5): number[]`); any other name falls back to `unknown[]`. Bracket access
176
+ * handles hyphenated names: `db.call["is-son"]("Bob", "Tom")`. */
177
+ type CallProxy<S> = {
178
+ [K in keyof S]: (...args: FnArgs<S[K]>) => FnRet<S[K]>[];
179
+ } & Record<string, (...args: Term[]) => unknown[]>;
180
+ /** A typed MeTTa runner. Build it with {@link mettaDB}. The optional schema `S` types the host bridge
181
+ * (`call`, `import`, `fn`); the default is an empty schema, so with no schema those stay permissive
182
+ * (`db.call.<any>(...)` is `unknown[]`, `db.import(name)` a permissive callable) but still work. */
183
+ declare class MettaDB<S = Record<never, never>> {
117
184
  /** The underlying hyperon runner, for anything the eDSL does not wrap. */
118
185
  readonly metta: MeTTa;
119
186
  /** Add atoms (facts, rules, type declarations) to the program space. JS values are auto-grounded. */
@@ -136,16 +203,49 @@ declare class MettaDB {
136
203
  evalAsync(atom: Term): Promise<Atom[]>;
137
204
  /** Like {@link evalJs}, awaiting async grounded operations. */
138
205
  evalJsAsync(atom: Term): Promise<unknown[]>;
139
- /** `match &self pattern` over stored atoms, returning one typed row of JS bindings per match. */
206
+ /** `match &self pattern` over stored atoms, returning one binding row per match. With no `vars`, the
207
+ * row keys are inferred from the pattern's free variables and the values come back as plain JS
208
+ * (typed `unknown`); pass an explicit `vars` map to get statically-typed values. */
209
+ query(pattern: Term): Array<Record<string, unknown>>;
140
210
  query<V extends Record<string, Var>>(pattern: Term, vars: V): Array<Row<V>>;
141
- /** Register a synchronous TypeScript function as a grounded operation callable from MeTTa. */
211
+ /** `match &self` from a plain MeTTa source string, with the result rows typed by the pattern's
212
+ * `$`-variables: `db.q("(Likes Ada $thing)")` returns `Array<{ thing: unknown }>`, keys inferred and
213
+ * autocompleted at compile time. Values are `unknown` (they come from runtime rewriting). For the
214
+ * builder form use {@link query}. */
215
+ q<Src extends string>(src: Src): Array<SourceRow<Src>>;
216
+ /** Register a synchronous TypeScript function as a raw grounded operation (atoms in, atoms out). */
142
217
  op(name: string, fn: (args: Atom[]) => Atom[]): this;
143
- /** Register an async TypeScript function (I/O) as a grounded operation; await it via {@link evalAsync}. */
218
+ /** Register an async TypeScript function (I/O) as a raw grounded operation; await it via
219
+ * {@link evalAsync}. */
144
220
  asyncOp(name: string, fn: (args: Atom[]) => Promise<Atom[]>): this;
221
+ /** Shared body of {@link fn}/{@link fns}: unwrap args to JS, call, ground the result. */
222
+ private registerFn;
223
+ /** Register a plain typed function as a grounded operation, with arguments auto-unwrapped to JS and the
224
+ * single result auto-grounded: `db.fn("balance-of", (a: {balance: number}) => a.balance)`. When the
225
+ * name is in the schema `S`, `fn` is checked against its declared signature. Return an array from `fn`
226
+ * to yield it as one grounded list; use {@link op} for multiple (nondeterministic) results or full
227
+ * atom control. */
228
+ fn<K extends string>(name: K, fn: K extends keyof S ? S[K] : AnyFn): this;
229
+ /** Register several typed functions at once, keyed by name: `db.fns({ inc: n => n+1, ... })`. The JS
230
+ * key becomes the MeTTa token. */
231
+ fns(map: Record<string, AnyFn>): this;
232
+ /** Register a plain async typed function as a grounded operation (args unwrapped, result grounded). */
233
+ asyncFn(name: string, fn: (...args: never[]) => Promise<unknown>): this;
234
+ /** Import a MeTTa function as a typed TypeScript callable. Arguments are auto-grounded, the call is
235
+ * `(name ...args)`, and the first result is unwrapped to JS. A name in the schema `S` is typed from
236
+ * its signature (`db.import("fact")`); a name outside the schema returns a permissive callable. */
237
+ import<K extends string>(name: K): K extends keyof S ? ImportedFn<FnArgs<S[K]>, FnRet<S[K]>> : ImportedFn<unknown[], unknown>;
238
+ /** Proxy for calling MeTTa functions by name from TypeScript. `db.call.fib(5)` evaluates `(fib 5)` and
239
+ * returns each result unwrapped to JS; bracket access handles hyphenated names. */
240
+ get call(): CallProxy<S>;
241
+ /** Enable the JSON module on this runner, registering `json-encode`, `json-decode`, `dict-space`,
242
+ * `get-keys`, and `get-value` (see the builders of the same name). Chainable. */
243
+ useJson(): this;
145
244
  /** Run raw MeTTa source, one result group per `!`-query. */
146
245
  run(src: string): Atom[][];
147
246
  }
148
- /** Create an ergonomic, typed MeTTa runner. */
149
- declare const mettaDB: () => MettaDB;
247
+ /** Create an ergonomic, typed MeTTa runner. Pass a schema to type the host bridge:
248
+ * `mettaDB<{ fact: (n: number) => number }>()`. */
249
+ declare const mettaDB: <S = Record<never, never>>() => MettaDB<S>;
150
250
 
151
- export { MettaDB, type Row, S, type SymbolBuilder, type Term, type Var, type VarValue, add, and, arrow, assertAlphaEqual, assertEqual, carAtom, caseOf, cdrAtom, collapse, consAtom, decl, deconsAtom, div, e, empty, eq, ge, getMetatype, getType, ground, gt, iff, intersection, le, letStar, lett, list, lt, m, mAll, matchSelf, mettaDB, mod, mul, nil, not, or, println, quote, rel, rule, sealed, sub, subtraction, superpose, unify, union, unique, v };
251
+ export { type CallProxy, Case, Collapse, Empty, type FnSchema, If, type ImportedFn, Let, LetStar, Match, MettaDB, type Name, type Names, Quote, type Row, Sealed, type SourceRow, type SourceVars, Superpose, type Term, Unify, type Var, type VarValue, type Vars, add, and, arrow, assertAlphaEqual, assertEqual, carAtom, cdrAtom, consAtom, decl, deconsAtom, dictSpace, div, e, eq, ge, getKeys, getMetatype, getType, getValue, ground, gt, intersection, jsonDecode, jsonEncode, le, list, lt, m, mAll, mettaDB, mod, mul, names, nil, not, or, parseSource, patternVars, println, rule, sub, subtraction, union, unique, vars };
package/dist/index.js CHANGED
@@ -4,23 +4,63 @@ import {
4
4
  S as hS,
5
5
  V,
6
6
  E,
7
- ValueAtom
7
+ ValueAtom,
8
+ VariableAtom,
9
+ ExpressionAtom
8
10
  } from "@metta-ts/hyperon";
9
- var v = (name) => V(name);
10
- var S = new Proxy(((name) => hS(name)), {
11
- get(_target, prop) {
12
- return typeof prop === "string" ? hS(prop) : void 0;
13
- }
14
- });
11
+ var HEAD = /* @__PURE__ */ Symbol("metta.edsl.head");
12
+ function isName(x) {
13
+ return typeof x === "function" && x[HEAD] !== void 0;
14
+ }
15
15
  function ground(x) {
16
16
  if (x instanceof Atom) return x;
17
+ if (isName(x)) return x[HEAD];
17
18
  return ValueAtom(x);
18
19
  }
19
- var e = (...items) => E(...items.map(ground));
20
- function rel(name) {
20
+ function makeName(name) {
21
21
  const head = hS(name);
22
- return (...args) => E(head, ...args.map(ground));
22
+ const fn = (...args) => E(head, ...args.map(ground));
23
+ return Object.assign(fn, { [HEAD]: head, toString: () => name });
24
+ }
25
+ function names() {
26
+ const cache = /* @__PURE__ */ new Map();
27
+ return new Proxy(/* @__PURE__ */ Object.create(null), {
28
+ get(_t, prop) {
29
+ if (typeof prop !== "string") return void 0;
30
+ let n = cache.get(prop);
31
+ if (n === void 0) {
32
+ n = makeName(prop);
33
+ cache.set(prop, n);
34
+ }
35
+ return n;
36
+ }
37
+ });
38
+ }
39
+ function vars() {
40
+ const cache = /* @__PURE__ */ new Map();
41
+ return new Proxy(/* @__PURE__ */ Object.create(null), {
42
+ get(_t, prop) {
43
+ if (typeof prop !== "string") return void 0;
44
+ let x = cache.get(prop);
45
+ if (x === void 0) {
46
+ x = V(prop);
47
+ cache.set(prop, x);
48
+ }
49
+ return x;
50
+ }
51
+ });
23
52
  }
53
+ function patternVars(atom) {
54
+ const seen = /* @__PURE__ */ new Map();
55
+ const walk = (a) => {
56
+ if (a instanceof VariableAtom) {
57
+ if (!seen.has(a.name())) seen.set(a.name(), a);
58
+ } else if (a instanceof ExpressionAtom) for (const c of a.children()) walk(c);
59
+ };
60
+ walk(atom);
61
+ return [...seen.values()];
62
+ }
63
+ var e = (...items) => E(...items.map(ground));
24
64
  var nil = () => E();
25
65
  function list(items, opts) {
26
66
  const cons = hS(opts?.cons ?? "::");
@@ -30,20 +70,23 @@ function list(items, opts) {
30
70
  }
31
71
 
32
72
  // src/forms.ts
33
- import { E as E2, S as S2 } from "@metta-ts/hyperon";
34
- var rule = (head, body) => E2(S2("="), ground(head), ground(body));
35
- var decl = (subject, type) => E2(S2(":"), ground(subject), ground(type));
36
- var arrow = (...types) => E2(S2("->"), ...types.map(ground));
37
- var iff = (cond, then, els) => E2(S2("if"), ground(cond), ground(then), ground(els));
38
- var caseOf = (scrutinee, cases) => E2(S2("case"), ground(scrutinee), E2(...cases.map(([pat, body]) => E2(ground(pat), ground(body)))));
39
- var lett = (pattern, value, body) => E2(S2("let"), ground(pattern), ground(value), ground(body));
40
- var letStar = (bindings, body) => E2(S2("let*"), E2(...bindings.map(([pat, val]) => E2(ground(pat), ground(val)))), ground(body));
41
- var matchSelf = (pattern, template, space = S2("&self")) => E2(S2("match"), ground(space), ground(pattern), ground(template));
42
- var superpose = (...items) => E2(S2("superpose"), E2(...items.map(ground)));
43
- var collapse = (x) => E2(S2("collapse"), ground(x));
44
- var empty = () => E2(S2("empty"));
45
- var unify = (a, b, then, els) => E2(S2("unify"), ground(a), ground(b), ground(then), ground(els));
46
- var op2 = (name) => (a, b) => E2(S2(name), ground(a), ground(b));
73
+ import { E as E2, S } from "@metta-ts/hyperon";
74
+ var rule = (head, body) => E2(S("="), ground(head), ground(body));
75
+ var decl = (subject, type) => E2(S(":"), ground(subject), ground(type));
76
+ var arrow = (...types) => E2(S("->"), ...types.map(ground));
77
+ var If = (cond, then, els) => E2(S("if"), ground(cond), ground(then), ground(els));
78
+ var Case = (scrutinee, cases) => E2(S("case"), ground(scrutinee), E2(...cases.map(([pat, body]) => E2(ground(pat), ground(body)))));
79
+ var Let = (pattern, value, body) => E2(S("let"), ground(pattern), ground(value), ground(body));
80
+ var LetStar = (bindings, body) => E2(S("let*"), E2(...bindings.map(([pat, val]) => E2(ground(pat), ground(val)))), ground(body));
81
+ var Match = (pattern, template, space = S("&self")) => E2(S("match"), ground(space), ground(pattern), ground(template));
82
+ var Superpose = (...items) => E2(S("superpose"), E2(...items.map(ground)));
83
+ var Collapse = (x) => E2(S("collapse"), ground(x));
84
+ var Empty = () => E2(S("empty"));
85
+ var Unify = (a, b, then, els) => E2(S("unify"), ground(a), ground(b), ground(then), ground(els));
86
+ var Sealed = (vars2, body) => E2(S("sealed"), E2(...vars2.map(ground)), ground(body));
87
+ var Quote = (x) => E2(S("quote"), ground(x));
88
+ var op2 = (name) => (a, b) => E2(S(name), ground(a), ground(b));
89
+ var op1 = (name) => (x) => E2(S(name), ground(x));
47
90
  var add = op2("+");
48
91
  var sub = op2("-");
49
92
  var mul = op2("*");
@@ -54,15 +97,13 @@ var gt = op2(">");
54
97
  var lt = op2("<");
55
98
  var ge = op2(">=");
56
99
  var le = op2("<=");
57
- var op1 = (name) => (x) => E2(S2(name), ground(x));
58
100
  var and = op2("and");
59
101
  var or = op2("or");
60
102
  var not = op1("not");
61
103
  var carAtom = op1("car-atom");
62
104
  var cdrAtom = op1("cdr-atom");
63
- var consAtom = (head, tail) => E2(S2("cons-atom"), ground(head), ground(tail));
105
+ var consAtom = (head, tail) => E2(S("cons-atom"), ground(head), ground(tail));
64
106
  var deconsAtom = op1("decons-atom");
65
- var quote = op1("quote");
66
107
  var getType = op1("get-type");
67
108
  var getMetatype = op1("get-metatype");
68
109
  var assertEqual = op2("assertEqual");
@@ -72,13 +113,17 @@ var union = op2("union");
72
113
  var intersection = op2("intersection");
73
114
  var subtraction = op2("subtraction");
74
115
  var println = op1("println!");
75
- var sealed = (vars, body) => E2(S2("sealed"), E2(...vars.map(ground)), ground(body));
116
+ var jsonEncode = op1("json-encode");
117
+ var jsonDecode = op1("json-decode");
118
+ var dictSpace = (pairs) => E2(S("dict-space"), E2(...pairs.map(([k, v]) => E2(ground(k), ground(v)))));
119
+ var getKeys = op1("get-keys");
120
+ var getValue = op2("get-value");
76
121
 
77
122
  // src/template.ts
78
123
  import {
79
124
  SExprParser,
80
- SymbolAtom,
81
- ExpressionAtom,
125
+ SymbolAtom as SymbolAtom2,
126
+ ExpressionAtom as ExpressionAtom2,
82
127
  E as E3,
83
128
  standardTokenizer
84
129
  } from "@metta-ts/hyperon";
@@ -87,11 +132,11 @@ var SLOT_RE = /^__metta_ts_slot_(\d+)__$/;
87
132
  var sharedTokenizer;
88
133
  var tokenizer = () => sharedTokenizer ??= standardTokenizer();
89
134
  function substituteSlots(atom, slots) {
90
- if (atom instanceof SymbolAtom) {
135
+ if (atom instanceof SymbolAtom2) {
91
136
  const match = SLOT_RE.exec(atom.name());
92
137
  return match ? slots[Number(match[1])] : atom;
93
138
  }
94
- if (atom instanceof ExpressionAtom)
139
+ if (atom instanceof ExpressionAtom2)
95
140
  return E3(...atom.children().map((c) => substituteSlots(c, slots)));
96
141
  return atom;
97
142
  }
@@ -109,9 +154,21 @@ function m(strings, ...values) {
109
154
  );
110
155
  return atoms[0];
111
156
  }
157
+ function parseSource(src) {
158
+ const atoms = new SExprParser(src).parseAll(tokenizer());
159
+ if (atoms.length !== 1)
160
+ throw new Error(`parseSource: expected exactly one atom, got ${atoms.length}: ${src}`);
161
+ return atoms[0];
162
+ }
112
163
 
113
164
  // src/db.ts
114
- import { MeTTa, atomToJs } from "@metta-ts/hyperon";
165
+ import {
166
+ MeTTa,
167
+ E as E4,
168
+ S as S2,
169
+ atomToJs,
170
+ registerJsonModule
171
+ } from "@metta-ts/hyperon";
115
172
  var MettaDB = class {
116
173
  /** The underlying hyperon runner, for anything the eDSL does not wrap. */
117
174
  metta = new MeTTa();
@@ -158,41 +215,110 @@ var MettaDB = class {
158
215
  async evalJsAsync(atom) {
159
216
  return (await this.evalAsync(atom)).map(atomToJs);
160
217
  }
161
- /** `match &self pattern` over stored atoms, returning one typed row of JS bindings per match. */
162
- query(pattern, vars) {
163
- const set = this.metta.space().query(ground(pattern));
218
+ query(pattern, vars2) {
219
+ const pat = ground(pattern);
220
+ const set = this.metta.space().query(pat);
221
+ const cols = vars2 ?? Object.fromEntries(patternVars(pat).map((v) => [v.name(), v]));
164
222
  return set.frames.map((frame) => {
165
223
  const row = {};
166
- for (const key in vars) {
167
- const bound = frame.resolve(vars[key]);
224
+ for (const key in cols) {
225
+ const bound = frame.resolve(cols[key]);
168
226
  row[key] = bound === void 0 ? void 0 : atomToJs(bound);
169
227
  }
170
228
  return row;
171
229
  });
172
230
  }
173
- /** Register a synchronous TypeScript function as a grounded operation callable from MeTTa. */
231
+ /** `match &self` from a plain MeTTa source string, with the result rows typed by the pattern's
232
+ * `$`-variables: `db.q("(Likes Ada $thing)")` returns `Array<{ thing: unknown }>`, keys inferred and
233
+ * autocompleted at compile time. Values are `unknown` (they come from runtime rewriting). For the
234
+ * builder form use {@link query}. */
235
+ q(src) {
236
+ return this.query(parseSource(src));
237
+ }
238
+ /** Register a synchronous TypeScript function as a raw grounded operation (atoms in, atoms out). */
174
239
  op(name, fn) {
175
240
  this.metta.registerOperation(name, fn);
176
241
  return this;
177
242
  }
178
- /** Register an async TypeScript function (I/O) as a grounded operation; await it via {@link evalAsync}. */
243
+ /** Register an async TypeScript function (I/O) as a raw grounded operation; await it via
244
+ * {@link evalAsync}. */
179
245
  asyncOp(name, fn) {
180
246
  this.metta.registerAsyncOperation(name, fn);
181
247
  return this;
182
248
  }
249
+ /** Shared body of {@link fn}/{@link fns}: unwrap args to JS, call, ground the result. */
250
+ registerFn(name, fn) {
251
+ return this.op(name, (args) => [ground(fn(...args.map(atomToJs)))]);
252
+ }
253
+ /** Register a plain typed function as a grounded operation, with arguments auto-unwrapped to JS and the
254
+ * single result auto-grounded: `db.fn("balance-of", (a: {balance: number}) => a.balance)`. When the
255
+ * name is in the schema `S`, `fn` is checked against its declared signature. Return an array from `fn`
256
+ * to yield it as one grounded list; use {@link op} for multiple (nondeterministic) results or full
257
+ * atom control. */
258
+ fn(name, fn) {
259
+ return this.registerFn(name, fn);
260
+ }
261
+ /** Register several typed functions at once, keyed by name: `db.fns({ inc: n => n+1, ... })`. The JS
262
+ * key becomes the MeTTa token. */
263
+ fns(map) {
264
+ for (const [name, fn] of Object.entries(map)) this.registerFn(name, fn);
265
+ return this;
266
+ }
267
+ /** Register a plain async typed function as a grounded operation (args unwrapped, result grounded). */
268
+ asyncFn(name, fn) {
269
+ return this.asyncOp(name, async (args) => [
270
+ ground(await fn(...args.map(atomToJs)))
271
+ ]);
272
+ }
273
+ /** Import a MeTTa function as a typed TypeScript callable. Arguments are auto-grounded, the call is
274
+ * `(name ...args)`, and the first result is unwrapped to JS. A name in the schema `S` is typed from
275
+ * its signature (`db.import("fact")`); a name outside the schema returns a permissive callable. */
276
+ import(name) {
277
+ const fn = (...args) => {
278
+ const results = this.evalJs(callExpr(name, args));
279
+ return results.length === 0 ? void 0 : results[0];
280
+ };
281
+ return fn;
282
+ }
283
+ /** Proxy for calling MeTTa functions by name from TypeScript. `db.call.fib(5)` evaluates `(fib 5)` and
284
+ * returns each result unwrapped to JS; bracket access handles hyphenated names. */
285
+ get call() {
286
+ return new Proxy(/* @__PURE__ */ Object.create(null), {
287
+ get: (_t, prop) => typeof prop === "string" ? (...args) => this.evalJs(callExpr(prop, args)) : void 0
288
+ });
289
+ }
290
+ /** Enable the JSON module on this runner, registering `json-encode`, `json-decode`, `dict-space`,
291
+ * `get-keys`, and `get-value` (see the builders of the same name). Chainable. */
292
+ useJson() {
293
+ registerJsonModule(this.metta);
294
+ return this;
295
+ }
183
296
  /** Run raw MeTTa source, one result group per `!`-query. */
184
297
  run(src) {
185
298
  return this.metta.run(src);
186
299
  }
187
300
  };
301
+ function callExpr(name, args) {
302
+ return E4(S2(name), ...args.map(ground));
303
+ }
188
304
  var mettaDB = () => new MettaDB();
189
305
 
190
306
  // src/index.ts
191
307
  import { Atom as Atom3, ValueAtom as ValueAtom2, atomToJs as atomToJs2 } from "@metta-ts/hyperon";
192
308
  export {
193
309
  Atom3 as Atom,
310
+ Case,
311
+ Collapse,
312
+ Empty,
313
+ If,
314
+ Let,
315
+ LetStar,
316
+ Match,
194
317
  MettaDB,
195
- S,
318
+ Quote,
319
+ Sealed,
320
+ Superpose,
321
+ Unify,
196
322
  ValueAtom2 as ValueAtom,
197
323
  add,
198
324
  and,
@@ -201,47 +327,43 @@ export {
201
327
  assertEqual,
202
328
  atomToJs2 as atomToJs,
203
329
  carAtom,
204
- caseOf,
205
330
  cdrAtom,
206
- collapse,
207
331
  consAtom,
208
332
  decl,
209
333
  deconsAtom,
334
+ dictSpace,
210
335
  div,
211
336
  e,
212
- empty,
213
337
  eq,
214
338
  ge,
339
+ getKeys,
215
340
  getMetatype,
216
341
  getType,
342
+ getValue,
217
343
  ground,
218
344
  gt,
219
- iff,
220
345
  intersection,
346
+ jsonDecode,
347
+ jsonEncode,
221
348
  le,
222
- letStar,
223
- lett,
224
349
  list,
225
350
  lt,
226
351
  m,
227
352
  mAll,
228
- matchSelf,
229
353
  mettaDB,
230
354
  mod,
231
355
  mul,
356
+ names,
232
357
  nil,
233
358
  not,
234
359
  or,
360
+ parseSource,
361
+ patternVars,
235
362
  println,
236
- quote,
237
- rel,
238
363
  rule,
239
- sealed,
240
364
  sub,
241
365
  subtraction,
242
- superpose,
243
- unify,
244
366
  union,
245
367
  unique,
246
- v
368
+ vars
247
369
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metta-ts/edsl",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "author": "MesTTo",
5
5
  "license": "MIT",
6
6
  "description": "Ergonomic, typed TypeScript eDSL for MeTTa: typed term builders, rewrite rules, a tagged-template surface, and auto-grounding of TypeScript values.",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "sideEffects": false,
33
33
  "dependencies": {
34
- "@metta-ts/hyperon": "1.0.3"
34
+ "@metta-ts/hyperon": "1.0.5"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",