nodality 1.1.14 → 1.2.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 (201) hide show
  1. package/bin/mcp-server.mjs +41 -5
  2. package/bin/nodality.js +61 -0
  3. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  4. package/dist/animator.esm.js.LICENSE.txt +1 -1
  5. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  6. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  7. package/dist/base.cjs.js.LICENSE.txt +1 -1
  8. package/dist/base.esm.js.LICENSE.txt +1 -1
  9. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  10. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  11. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  12. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  13. package/dist/bundle.umd.js +1 -1
  14. package/dist/bundle.umd.js.LICENSE.txt +60 -1
  15. package/dist/button.cjs.js.LICENSE.txt +1 -1
  16. package/dist/button.esm.js.LICENSE.txt +1 -1
  17. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  18. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  19. package/dist/center.cjs.js.LICENSE.txt +1 -1
  20. package/dist/center.esm.js.LICENSE.txt +1 -1
  21. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  22. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  23. package/dist/code.cjs.js.LICENSE.txt +1 -1
  24. package/dist/code.esm.js.LICENSE.txt +1 -1
  25. package/dist/container.cjs.js.LICENSE.txt +1 -1
  26. package/dist/container.esm.js.LICENSE.txt +1 -1
  27. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  28. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  29. package/dist/designer.cjs.js +1 -1
  30. package/dist/designer.cjs.js.LICENSE.txt +60 -1
  31. package/dist/designer.esm.js +1 -1
  32. package/dist/designer.esm.js.LICENSE.txt +60 -1
  33. package/dist/element-mapper.cjs.js +1 -1
  34. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  35. package/dist/element-mapper.esm.js +1 -1
  36. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  37. package/dist/finalresult.esm.js +1 -1
  38. package/dist/finalresult.esm.js.LICENSE.txt +60 -1
  39. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  40. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  41. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  42. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  43. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  44. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  45. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  46. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  47. package/dist/free.cjs.js.LICENSE.txt +1 -1
  48. package/dist/free.esm.js.LICENSE.txt +1 -1
  49. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  50. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  51. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  52. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  53. package/dist/image.cjs.js.LICENSE.txt +1 -1
  54. package/dist/image.esm.js.LICENSE.txt +1 -1
  55. package/dist/index.cjs.js +1 -1
  56. package/dist/index.cjs.js.LICENSE.txt +60 -1
  57. package/dist/index.d.ts +1 -1
  58. package/dist/index.esm.js +1 -1
  59. package/dist/index.esm.js.LICENSE.txt +60 -1
  60. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  61. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  62. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  63. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  64. package/dist/link.cjs.js.LICENSE.txt +1 -1
  65. package/dist/link.esm.js.LICENSE.txt +1 -1
  66. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  67. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  68. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  69. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  70. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  71. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  72. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  73. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  74. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  75. package/dist/picker.esm.js.LICENSE.txt +1 -1
  76. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  77. package/dist/progress.esm.js.LICENSE.txt +1 -1
  78. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  79. package/dist/radio.esm.js.LICENSE.txt +1 -1
  80. package/dist/range.cjs.js.LICENSE.txt +1 -1
  81. package/dist/range.esm.js.LICENSE.txt +1 -1
  82. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  83. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  84. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  85. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  86. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  87. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  88. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  89. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  90. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  91. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  92. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  93. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  94. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  95. package/dist/stack.esm.js.LICENSE.txt +1 -1
  96. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  97. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  98. package/dist/table.cjs.js.LICENSE.txt +1 -1
  99. package/dist/table.esm.js.LICENSE.txt +1 -1
  100. package/dist/text-field.cjs.js +1 -1
  101. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  102. package/dist/text-field.esm.js +1 -1
  103. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  104. package/dist/text.cjs.js.LICENSE.txt +1 -1
  105. package/dist/text.esm.js.LICENSE.txt +1 -1
  106. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  107. package/dist/theme.esm.js.LICENSE.txt +1 -1
  108. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  109. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  110. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  111. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  112. package/dist/video.cjs.js.LICENSE.txt +1 -1
  113. package/dist/video.esm.js.LICENSE.txt +1 -1
  114. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  115. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  116. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  117. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  118. package/layout/animator.js +1 -1
  119. package/layout/audio.js +1 -1
  120. package/layout/audionew.js +1 -1
  121. package/layout/base.js +1 -1
  122. package/layout/beta-desktop-bar.js +1 -1
  123. package/layout/beta-mobile-bar.js +1 -1
  124. package/layout/button.js +1 -1
  125. package/layout/center.js +1 -1
  126. package/layout/checkbox.js +1 -1
  127. package/layout/circle.js +1 -1
  128. package/layout/code.js +1 -1
  129. package/layout/container.js +1 -1
  130. package/layout/dropdown-2025.js +1 -1
  131. package/layout/flex-card.js +1 -1
  132. package/layout/flex-grid.js +1 -1
  133. package/layout/flex-row.js +1 -1
  134. package/layout/form-components/custom.js +1 -1
  135. package/layout/form-components/data-list.js +1 -1
  136. package/layout/form-components/floating-input.js +1 -1
  137. package/layout/form-components/form-all.js +1 -1
  138. package/layout/form-components/form.js +6 -1
  139. package/layout/form-components/image-picker.js +1 -1
  140. package/layout/form-components/picker.js +1 -1
  141. package/layout/form-components/radio.js +1 -1
  142. package/layout/form-components/radiogroup.js +1 -1
  143. package/layout/form-components/range.js +1 -1
  144. package/layout/free.js +1 -1
  145. package/layout/grid-switcher.js +1 -1
  146. package/layout/grid.js +1 -1
  147. package/layout/horizontal-scroller.js +1 -1
  148. package/layout/image.js +1 -1
  149. package/layout/index.js +1 -1
  150. package/layout/link.js +1 -1
  151. package/layout/list.js +1 -1
  152. package/layout/meta-adder.js +1 -1
  153. package/layout/modal-2025.js +1 -1
  154. package/layout/morph.js +1 -1
  155. package/layout/multiswitcher.js +1 -1
  156. package/layout/nav-bar.js +1 -1
  157. package/layout/nav-factor/custom-div.js +1 -1
  158. package/layout/new-nav-bar.js +1 -1
  159. package/layout/polygon.js +1 -1
  160. package/layout/prerender-site.js +1 -1
  161. package/layout/prerender.js +1 -1
  162. package/layout/progress.js +1 -1
  163. package/layout/row.js +1 -1
  164. package/layout/scroll-video.js +1 -1
  165. package/layout/side-bar.js +1 -1
  166. package/layout/side-nav-bar.js +1 -1
  167. package/layout/simple-bar.js +1 -1
  168. package/layout/slider-2025.js +1 -1
  169. package/layout/spacer.js +1 -1
  170. package/layout/stack.js +1 -1
  171. package/layout/svg.js +1 -1
  172. package/layout/switcher.js +1 -1
  173. package/layout/table.js +1 -1
  174. package/layout/text-field.js +13 -1
  175. package/layout/text.js +1 -1
  176. package/layout/ulist.js +1 -1
  177. package/layout/video.js +1 -1
  178. package/layout/wrap.js +1 -1
  179. package/layout/zoom-card.js +1 -1
  180. package/lib/agent-surface.js +347 -0
  181. package/lib/card-getter.js +1 -1
  182. package/lib/codegen.js +1 -1
  183. package/lib/data.js +1 -1
  184. package/lib/designer.js +22 -1
  185. package/lib/element-mapper.js +2 -1
  186. package/lib/keyframe-animation.js +1 -1
  187. package/lib/link-getter.js +1 -1
  188. package/lib/morph-node.js +47 -8
  189. package/lib/raster-inspect.js +1 -1
  190. package/lib/raster-ops.js +1 -1
  191. package/lib/raster-presets.js +1 -1
  192. package/lib/scroll-video.js +1 -1
  193. package/lib/seo.js +1 -1
  194. package/lib/stacker.js +1 -1
  195. package/lib/suggest.js +1 -1
  196. package/lib/theme.js +1 -1
  197. package/lib/transform-anim.js +1 -1
  198. package/lib/transition.js +1 -1
  199. package/lib/validate-nodes.js +196 -32
  200. package/lib/webmcp-adapter.js +307 -0
  201. package/package.json +1 -1
@@ -76,9 +76,19 @@ const NODES_SCHEMA = {
76
76
  "array order); `{ op: { name: \"shadow\" }, target: [...] }` is a " +
77
77
  "design node; `{ op: \"morph\", from: \"topnav\", to: { \"About\": " +
78
78
  "\"about\" }, effect: \"t-vhs\", duration: 900, back: true }` is a " +
79
- "transition — one element becomes another on interaction. Nothing in " +
80
- "N names a component; the two arrays meet only through `target`, " +
81
- "`from` and `to`. Call list_ops first for the exact vocabulary.",
79
+ "transition — one element becomes another on interaction. A morph " +
80
+ "describes a whole navigation graph by carrying `chain` instead of one " +
81
+ "`from`/`to`: `{ op: \"morph\", effect: \"t-vhs\", duration: 620, " +
82
+ "back: true, chain: [ { from: \"home\", to: { \"Work\": \"work\" } }, " +
83
+ "{ from: \"work\", to: { \"Detail\": \"detail\" }, effect: \"t-split\" } " +
84
+ "] }`. The entries are EDGES, not keyframes: edge two is reachable " +
85
+ "FROM the state edge one lands on, so a landed state becomes a source. " +
86
+ "Settings on the node are defaults each edge may override, and `chain` " +
87
+ "wins outright — node-level `from`/`to` are not read beside it. " +
88
+ "Nothing in N names a component; the two arrays meet only through " +
89
+ "`target`, `from` and `to`, each of which names an element id, written " +
90
+ "either bare (\"work\") or in selector form (\"#work\"). Call list_ops " +
91
+ "first for the exact vocabulary.",
82
92
  items: { type: "object" },
83
93
  };
84
94
 
@@ -199,13 +209,39 @@ const IMPL = {
199
209
  },
200
210
  });
