mosaic-headless 1.21.1 → 1.21.2

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/SKILL.md CHANGED
@@ -4,7 +4,7 @@ description: |
4
4
  Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface with `mo.py`, which joins every source table to the live sweeps so a lookup leads with the measured verdict rather than the declaration (126 node types, 191 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 156 variants, 74 dynamic variables, 15 interaction triggers, 115 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, the design-token and element-class layers verified against compiled CSS, the @VAR() dynamic language verified against rendered output, nine designed pages built through the tables themselves, and the delivered pages re-read in Chromium at three viewports so a rule that is present, correct and still wrong cannot pass. Drives Mosaic's own theme export/import and its plugin data upgrade from outside the editor and holds the copy against the source tree for tree. Measured on Mosaic Pro 1.0.9: the modal (`<dialog>`), OpenStreetMap, the exit-intent and scroll-depth triggers, run rules and the memory actions all built on a live page and read back, and the 1.0.7 -> 1.0.8 -> 1.0.9 migrations driven from outside wp-admin.
5
5
  license: "MIT"
6
6
  author: "moksa (https://moksaweb.com)"
7
- version: "1.21.1"
7
+ version: "1.21.2"
8
8
  ---
9
9
 
10
10
  # Headless Mosaic
@@ -700,6 +700,12 @@ post — `build_all.py` resets first for that reason.
700
700
  rows and `theme_zip_compare.php` reports a tree that does not match - delete
701
701
  nodes with a missing parent REPEATEDLY until none are left, because each pass
702
702
  orphans the next level down.
703
+ - **`width` / `height` and their min/max take the keyword `stretch` since 1.0.9**,
704
+ and Mosaic emits `-webkit-fill-available` before it so an older engine still gets
705
+ something. They are still token-referencable - `CSSSizePropertyFactory` extends
706
+ the collection-variable one, which is why `data/style-properties.csv` resolves a
707
+ factory's ancestry rather than testing its name. 39 properties take a token, not
708
+ the 34 counted before that fix.
703
709
  - **A width copied out of Elementor needs `maxWidth: "100%"` beside it.**
704
710
  Elementor caps every widget with `max-width:100%`, so a px width there is a
705
711
  desktop intent its own CSS already constrains; carried across bare it keeps the
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.21.1"
23
+ "version": "1.21.2"
24
24
  },
25
25
  "loaderBehaviour": "Upload via Settings -> Skills -> Upload. Claude.ai parses SKILL.md frontmatter and surfaces the skill in your library. The extraction tool (extract-block-schema.php) needs a live WP-CLI connection and won't run in the sandbox; use it from a local terminal against your own site instead.",
26
26
  "uploadSteps": [
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.21.1"
23
+ "version": "1.21.2"
24
24
  },
25
25
  "loaderBehaviour": "Auto-loads on session start when SKILL.md frontmatter parses successfully.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.21.1"
23
+ "version": "1.21.2"
24
24
  },
25
25
  "loaderBehaviour": "Confirmed (2026-07-11): Codex CLI natively supports the SKILL.md spec. Place SKILL.md under .codex/skills/<name>/ (project) or ~/.codex/skills/<name>/ (personal) and Codex loads the name+description at session start, then the full body on demand. A parallel, broader convention .agents/skills/ (searched from cwd up to repo root, then ~/.agents/skills/) also exists across multiple tools - if your Codex CLI version prioritizes that path instead, mirror the same SKILL.md there.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.21.1"
23
+ "version": "1.21.2"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: GitHub Copilot added a proper '.github/skills/' Agent Skills directory (December 2025), alongside the older single-file .github/copilot-instructions.md convention. This config targets the new skills-directory form. If your Copilot version predates this (pre Dec 2025), use the instructions-append fallback instead (see fallback below).",
26
26
  "fallback": {
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.21.1"
23
+ "version": "1.21.2"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: Gemini CLI now natively supports the same SKILL.md standard as Claude Code and Codex CLI - the same directory-based skill works unmodified. Gemini CLI discovers skills in this precedence order: built-in, extension skills, ~/.gemini/skills/ (personal), .gemini/skills/ (project, shared via version control). At session start Gemini injects each discovered skill's name+description into the system prompt and calls activate_skill when a task matches.",
26
26
  "verified": true,
@@ -38,12 +38,12 @@ wordSpacing,,CSSCollectionVariablePropertyFactory,,,yes
38
38
  whiteSpace,,CSSPropertyFactory,,normal|pre-wrap|nowrap|pre,
39
39
  textTransform,,CSSPropertyFactory,,none|lowercase|uppercase|capitalize,
40
40
  textShadow,,CSSTextShadowStylePropertyFactory,,,
41
- width,,CSSSizePropertyFactory,,,
42
- minWidth,,CSSSizePropertyFactory,,,
43
- maxWidth,,CSSSizePropertyFactory,,,
44
- height,,CSSSizePropertyFactory,,,
45
- minHeight,,CSSSizePropertyFactory,,,
46
- maxHeight,,CSSSizePropertyFactory,,,
41
+ width,,CSSSizePropertyFactory,,,yes
42
+ minWidth,,CSSSizePropertyFactory,,,yes
43
+ maxWidth,,CSSSizePropertyFactory,,,yes
44
+ height,,CSSSizePropertyFactory,,,yes
45
+ minHeight,,CSSSizePropertyFactory,,,yes
46
+ maxHeight,,CSSSizePropertyFactory,,,yes
47
47
  position,,CSSPropertyFactory,,static|relative|absolute|fixed|sticky,
48
48
  zIndex,,CSSPropertyFactory,,,
49
49
  top,,CSSCollectionVariablePropertyFactory,,,yes
@@ -61,19 +61,19 @@ paddingLeft,,CSSCollectionVariablePropertyFactory,,,yes
61
61
  borderRadius,,CSSBorderRadiusPropertyFactory,,,
62
62
  borderTopWidth,borderStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
63
63
  borderTopStyle,borderStyle,CSSGrouppedPropertyFactory,,,
64
- borderTopColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,
64
+ borderTopColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,yes
65
65
  borderRightWidth,borderStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
66
66
  borderRightStyle,borderStyle,CSSGrouppedPropertyFactory,,,
67
- borderRightColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,
67
+ borderRightColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,yes
68
68
  borderBottomWidth,borderStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
69
69
  borderBottomStyle,borderStyle,CSSGrouppedPropertyFactory,,,
70
- borderBottomColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,
70
+ borderBottomColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,yes
71
71
  borderLeftWidth,borderStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
72
72
  borderLeftStyle,borderStyle,CSSGrouppedPropertyFactory,,,
73
- borderLeftColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,
73
+ borderLeftColor,borderStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,yes
74
74
  outlineWidth,outlineStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
75
75
  outlineStyle,outlineStyle,CSSGrouppedPropertyFactory,,,
76
- outlineColor,outlineStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,
76
+ outlineColor,outlineStyle,CSSGrouppedPropertyFactory,CSSColorProperty,,yes
77
77
  outlineOffset,outlineStyle,CSSGrouppedPropertyFactory,CSSCollectionVariableProperty,,yes
78
78
  boxShadow,,CSSBoxShadowStylePropertyFactory,,,
79
79
  opacity,,CSSPropertyFactory,,,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mosaic-headless",
3
- "version": "1.21.1",
3
+ "version": "1.21.2",
4
4
  "description": "AI-agent skill: build Mosaic Pro (Nextend) WordPress sites by writing the underlying data model directly - 23 custom tables, no visual editor, no DOM. Every node type, style property and node property swept against a live install and asserted on the delivered HTML and compiled CSS. Installs into Claude Code, Cursor, Codex CLI, Gemini CLI, Copilot, Continue, Windsurf and Claude.ai.",
5
5
  "keywords": [
6
6
  "wordpress",
@@ -198,6 +198,33 @@ anywhere. That is the skill's existing rule (`ValidatorDynamicCode` = bare strin
198
198
  `ValidatorDynamicCodeObject` = `{"v": …}`) applying to a new element, and it is also
199
199
  why those three can hold `@VAR('post/meta_lat')` and a custom field can drive the map.
200
200
 
201
+ ## The rest of 1.0.9, briefly
202
+
203
+ Not everything in the release is a node you place. Four things that change how the
204
+ plugin behaves rather than what you can build:
205
+
206
+ - **`stretch` on the size properties.** `width`, `height` and their min/max moved to
207
+ `CSSSizePropertyFactory`, which accepts the keyword and emits
208
+ `width:-webkit-fill-available` **then** `width:stretch` — the modern value last so
209
+ a current engine lands on it and an older one keeps the alias. Measured on all
210
+ three of width / height / max-width; the author's casing is preserved as typed.
211
+ - **`ElementClassPruner`.** The generated `_<token>` class is now a placeholder while
212
+ the tree renders, and one pass over the finished HTML keeps it only where a
213
+ selector actually claimed it. The marker is random per render, so the pass can
214
+ never touch a class that arrived from post content or a shortcode. This is the
215
+ mechanism behind "an element whose styles compile to nothing has no generated
216
+ class" — it is a deliberate feature, not an accident.
217
+ - **Author and term page instances.** `PageInstance/PageTypes/Author` and `Term` let
218
+ the editor put a specific author or taxonomy term in front of an archive template;
219
+ a term has no assign of its own, because a term archive is only ever rendered by
220
+ its path.
221
+ - **`POST /template/createAutoTemplate`** (`resourceQuery`, `masterID`) creates the
222
+ automatic template a post type is missing — a template on the post type's PATH,
223
+ with nothing recorded against the resource that prompted it. Deliberately not the
224
+ assign endpoint: a post type whose resources cannot carry an assign still needs a
225
+ way to be designed, and conflating the two would make this look like an assign.
226
+ 115 routes now, up from 114.
227
+
201
228
  ## What else moved in the delivered page
202
229
 
203
230
  **The three per-breakpoint stylesheets became one.** Through 1.0.8 a page carried
@@ -109,12 +109,13 @@ The `factory` column in `data/style-properties.csv` tells you the value shape:
109
109
  | factory | write |
110
110
  |---|---|
111
111
  | `CSSPropertyFactory` (29) | a plain CSS value string — `"flex"`, `"center"`, `"700"` |
112
- | `CSSCollectionVariablePropertyFactory` (26) | a length string, or a reference to a collection variable |
112
+ | `CSSCollectionVariablePropertyFactory` (20) | a length string, or a reference to a collection variable |
113
+ | `CSSSizePropertyFactory` (6) | `width`, `height` and their min/max. A collection-variable length like the row above - it is a subclass - plus the keyword **`stretch`**, which Mosaic emits as `-webkit-fill-available` FIRST and `stretch` second, so a current engine takes the standard value and an older one the alias. New in 1.0.9; measured. |
113
114
  | `CSSColorPropertyFactory` (2) | `color`, `backgroundColor` — a colour string or variable reference |
114
115
  | `CSSGrouppedPropertyFactory` (20) | one leg of `borderStyle`, `outlineStyle` or `gridChildPosition`; the data is keyed under the group |
115
116
  | the other 21 | purpose-built shapes — shadow, transform, gradient, filter, mask. Read the factory named in the CSV. |
116
117
 
117
- Plain strings were accepted verbatim for the properties probed above. The 34
118
+ Plain strings were accepted verbatim for the properties probed above. The 39
118
119
  token-referencable properties are the interface to the collection/variable layer,
119
120
  which is how a design system is meant to be expressed rather than hard-coding values
120
121
  on every node.
@@ -127,7 +128,11 @@ lowest layer and it opts that node out of both reuse mechanisms:
127
128
  1. **Variants** (`data/variants.csv`, 152 built in - Mosaic's element classes) carry
128
129
  the shared look; a node points at one through `style.variant`.
129
130
  2. **Collections → modes/skins → variables** are the token layer, the thing the
130
- 34 token-referencable properties reference.
131
+ 39 token-referencable properties reference. (34 until this was last counted:
132
+ `data/style-properties.csv` resolves a factory's ANCESTRY now rather than
133
+ testing its name, which 1.0.9 made necessary - `CSSSizePropertyFactory` extends
134
+ the collection-variable one - and which also recovered the five grouped colour
135
+ legs whose value class was always `CSSColorProperty`.)
131
136
 
132
137
  Per-node `style` is for the exception, not the rule. Build a design by putting values
133
138
  in the class and token layers and letting nodes inherit; reach for per-node style when
@@ -110,6 +110,44 @@ def style_enums(plugin_root):
110
110
  return out
111
111
 
112
112
 
113
+ def factory_parents(plugin_root):
114
+ """class -> its parent, for every property factory under Builder/Style.
115
+
116
+ Read because a factory's NAME stopped being enough in 1.0.9:
117
+ `CSSSizePropertyFactory extends CSSCollectionVariablePropertyFactory` and drives
118
+ width / height and their min and max, which still take a collection variable -
119
+ but a name test for "CollectionVariable" misses it and the table then says six
120
+ length properties cannot reference a design token, which is false.
121
+ """
122
+ parents = {}
123
+ base = os.path.join(plugin_root, "Mosaic", "Builder", "Style")
124
+ for root, _dirs, files in os.walk(base):
125
+ for name in files:
126
+ if not name.endswith(".php"):
127
+ continue
128
+ with open(os.path.join(root, name), encoding="utf-8", errors="replace") as fh:
129
+ src = fh.read()
130
+ # `extends Foo` and `extends \Name\Space\Foo` both; only the last
131
+ # segment is kept, which is what the factory column shows.
132
+ bs = chr(92)
133
+ for m in re.finditer("class" + r"\s+(\w+)\s+extends\s+([" + bs * 2
134
+ + r"\w]+)", src):
135
+ parents[m.group(1)] = m.group(2).split(bs)[-1]
136
+ return parents
137
+
138
+
139
+ def is_tokenable(factory, value_class, parents):
140
+ """Does this factory, or anything it inherits from, accept a collection variable?"""
141
+ for name in (factory, value_class):
142
+ seen = set()
143
+ while name and name not in seen:
144
+ if "CollectionVariable" in name or "Color" in name:
145
+ return True
146
+ seen.add(name)
147
+ name = parents.get(name)
148
+ return False
149
+
150
+
113
151
  def extract(plugin_root, out_dir):
114
152
  enums = style_enums(plugin_root)
115
153
  path = os.path.join(plugin_root, "Mosaic", "Builder", "Style", "SupportedStyleProperties.php")
@@ -118,6 +156,7 @@ def extract(plugin_root, out_dir):
118
156
  with open(path, encoding="utf-8", errors="replace") as fh:
119
157
  src = fh.read()
120
158
 
159
+ parents = factory_parents(plugin_root)
121
160
  rows = []
122
161
  for factory, first, member, value_class in RE_ADD.findall(src):
123
162
  grouped = factory == "CSSGrouppedPropertyFactory"
@@ -128,10 +167,9 @@ def extract(plugin_root, out_dir):
128
167
  "factory": factory,
129
168
  "value_class": value_class.split("\\")[-1] if value_class else "",
130
169
  "accepted_values": "|".join(enums.get(member if grouped else first, [])),
131
- "tokenable": "yes" if (
132
- "CollectionVariable" in factory or "Color" in factory
133
- or "CollectionVariable" in (value_class or "")
134
- ) else "",
170
+ "tokenable": "yes" if is_tokenable(
171
+ factory, value_class.split("\\")[-1] if value_class else "",
172
+ parents) else "",
135
173
  }
136
174
  )
137
175