@muten/core 0.0.1 → 0.0.3

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,97 +1,97 @@
1
- # muten
2
-
3
- An **AI-first** frontend framework. You write `.muten` files; muten compiles them to vanilla JS
4
- with fine-grained signals — **no virtual DOM, no framework runtime to ship**. The language is small,
5
- semantic and analyzable on purpose: an AI (or a person) can **locate and mutate** an app cheaply.
6
-
7
- ```sh
8
- npm create muten@latest my-app # scaffold a new app (cross-platform: Windows + macOS)
9
- cd my-app && npm install && npm run dev
10
- ```
11
-
12
- ## The app, by convention
13
-
14
- ```
15
- my-app/
16
- ├─ src/
17
- │ ├─ app.muten # the ROOT: routes (+ optional persistent shell)
18
- │ ├─ pages/
19
- │ │ └─ home/home.muten # a page; the folder name is its route target
20
- │ ├─ parts/ # reusable .muten components (object + action params)
21
- │ └─ components/ # host-written Custom JS (the escape hatch)
22
- ├─ theme.muten # the project's token scale (md=16px, breakpoints, …)
23
- └─ src/styles.css # the look (muten ships structure + layout; the skin is yours)
24
- ```
25
-
26
- `src/app.muten` is the single source of truth the AI reads first:
27
-
28
- ```
29
- routes {
30
- / -> home
31
- }
32
- ```
33
-
34
- ## CLI
35
-
36
- ```sh
37
- muten build [dir] # compile → ./dist/<route>/index.html (+ dist/app.map.json, the app graph)
38
- muten lint [dir] # parse + validate every page, no compile
39
- ```
40
-
41
- `build`/`lint` default to the current directory; pass a path to target another. The `muten` bin ships
42
- with the app (it's a dependency). To scaffold a *new* app, use `npm create muten@latest` (the separate
43
- [`create-muten`](https://www.npmjs.com/package/create-muten) scaffolder).
44
-
45
- ## Dev server (Vite)
46
-
47
- The Vite plugin gives a Muten app a dev server + HMR + client-side routing while authoring stays the
48
- DSL. `npm create muten` wires it up; `npm run dev` runs it.
49
-
50
- ```js
51
- // vite.config.mjs
52
- import muten from '@muten/core/vite-plugin-muten.js';
53
- export default { plugins: [muten()] }; // theme.muten is auto-loaded
54
- ```
55
-
56
- ## Programmatic API
57
-
58
- ```js
59
- import { buildApp, compile, parse, validate, toDoc } from '@muten/core';
60
-
61
- await buildApp('./my-app'); // same as `muten build ./my-app`
62
- const html = compile(toDoc(parse(src))); // drive the compiler directly (embedding)
63
- ```
64
-
65
- ## Architecture
66
-
67
- The compiler is a straight pipeline of small, single-purpose stages:
68
-
69
- ```
70
- .muten ─[lang]→ IR ─[ir: compose]→ tree ─[ir: flatten]→ Doc ─[ir: validate]→ ✓ ─[compile]→ JS
71
- ```
72
-
73
- The source is TypeScript under `src/`, organized by **domain** — each has its own README:
74
-
75
- | Domain | Role |
76
- |---|---|
77
- | [`src/engine/shared`](src/engine/shared/README.md) | contracts: types, the vocabulary (no magic strings), diagnostics |
78
- | [`src/engine/lang`](src/engine/lang/README.md) | front-end: `.muten` text → IR (lexer · grammar · parser · manifest) |
79
- | [`src/engine/ir`](src/engine/ir/README.md) | IR transforms + validation (compose · flatten · validate) |
80
- | [`src/engine/compile`](src/engine/compile/README.md) | back-end: Doc → runnable JS (DOM + logic + emit + helpers) |
81
- | [`src/engine/style`](src/engine/style/README.md) | the styling token vocabulary (the engine ships no values) |
82
- | [`src/engine/project`](src/engine/project/README.md) | filesystem + whole-app awareness (load · analyze · routes · styles) |
83
-
84
- The runtime (the only thing shipped to the browser), the Vite plugin, the CLI and the build/lint
85
- orchestration also live in `src/`. See [`src/engine/README.md`](src/engine/README.md) for the
86
- file-level conventions (≤500 lines, honest types, data-table dispatch, no magic strings).
87
-
88
- ## Build
89
-
90
- `npm run build` = `tsc` (strict type-check) + `esbuild` → `dist/**/*.js`, **minified, per-file**
91
- (modules preserved, so nothing bundles into a heavy monolith). `dist/` is generated — edit `src/`.
92
-
93
- ## Styling & escape hatch
94
-
95
- muten imposes no theme. A page lays itself out with `style(…)` tokens (analyzable, resolved against
96
- `theme.muten`) and skins itself via `class("…")` (your CSS / Tailwind / anything). For behavior the
97
- primitives can't express, drop to a `Custom` component (`src/components/<Name>.js`).
1
+
2
+ <img width="157" height="157" alt="Group 21" src="https://github.com/user-attachments/assets/fe9a02e6-483d-4788-9286-142c1ddb7057" /> </br>
3
+ An **AI-first** frontend framework. You write `.muten` files; muten compiles them to vanilla JS
4
+ with fine-grained signals — **no virtual DOM, no framework runtime to ship**. The language is small,
5
+ semantic and analyzable on purpose: an AI (or a person) can **locate and mutate** an app cheaply.
6
+
7
+ ```sh
8
+ npm create muten@latest my-app # scaffold a new app (cross-platform: Windows + macOS)
9
+ cd my-app && npm install && npm run dev
10
+ ```
11
+
12
+ ## The app, by convention
13
+
14
+ ```
15
+ my-app/
16
+ ├─ src/
17
+ │ ├─ app.muten # the ROOT: routes (+ optional persistent shell)
18
+ │ ├─ pages/
19
+ │ │ └─ home/home.muten # a page; the folder name is its route target
20
+ │ ├─ parts/ # reusable .muten components (object + action params)
21
+ │ └─ components/ # host-written Custom JS (the escape hatch)
22
+ ├─ theme.muten # the project's token scale (md=16px, breakpoints, …)
23
+ └─ src/styles.css # the look (muten ships structure + layout; the skin is yours)
24
+ ```
25
+
26
+ `src/app.muten` is the single source of truth the AI reads first:
27
+
28
+ ```
29
+ routes {
30
+ / -> home
31
+ }
32
+ ```
33
+
34
+ ## CLI
35
+
36
+ ```sh
37
+ muten build [dir] # compile → ./dist/<route>/index.html (+ dist/app.map.json, the app graph)
38
+ muten lint [dir] # parse + validate every page, no compile
39
+ ```
40
+
41
+ `build`/`lint` default to the current directory; pass a path to target another. The `muten` bin ships
42
+ with the app (it's a dependency). To scaffold a *new* app, use `npm create muten@latest` (the separate
43
+ [`create-muten`](https://www.npmjs.com/package/create-muten) scaffolder).
44
+
45
+ ## Dev server (Vite)
46
+
47
+ The Vite plugin gives a Muten app a dev server + HMR + client-side routing while authoring stays the
48
+ DSL. `npm create muten` wires it up; `npm run dev` runs it.
49
+
50
+ ```js
51
+ // vite.config.mjs
52
+ import muten from '@muten/core/vite-plugin-muten.js';
53
+ export default { plugins: [muten()] }; // theme.muten is auto-loaded
54
+ ```
55
+
56
+ ## Programmatic API
57
+
58
+ ```js
59
+ import { buildApp, compile, parse, validate, toDoc } from '@muten/core';
60
+
61
+ await buildApp('./my-app'); // same as `muten build ./my-app`
62
+ const html = compile(toDoc(parse(src))); // drive the compiler directly (embedding)
63
+ ```
64
+
65
+ ## Architecture
66
+
67
+ The compiler is a straight pipeline of small, single-purpose stages:
68
+
69
+ ```
70
+ .muten ─[lang]→ IR ─[ir: compose]→ tree ─[ir: flatten]→ Doc ─[ir: validate]→ ✓ ─[compile]→ JS
71
+ ```
72
+
73
+ The source is TypeScript under `src/`, organized by **domain** — each has its own README:
74
+
75
+ | Domain | Role |
76
+ |---|---|
77
+ | [`src/engine/shared`](src/engine/shared/README.md) | contracts: types, the vocabulary (no magic strings), diagnostics |
78
+ | [`src/engine/lang`](src/engine/lang/README.md) | front-end: `.muten` text → IR (lexer · grammar · parser · manifest) |
79
+ | [`src/engine/ir`](src/engine/ir/README.md) | IR transforms + validation (compose · flatten · validate) |
80
+ | [`src/engine/compile`](src/engine/compile/README.md) | back-end: Doc → runnable JS (DOM + logic + emit + helpers) |
81
+ | [`src/engine/style`](src/engine/style/README.md) | the styling token vocabulary (the engine ships no values) |
82
+ | [`src/engine/project`](src/engine/project/README.md) | filesystem + whole-app awareness (load · analyze · routes · styles) |
83
+
84
+ The runtime (the only thing shipped to the browser), the Vite plugin, the CLI and the build/lint
85
+ orchestration also live in `src/`. See [`src/engine/README.md`](src/engine/README.md) for the
86
+ file-level conventions (≤500 lines, honest types, data-table dispatch, no magic strings).
87
+
88
+ ## Build
89
+
90
+ `npm run build` = `tsc` (strict type-check) + `esbuild` → `dist/**/*.js`, **minified, per-file**
91
+ (modules preserved, so nothing bundles into a heavy monolith). `dist/` is generated — edit `src/`.
92
+
93
+ ## Styling & escape hatch
94
+
95
+ muten imposes no theme. A page lays itself out with `style(…)` tokens (analyzable, resolved against
96
+ `theme.muten`) and skins itself via `class("…")` (your CSS / Tailwind / anything). For behavior the
97
+ primitives can't express, drop to a `Custom` component (`src/components/<Name>.js`).
package/dist/build.js CHANGED
@@ -1,12 +1,12 @@
1
- import{writeFileSync as u,mkdirSync as j,readFileSync as A,existsSync as S,rmSync as E}from"node:fs";import{join as s,relative as N}from"node:path";import{Nt as M}from"#engine/shared/vocab.js";import{readRoutes as C}from"#engine/project/routes.js";import{load as F,loadAllParts as V}from"#engine/project/load.js";import{validate as v}from"#engine/ir/validate.js";import{compile as H}from"#engine/compile/compile.js";import{formatDiagnostic as $,ParseError as I}from"#engine/shared/diagnostics.js";const J=r=>typeof r=="string"?r:r&&typeof r=="object"&&!Array.isArray(r)&&typeof r.url=="string"?r.url:"";async function T(r,n=s(r,"dist")){const i=t=>N(r,t);E(n,{recursive:!0,force:!0});const a=await V(r);Object.keys(a).length&&console.log(`Parts: ${Object.keys(a).join(", ")}`);const f=C(r);console.log(`Host app: ${r}`),console.log(`Pages: ${f.map(t=>"/"+t.route).join(", ")}
2
- `);const l=[],g={app:r.split(/[\\/]/).pop()||"",parts:Object.keys(a),routes:{}};for(const t of f){let d;try{d=await F(t.screenPath,a)}catch(e){if(!(e instanceof I))throw e;const o={code:e.code,severity:"error",message:e.message,loc:e.loc,suggestion:null};throw new Error(`/${t.route}
3
- `+$(o,i(t.screenPath)))}const{doc:c,data:O,sources:h,styles:p,partNames:w}=d,{ok:P,diagnostics:k}=v(c,{parts:w});if(!P)throw new Error(`/${t.route}
4
- `+k.map(e=>" "+$(e,i(t.screenPath))).join(`
5
- `));const x=[...new Set(Object.values(c.nodes).filter(e=>e.type===M.Custom).map(e=>e.props?.component))],y={};for(const e of x){if(!e)continue;const o=s(r,"src","components",e+".js");if(!S(o))throw new Error(`/${t.route}: Custom component not found: src/components/${e}.js`);y[e]=A(o,"utf8")}const m=s(n,t.route);j(m,{recursive:!0}),u(s(m,"index.html"),H(c,O,p.css,y,h)),console.log(`\u2713 /${t.route} \u2192 ${i(s(m,"index.html"))} (${Object.keys(c.nodes).length} nodes${p.from?", + "+p.from:""})`),l.push(t.route),g.routes["/"+t.route]={file:i(t.screenPath),models:Object.keys(c.entities),state:Object.fromEntries(Object.entries(c.state).map(([e,o])=>[e,typeof o.source=="string"?o.source:o.initial??null])),sources:Object.fromEntries(Object.entries(h).map(([e,o])=>[e,J(o)]))}}j(n,{recursive:!0});const b=l.map(t=>`<li><a href="./${t}/">/${t}</a></li>`).join(`
6
- `);return u(s(n,"index.html"),`<!doctype html><meta charset="utf-8"><title>app</title>
1
+ import{writeFileSync as f,mkdirSync as j,readFileSync as x,existsSync as A,rmSync as S}from"node:fs";import{join as s,relative as E}from"node:path";import{Nt as N}from"#engine/shared/vocab.js";import{readRoutes as M}from"#engine/project/routes.js";import{load as C,loadAllParts as F}from"#engine/project/load.js";import{validate as V}from"#engine/ir/validate.js";import{compile as v}from"#engine/compile/compile.js";import{formatDiagnostic as $,ParseError as H}from"#engine/shared/diagnostics.js";const I=r=>typeof r=="string"?r:r&&typeof r=="object"&&!Array.isArray(r)&&typeof r.url=="string"?r.url:"";async function Q(r,n=s(r,"dist")){const i=t=>E(r,t);S(n,{recursive:!0,force:!0});const l=await F(r);Object.keys(l).length&&console.log(`Parts: ${Object.keys(l).join(", ")}`);const g=M(r);console.log(`Host app: ${r}`),console.log(`Pages: ${g.map(t=>"/"+t.route).join(", ")}
2
+ `);const p=[],d={app:r.split(/[\\/]/).pop()||"",parts:Object.keys(l),routes:{}};for(const t of g){let a;try{a=await C(t.screenPath,l)}catch(e){if(!(e instanceof H))throw e;const o={code:e.code,severity:"error",message:e.message,loc:e.loc,suggestion:null};throw new Error(`/${t.route}
3
+ `+$(o,i(t.screenPath)))}const{doc:c,data:b,sources:h,styles:m,partNames:O}=a,{ok:w,diagnostics:P}=V(c,{parts:O});if(!w)throw new Error(`/${t.route}
4
+ `+P.map(e=>" "+$(e,i(t.screenPath))).join(`
5
+ `));const k=[...new Set(Object.values(c.nodes).filter(e=>e.type===N.Custom).map(e=>e.props?.component))],y={};for(const e of k){if(!e)continue;const o=s(r,"src","components",e+".js");if(!A(o))throw new Error(`/${t.route}: Custom component not found: src/components/${e}.js`);y[e]=x(o,"utf8")}const u=s(n,t.route);j(u,{recursive:!0}),f(s(u,"index.html"),v(c,b,m.css,y,h)),console.log(`\u2713 /${t.route} \u2192 ${i(s(u,"index.html"))} (${Object.keys(c.nodes).length} nodes${m.from?", + "+m.from:""})`),p.push(t.route),d.routes["/"+t.route]={file:i(t.screenPath),models:Object.keys(c.entities),state:Object.fromEntries(Object.entries(c.state).map(([e,o])=>[e,typeof o.source=="string"?o.source:o.initial??null])),sources:Object.fromEntries(Object.entries(h).map(([e,o])=>[e,I(o)]))}}if(j(n,{recursive:!0}),!p.includes("")){const t=p.map(a=>`<li><a href="./${a}/">/${a}</a></li>`).join(`
6
+ `);f(s(n,"index.html"),`<!doctype html><meta charset="utf-8"><title>app</title>
7
7
  <h1>Routes</h1>
8
8
  <ul>
9
- ${b}
9
+ ${t}
10
10
  </ul>
11
- `),u(s(n,"app.map.json"),JSON.stringify(g,null,2)),console.log(`
12
- \u2713 ${i(s(n,"index.html"))} \u2192 route index`),console.log(`\u2713 ${i(s(n,"app.map.json"))} \u2192 app graph (the root the AI reads)`),{routes:l,outDir:n}}export{T as buildApp};
11
+ `),console.log(`
12
+ \u2713 ${i(s(n,"index.html"))} \u2192 route index`)}return f(s(n,"app.map.json"),JSON.stringify(d,null,2)),console.log(`\u2713 ${i(s(n,"app.map.json"))} \u2192 app graph (the root the AI reads)`),{routes:p,outDir:n}}export{Q as buildApp};
@@ -1 +1 @@
1
- const g=new Map([["start","flex-start"],["center","center"],["end","flex-end"],["between","space-between"],["around","space-around"],["evenly","space-evenly"]]),d=new Map([["start","flex-start"],["center","center"],["end","flex-end"],["stretch","stretch"],["baseline","baseline"]]),r=new Map([["row","display:flex;flex-direction:row"],["column","display:flex;flex-direction:column"],["wrap","flex-wrap:wrap"],["grid","display:grid"],["grow","flex:1"],["center","align-items:center"],["between","justify-content:space-between"],["bold","font-weight:700"],["italic","font-style:italic"]]),i=(e,t)=>t[e]??(/^\d+$/.test(e)?e+"px":null),c=(e,t,n)=>{if(e.startsWith("x.")){const l=i(e.slice(2),n);return l?`${t}-left:${l};${t}-right:${l}`:null}if(e.startsWith("y.")){const l=i(e.slice(2),n);return l?`${t}-top:${l};${t}-bottom:${l}`:null}const s=i(e,n);return s?`${t}:${s}`:null},o={gap:(e,t)=>{const n=i(e,t.space);return n?`gap:${n}`:null},padding:(e,t)=>c(e,"padding",t.space),margin:(e,t)=>c(e,"margin",t.space),cols:e=>e==="auto"?"grid-template-columns:repeat(auto-fill,minmax(160px,1fr))":/^\d+$/.test(e)?`grid-template-columns:repeat(${e},1fr)`:null,rows:e=>/^\d+$/.test(e)?`grid-template-rows:repeat(${e},1fr)`:null,text:(e,t)=>{const n=i(e,t.font);return n?`font-size:${n}`:null},weight:(e,t)=>{const n=t.weight[e]??(/^\d+$/.test(e)?e:null);return n?`font-weight:${n}`:null},leading:(e,t)=>{const n=t.leading[e]??(/^[\d.]+$/.test(e)?e:null);return n?`line-height:${n}`:null},align:e=>["left","center","right","justify"].includes(e)?`text-align:${e}`:null,justify:e=>{const t=g.get(e);return t?`justify-content:${t}`:null},items:e=>{const t=d.get(e);return t?`align-items:${t}`:null},width:(e,t)=>e==="full"?"width:100%":i(e,t.space)?`width:${i(e,t.space)}`:null,height:(e,t)=>e==="full"?"height:100%":i(e,t.space)?`height:${i(e,t.space)}`:null},u=Object.keys(o),x=[...r.keys()],f=["sm","md","lg","xl"],p={space:{},font:{},weight:{},leading:{},breakpoints:{}};function w(e={}){return{space:{...e.space||{}},font:{...e.font||{}},weight:{...e.weight||{}},leading:{...e.leading||{}},breakpoints:{...e.breakpoints||{}}}}function h(e,t=p){const n=e.indexOf(":");if(n>0&&t.breakpoints[e.slice(0,n)])return h(e.slice(n+1),t);const s=r.get(e);if(s)return s;const l=e.indexOf(".");if(l<0)return null;const a=o[e.slice(0,l)];return a&&a(e.slice(l+1),t)||null}function m(e){const t=e.indexOf(":"),n=t>0&&f.includes(e.slice(0,t))?e.slice(t+1):e;if(r.has(n))return!0;const s=n.indexOf(".");return s>0&&u.includes(n.slice(0,s))}const $=e=>"t-"+e.replace(/[.:]/g,"-"),y=["row","column","wrap","grid","grow","center","between","bold","italic","gap.sm","gap.md","gap.lg","padding.md","padding.lg","padding.x.md","padding.y.md","margin.md","cols.2","cols.3","cols.auto","rows.2","text.sm","text.md","text.lg","text.xl","weight.medium","weight.bold","leading.normal","align.left","align.center","align.right","justify.center","justify.between","items.center","items.start","width.full","height.full","md:row","md:cols.2","md:cols.3","lg:cols.4"];export{x as ATOM_NAMES,f as BREAKPOINT_NAMES,u as FAMILY_NAMES,y as SUGGESTED,p as defaultTheme,m as isKnownTokenShape,w as mergeTheme,h as resolveToken,$ as tokenClass};
1
+ const g=new Map([["start","flex-start"],["center","center"],["end","flex-end"],["between","space-between"],["around","space-around"],["evenly","space-evenly"]]),d=new Map([["start","flex-start"],["center","center"],["end","flex-end"],["stretch","stretch"],["baseline","baseline"]]),r=new Map([["row","display:flex;flex-direction:row"],["column","display:flex;flex-direction:column"],["wrap","flex-wrap:wrap"],["grid","display:grid"],["grow","flex:1"],["center","align-items:center"],["between","justify-content:space-between"],["bold","font-weight:700"],["italic","font-style:italic"]]),s=(e,t)=>t[e]??(/^\d+$/.test(e)?e+"px":null),o=(e,t,n)=>{if(e.startsWith("x.")){const l=s(e.slice(2),n);return l?`${t}-left:${l};${t}-right:${l}`:null}if(e.startsWith("y.")){const l=s(e.slice(2),n);return l?`${t}-top:${l};${t}-bottom:${l}`:null}const i=s(e,n);return i?`${t}:${i}`:null},c={gap:(e,t)=>{const n=s(e,t.space);return n?`gap:${n}`:null},padding:(e,t)=>o(e,"padding",t.space),margin:(e,t)=>o(e,"margin",t.space),cols:e=>e==="auto"?"grid-template-columns:repeat(auto-fill,minmax(160px,1fr))":/^\d+$/.test(e)?`grid-template-columns:repeat(${e},1fr)`:null,rows:e=>/^\d+$/.test(e)?`grid-template-rows:repeat(${e},1fr)`:null,text:(e,t)=>{const n=s(e,t.font);return n?`font-size:${n}`:null},weight:(e,t)=>{const n=t.weight[e]??(/^\d+$/.test(e)?e:null);return n?`font-weight:${n}`:null},leading:(e,t)=>{const n=t.leading[e]??(/^[\d.]+$/.test(e)?e:null);return n?`line-height:${n}`:null},align:e=>["left","center","right","justify"].includes(e)?`text-align:${e}`:null,justify:e=>{const t=g.get(e);return t?`justify-content:${t}`:null},items:e=>{const t=d.get(e);return t?`align-items:${t}`:null},width:e=>e==="full"?"width:100%":/^\d+$/.test(e)?`width:${e}px`:null,height:e=>e==="full"?"height:100%":/^\d+$/.test(e)?`height:${e}px`:null},u=Object.keys(c),h=[...r.keys()],f=["sm","md","lg","xl"],p={space:{},font:{},weight:{},leading:{},breakpoints:{}};function w(e={}){return{space:{...e.space||{}},font:{...e.font||{}},weight:{...e.weight||{}},leading:{...e.leading||{}},breakpoints:{...e.breakpoints||{}}}}function x(e,t=p){const n=e.indexOf(":");if(n>0&&t.breakpoints[e.slice(0,n)])return x(e.slice(n+1),t);const i=r.get(e);if(i)return i;const l=e.indexOf(".");if(l<0)return null;const a=c[e.slice(0,l)];return a&&a(e.slice(l+1),t)||null}function m(e){const t=e.indexOf(":"),n=t>0&&f.includes(e.slice(0,t))?e.slice(t+1):e;if(r.has(n))return!0;const i=n.indexOf(".");return i>0&&u.includes(n.slice(0,i))}const $=e=>"t-"+e.replace(/[.:]/g,"-"),y=["row","column","wrap","grid","grow","center","between","bold","italic","gap.sm","gap.md","gap.lg","padding.md","padding.lg","padding.x.md","padding.y.md","margin.md","cols.2","cols.3","cols.auto","rows.2","text.sm","text.md","text.lg","text.xl","weight.medium","weight.bold","leading.normal","align.left","align.center","align.right","justify.center","justify.between","items.center","items.start","width.full","height.full","md:row","md:cols.2","md:cols.3","lg:cols.4"];export{h as ATOM_NAMES,f as BREAKPOINT_NAMES,u as FAMILY_NAMES,y as SUGGESTED,p as defaultTheme,m as isKnownTokenShape,w as mergeTheme,x as resolveToken,$ as tokenClass};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muten/core",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "AI-first frontend framework — compiles .muten files to vanilla JS + signals.",
5
5
  "repository": {
6
6
  "type": "git",