201
211
 
202
- const bytes = (await readFile(out)).length;
212
+ const html = await readFile(out, "utf8");
213
+ const bytes = Buffer.byteLength(html);
214
+
215
+ // The surface this pair would give an OPERATING agent, reported to
216
+ // the GENERATING one. The two loops meet here: a model writing the
217
+ // page can see the tools a model using the page will be handed, and
218
+ // can tell before shipping that a form it meant to expose derived
219
+ // nothing. Lifted out of the rendered page rather than derived a
220
+ // second time, so what is reported is what the build emitted.
221
+ let surface;
222
+ const at = html.indexOf('id="nodality-agent-manifest"');
223
+ if (at >= 0) {
224
+ const s = html.indexOf(">", at);
225
+ const e = html.indexOf("</script>", s);
226
+ if (s >= 0 && e > s) {
227
+ try {
228
+ const m = JSON.parse(html.slice(s + 1, e));
229
+ surface = {
230
+ tools: m.tools.map((x) => ({ name: x.name, description: x.description })),
231
+ views: m.views || null,
232
+ };
233
+ } catch { /* a malformed declaration is simply not reported */ }
234
+ }
235
+ }
236
+
203
237
  return ok({
204
238
  path: out, bytes,
239
+ ...(surface ? { surface } : {}),
205
240
  // Said plainly, because an agent cannot see the result and would
206
241
  // otherwise report a shader that never ran as working.
207
242
  note: "Prerendered DOM only. Raster effects and morph transitions " +
208
- "need a GPU and run when this file is opened in a browser.",
243
+ "need a GPU and run when this file is opened in a browser." +
244
+ (surface ? " `surface` is what an agent operating this page would be offered." : ""),
209
245
  });
210
246
  },
211
247
  };
package/bin/nodality.js CHANGED
@@ -596,6 +596,67 @@ async function runPrerender(rawArgs) {
596
596
  }
597
597
 
598
598
  await prerenderSite(config);
599
+ writeAgentManifest(config);
600
+ }
601
+
602
+ /**
603
+ * Lift the agent surface out of the prerendered pages into one file.
604
+ *
605
+ * Nothing derives anything here. The declaration was written into each
606
+ * document by the SAME code that registers the tools at runtime, so by
607
+ * the time prerendering has finished it is already serialised inside the
608
+ * static HTML — this only gathers it up, so that a consumer which wants
609
+ * capability without parsing pages has one URL to fetch. That is the
610
+ * half of the agent story that needs no browser support, no origin
611
+ * trial and no standard: a crawler, an indexer, or an agent deciding
612
+ * whether the site is worth visiting reads it without executing
613
+ * anything.
614
+ *
615
+ * Byte-stability matters and is asserted in the suite: the file ships
616
+ * from a build, so it inherits the determinism the whole model rests on
617
+ * — pages are visited in sorted order and nothing here is timestamped.
618
+ */
619
+ function writeAgentManifest(config) {
620
+ const uploadDir = path.resolve(config.uploadDir || "upload");
621
+ const MANIFEST_ID = "nodality-agent-manifest";
622
+ const pages = {};
623
+
624
+ const scan = (dir, prefix = "") => {
625
+ let entries;
626
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
627
+ for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
628
+ const abs = path.join(dir, e.name);
629
+ if (e.isDirectory()) {
630
+ if (["node_modules", "dist", "lib", "layout", "assets", "p"].includes(e.name)) continue;
631
+ scan(abs, prefix + e.name + "/");
632
+ continue;
633
+ }
634
+ if (!e.name.endsWith(".html")) continue;
635
+ const html = fs.readFileSync(abs, "utf8");
636
+ // Located by id rather than parsed: the file is emitted by us, and
637
+ // a dependency-free substring read cannot be broken by whatever a
638
+ // page happens to contain elsewhere.
639
+ const open = html.indexOf(`id="${MANIFEST_ID}"`);
640
+ if (open < 0) continue;
641
+ const start = html.indexOf(">", open);
642
+ const end = html.indexOf("</script>", start);
643
+ if (start < 0 || end < 0) continue;
644
+ try {
645
+ pages[prefix + e.name] = JSON.parse(html.slice(start + 1, end));
646
+ } catch { /* a page that did not finish rendering is simply absent */ }
647
+ }
648
+ };
649
+ scan(uploadDir);
650
+
651
+ const out = path.join(uploadDir, "agent-manifest.json");
652
+ if (!Object.keys(pages).length) {
653
+ // No page declared a surface: remove a stale file rather than leave
654
+ // one claiming capabilities the site no longer offers.
655
+ if (fs.existsSync(out)) fs.unlinkSync(out);
656
+ return;
657
+ }
658
+ fs.writeFileSync(out, JSON.stringify({ origin: config.origin || null, pages }, null, 2) + "\n");
659
+ console.log(`✅ Agent manifest — ${Object.keys(pages).length} page(s) → agent-manifest.json`);
599
660
  }
600
661
 
601
662
  // ─── compile subcommand ────────────────────────────────────────
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.1.13
2
+ * nodality v1.1.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */