nodality 1.2.4 → 1.2.6

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 (202) hide show
  1. package/API.md +8 -4
  2. package/README.md +15 -1
  3. package/bin/install-skill.mjs +160 -0
  4. package/bin/nodality.js +12 -0
  5. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  6. package/dist/animator.esm.js.LICENSE.txt +1 -1
  7. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  8. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  9. package/dist/base.cjs.js.LICENSE.txt +1 -1
  10. package/dist/base.esm.js.LICENSE.txt +1 -1
  11. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  12. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  13. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  14. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  15. package/dist/bundle.umd.js +1 -1
  16. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  17. package/dist/button.cjs.js.LICENSE.txt +1 -1
  18. package/dist/button.esm.js.LICENSE.txt +1 -1
  19. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  20. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  21. package/dist/center.cjs.js.LICENSE.txt +1 -1
  22. package/dist/center.esm.js.LICENSE.txt +1 -1
  23. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  24. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  25. package/dist/code.cjs.js.LICENSE.txt +1 -1
  26. package/dist/code.esm.js.LICENSE.txt +1 -1
  27. package/dist/container.cjs.js.LICENSE.txt +1 -1
  28. package/dist/container.esm.js.LICENSE.txt +1 -1
  29. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  30. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  31. package/dist/designer.cjs.js +1 -1
  32. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  33. package/dist/designer.esm.js +1 -1
  34. package/dist/designer.esm.js.LICENSE.txt +1 -1
  35. package/dist/element-mapper.cjs.js +1 -1
  36. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  37. package/dist/element-mapper.esm.js +1 -1
  38. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  39. package/dist/finalresult.esm.js +1 -1
  40. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  41. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  42. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  43. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  44. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  45. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  46. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  47. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  48. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  49. package/dist/free.cjs.js.LICENSE.txt +1 -1
  50. package/dist/free.esm.js.LICENSE.txt +1 -1
  51. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  52. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  53. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  54. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  55. package/dist/image.cjs.js.LICENSE.txt +1 -1
  56. package/dist/image.esm.js.LICENSE.txt +1 -1
  57. package/dist/index.cjs.js +1 -1
  58. package/dist/index.cjs.js.LICENSE.txt +1 -1
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.esm.js +1 -1
  61. package/dist/index.esm.js.LICENSE.txt +1 -1
  62. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  63. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  64. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  65. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  66. package/dist/link.cjs.js.LICENSE.txt +1 -1
  67. package/dist/link.esm.js.LICENSE.txt +1 -1
  68. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  69. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  70. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  71. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  72. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  73. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  74. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  75. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  76. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  77. package/dist/picker.esm.js.LICENSE.txt +1 -1
  78. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  79. package/dist/progress.esm.js.LICENSE.txt +1 -1
  80. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  81. package/dist/radio.esm.js.LICENSE.txt +1 -1
  82. package/dist/range.cjs.js.LICENSE.txt +1 -1
  83. package/dist/range.esm.js.LICENSE.txt +1 -1
  84. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  85. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  86. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  87. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  88. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  89. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  90. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  91. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  92. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  93. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  94. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  95. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  96. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  97. package/dist/stack.esm.js.LICENSE.txt +1 -1
  98. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  99. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  100. package/dist/table.cjs.js.LICENSE.txt +1 -1
  101. package/dist/table.esm.js.LICENSE.txt +1 -1
  102. package/dist/text-field.cjs.js.LICENSE.txt +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 +1 -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 +1 -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 +1 -1
  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 +6 -2
  185. package/lib/element-mapper.js +7 -3
  186. package/lib/keyframe-animation.js +1 -1
  187. package/lib/link-getter.js +1 -1
  188. package/lib/morph-node.js +1 -1
  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 +1 -1
  200. package/lib/webmcp-adapter.js +1 -1
  201. package/package.json +3 -2
  202. package/skills/nodality/SKILL.md +192 -0
package/API.md CHANGED
@@ -104,9 +104,9 @@ Machine-readable index: https://nodalityjs.github.io/llms.txt
104
104
  https://nodalityjs.github.io/docs/elements/polygon
105
105
  - **Elements** — Elements are used to create UI.
106
106
  https://nodalityjs.github.io/docs/elements/readme
107
- - **Responsive wrapper** — The `Wrapper` class allows you to create a responsive element that can dynamically switch its layout between row and column orientations based on specified brea
107
+ - **Responsive wrapper** — The `Wrapper` class allows you to create a responsive element that can dynamically switch its layout between row and column orientations based on specified
108
108
  https://nodalityjs.github.io/docs/elements/responsive-wrapper
109
- - **Complex** — The `Wrapper` class allows you to create a responsive element that can dynamically switch its layout between row and column orientations based on specified brea
109
+ - **Complex** — The `Wrapper` class allows you to create a responsive element that can dynamically switch its layout between row and column orientations based on specified
110
110
  https://nodalityjs.github.io/docs/elements/responsive
111
111
  - **Row** — Row creates a simple element to allow you to organise children in a row.
112
112
  https://nodalityjs.github.io/docs/elements/row
@@ -166,7 +166,7 @@ Machine-readable index: https://nodalityjs.github.io/llms.txt
166
166
  https://nodalityjs.github.io/docs/guides/testing
167
167
  - **Tooling** — Create Nodality package allows you to quickly bootstrap a new Nodality application.
168
168
  https://nodalityjs.github.io/docs/guides/tooling
169
- - **Transitions** — This library supports the **CSS View Transition API** to enable smooth animations when navigating between pages.\
169
+ - **Transitions** — This library supports the **CSS View Transition API** to enable smooth animations when navigating between pages.\ For example, you can build a carousel where…
170
170
  https://nodalityjs.github.io/docs/guides/transitions
171
171
 
172
172
  ### nodes
@@ -198,10 +198,14 @@ Machine-readable index: https://nodalityjs.github.io/llms.txt
198
198
 
199
199
  ### raster
200
200
 
201
+ - **Agent surface – the page, as tools** — An `agent-surface` node lets an AI agent operate the page: move between morph views, submit a form you have allowed, and read what is on screen.
202
+ https://nodalityjs.github.io/docs/raster/agent-surface
201
203
  - **Raster basics** — Raster ops run your element through a WebGL shader.
202
204
  https://nodalityjs.github.io/docs/raster/basics
203
205
  - **Composing a pipeline** — A chain is not a list of passes.
204
206
  https://nodalityjs.github.io/docs/raster/composition
207
+ - **Morph – transitions as nodes** — A morph node describes which element *becomes* which, and on what interaction.
208
+ https://nodalityjs.github.io/docs/raster/morph
205
209
  - **Raster ops** — Every node has an `op` and a set of options.
206
210
  https://nodalityjs.github.io/docs/raster/ops
207
211
 
@@ -209,7 +213,7 @@ Machine-readable index: https://nodalityjs.github.io/llms.txt
209
213
 
210
214
  - **Basics** — To create smooth scroll animations you can use the following:
211
215
  https://nodalityjs.github.io/docs/scrollanimation/basics
212
- - **Scroll Animation** — Create engaging scroll animation
216
+ - **Scroll Animation** — Create engaging scroll animation Continue to [Basics](basics.md) to get started.
213
217
  https://nodalityjs.github.io/docs/scrollanimation/index
214
218
  - **ScrollVideo** — Play video as you scroll.
215
219
  https://nodalityjs.github.io/docs/scrollanimation/scrollvideo
package/README.md CHANGED
@@ -78,7 +78,8 @@ const elements = [
78
78
  ];
79
79
 
80
80
  const nodes = [
81
- { op: { name: "gradient" }, target: ["hero"], colors: ["#1d6fe0", "#7fd1ff"] },
81
+ { op: { name: "gradient", gradient: "linear-gradient(90deg, #1d6fe0, #7fd1ff)" },
82
+ target: ["hero"] },
82
83
  { op: "dither", target: ["hero"], levels: 6, size: 2 },
83
84
  ];
84
85
 
@@ -118,6 +119,19 @@ prerendered HTML as a static manifest.
118
119
 
119
120
  ## For AI agents
120
121
 
122
+ One command sets up an agent IDE end to end:
123
+
124
+ ```bash
125
+ npx nodality skill
126
+ ```
127
+
128
+ It installs the `/nodality` skill – the authoring workflow, the node
129
+ families, and the house rules the schema cannot encode – into Claude
130
+ Code (`.claude/skills/`) and Cursor (`.cursor/rules/`), and registers
131
+ the MCP server below in the project's config. Flags: `--claude`,
132
+ `--cursor`, `--global`, `--dir=<path>` for any other agent, `--no-mcp`.
133
+ Re-run it after upgrading nodality to refresh the skill in place.
134
+
121
135
  `nodality mcp` runs a Model Context Protocol server over stdio, so a
122
136
  generator writes against the real vocabulary instead of guessing at it:
123
137
 
@@ -0,0 +1,160 @@
1
+ // bin/install-skill.mjs — `npx nodality skill`: install the /nodality
2
+ // skill into agent IDEs, the way `npx motion-ai` does for Motion.
3
+ //
4
+ // Targets:
5
+ // • Claude Code — copies skills/nodality/SKILL.md to
6
+ // <scope>/.claude/skills/nodality/SKILL.md, where scope is the
7
+ // project (cwd) or the home directory (--global).
8
+ // • Cursor — writes .cursor/rules/nodality.mdc (project only: Cursor
9
+ // has no global rules *directory*; global guidance there is a
10
+ // settings field, not a file this installer may write).
11
+ // • Anything else — --dir=<path> copies SKILL.md verbatim wherever a
12
+ // custom agent reads its instructions from.
13
+ //
14
+ // Unless --no-mcp is passed, project installs also register the MCP
15
+ // server (`npx nodality mcp`) in .mcp.json (Claude Code) and
16
+ // .cursor/mcp.json (Cursor), merging into whatever is already there.
17
+ // A global Claude install prints the `claude mcp add` line instead:
18
+ // the global registry lives inside ~/.claude.json alongside unrelated
19
+ // state, and this installer does not edit a file it does not own.
20
+ //
21
+ // Re-running upgrades in place: the skill file is overwritten, the MCP
22
+ // entry re-merged, and each line reports "installed" or "updated".
23
+
24
+ import fs from "node:fs";
25
+ import os from "node:os";
26
+ import path from "node:path";
27
+ import readline from "node:readline";
28
+ import { fileURLToPath } from "node:url";
29
+
30
+ const SKILL_SRC = path.join(
31
+ path.dirname(fileURLToPath(import.meta.url)),
32
+ "..",
33
+ "skills",
34
+ "nodality",
35
+ "SKILL.md",
36
+ );
37
+
38
+ const MCP_ENTRY = { command: "npx", args: ["nodality", "mcp"] };
39
+
40
+ // ─── helpers ────────────────────────────────────────────────────
41
+
42
+ function log(line) {
43
+ console.log(`[nodality] ${line}`);
44
+ }
45
+
46
+ // Copy with an installed/updated verdict so re-runs read as upgrades.
47
+ function place(src, dest, content) {
48
+ const existed = fs.existsSync(dest);
49
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
50
+ if (content !== undefined) fs.writeFileSync(dest, content);
51
+ else fs.copyFileSync(src, dest);
52
+ log(`${existed ? "updated " : "installed"} ${dest}`);
53
+ }
54
+
55
+ // Merge our server into an existing config without touching anything
56
+ // else in it. A file that exists but does not parse is left alone and
57
+ // reported — clobbering a hand-edited config is worse than skipping.
58
+ function registerMcp(configPath) {
59
+ let config = {};
60
+ if (fs.existsSync(configPath)) {
61
+ try {
62
+ config = JSON.parse(fs.readFileSync(configPath, "utf8"));
63
+ } catch {
64
+ log(`SKIPPED ${configPath} — existing file is not valid JSON; add this by hand:`);
65
+ log(` "mcpServers": { "nodality": ${JSON.stringify(MCP_ENTRY)} }`);
66
+ return;
67
+ }
68
+ }
69
+ const existed = fs.existsSync(configPath);
70
+ config.mcpServers = { ...config.mcpServers, nodality: MCP_ENTRY };
71
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
72
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
73
+ log(`${existed ? "updated " : "installed"} ${configPath} (mcpServers.nodality)`);
74
+ }
75
+
76
+ // The Cursor variant of the skill: same body, Cursor's rule
77
+ // frontmatter. `alwaysApply: false` plus a description makes it an
78
+ // agent-requested rule, matching how the skill triggers in Claude Code.
79
+ function toCursorRule(skillText) {
80
+ const m = skillText.match(/^---\n([\s\S]*?)\n---\n/);
81
+ if (!m) throw new Error(`no frontmatter in ${SKILL_SRC}`);
82
+ const desc = m[1].match(/^description:\s*(.+)$/m);
83
+ if (!desc) throw new Error(`no description in ${SKILL_SRC} frontmatter`);
84
+ const body = skillText.slice(m[0].length);
85
+ return `---\ndescription: ${desc[1]}\nalwaysApply: false\n---\n${body}`;
86
+ }
87
+
88
+ function ask(rl, question, def) {
89
+ return new Promise((resolve) => {
90
+ rl.question(`${question} [${def}] `, (a) => resolve(a.trim() || def));
91
+ });
92
+ }
93
+
94
+ // ─── entry ──────────────────────────────────────────────────────
95
+
96
+ export async function runSkillInstall(args) {
97
+ if (!fs.existsSync(SKILL_SRC)) {
98
+ console.error(`[nodality] skill source missing: ${SKILL_SRC}`);
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+
103
+ const flags = new Set(args.filter((a) => !a.startsWith("--dir=")));
104
+ const dirFlag = args.find((a) => a.startsWith("--dir="));
105
+ let claude = flags.has("--claude");
106
+ let cursor = flags.has("--cursor");
107
+ let global = flags.has("--global");
108
+ const customDir = dirFlag ? dirFlag.slice("--dir=".length) : null;
109
+ const wireMcp = !flags.has("--no-mcp");
110
+
111
+ // Interactive only when the user picked nothing and a human is
112
+ // attached; agents and CI get the full default install silently.
113
+ const chose = claude || cursor || customDir !== null;
114
+ if (!chose && process.stdin.isTTY && !flags.has("--yes")) {
115
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
116
+ const which = await ask(rl, "Install for which agents? (both / claude / cursor)", "both");
117
+ claude = which === "both" || which === "claude";
118
+ cursor = which === "both" || which === "cursor";
119
+ if (claude) {
120
+ const scope = await ask(rl, "Claude Code scope? (project / global)", "project");
121
+ global = scope === "global";
122
+ }
123
+ rl.close();
124
+ } else if (!chose) {
125
+ claude = true;
126
+ cursor = true;
127
+ }
128
+
129
+ const skillText = fs.readFileSync(SKILL_SRC, "utf8");
130
+
131
+ if (claude) {
132
+ const root = global ? os.homedir() : process.cwd();
133
+ place(SKILL_SRC, path.join(root, ".claude", "skills", "nodality", "SKILL.md"));
134
+ if (wireMcp) {
135
+ if (global) {
136
+ // ~/.claude.json holds per-project state beside the MCP
137
+ // registry; the supported route in is the CLI, so hand it over.
138
+ log("global MCP registration: run this once yourself:");
139
+ log(" claude mcp add nodality -s user -- npx nodality mcp");
140
+ } else {
141
+ registerMcp(path.join(process.cwd(), ".mcp.json"));
142
+ }
143
+ }
144
+ }
145
+
146
+ if (cursor) {
147
+ if (global) {
148
+ log("SKIPPED Cursor — rules are per-project; re-run without --global inside a project.");
149
+ } else {
150
+ place(SKILL_SRC, path.join(process.cwd(), ".cursor", "rules", "nodality.mdc"), toCursorRule(skillText));
151
+ if (wireMcp) registerMcp(path.join(process.cwd(), ".cursor", "mcp.json"));
152
+ }
153
+ }
154
+
155
+ if (customDir) {
156
+ place(SKILL_SRC, path.join(path.resolve(customDir), "SKILL.md"));
157
+ }
158
+
159
+ log("done. Re-run this command after upgrading nodality to refresh the skill.");
160
+ }
package/bin/nodality.js CHANGED
@@ -55,6 +55,15 @@ function showUsage() {
55
55
  # { "mcpServers": { "nodality": {
56
56
  # "command": "npx",
57
57
  # "args": ["nodality", "mcp"] } } }
58
+ nodality skill [flags] # Install the /nodality skill into agent
59
+ # IDEs. No flags: interactive (or full
60
+ # default install when not a TTY).
61
+ # --claude --cursor pick agents
62
+ # --global Claude Code: user-wide
63
+ # (default: this project)
64
+ # --dir=<path> copy SKILL.md anywhere
65
+ # --no-mcp skip MCP registration
66
+ # Re-run after upgrading to refresh in place.
58
67
  nodality help
59
68
 
60
69
  Compile flags:
@@ -863,6 +872,9 @@ async function main() {
863
872
  await runFanoutStandalone(rest);
864
873
  } else if (command === "stage") {
865
874
  await runStage(rest);
875
+ } else if (command === "skill") {
876
+ const { runSkillInstall } = await import("./install-skill.mjs");
877
+ await runSkillInstall(rest);
866
878
  } else if (command === "mcp") {
867
879
  // Lazily imported so that prerender/compile/stage pay nothing for a
868
880
  // subcommand they never touch, and so a broken morph core cannot
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.2.2
2
+ * nodality v1.2.5
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */