mosaic-headless 1.2.0 → 1.2.1
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.ja.md +3 -3
- package/README.ko.md +96 -0
- package/README.md +13 -4
- package/README.zh-TW.md +3 -3
- package/SKILL.md +3 -3
- package/assets/templates/platforms/claude-ai.json +1 -1
- package/assets/templates/platforms/claude-code.json +1 -1
- package/assets/templates/platforms/codex-cli.json +1 -1
- package/assets/templates/platforms/copilot.json +1 -1
- package/assets/templates/platforms/gemini-cli.json +1 -1
- package/bin/check-release.mjs +9 -2
- package/data/animatable-properties.csv +23 -23
- package/data/condition-comparators.csv +13 -13
- package/data/condition-subjects.csv +60 -60
- package/data/db-columns.csv +207 -207
- package/data/default-children.csv +11 -11
- package/data/dynamic-variables.csv +75 -75
- package/data/element-classes.csv +152 -152
- package/data/evaluator-functions.csv +20 -20
- package/data/interaction-types.csv +13 -13
- package/data/node-properties.csv +182 -182
- package/data/node-property-verification.csv +182 -182
- package/data/node-types.csv +123 -123
- package/data/node-verification.csv +123 -123
- package/data/placement-rules.csv +123 -123
- package/data/pluggables.csv +208 -208
- package/data/property-verification.csv +171 -171
- package/data/rest-routes.csv +115 -115
- package/data/rwd-verification.csv +577 -570
- package/data/style-properties.csv +99 -99
- package/data/style-states.csv +54 -54
- package/data/style-value-shapes.csv +23 -23
- package/data/style-verification.csv +99 -99
- package/package.json +59 -59
- package/references/failure-modes.md +22 -0
- package/sites/_moksa.py +72 -26
- package/sites/moksa.json +9071 -8684
- package/tools/verify_rwd.py +14 -1
- package/README.zh-CN.md +0 -87
- package/tools/build_all.py +0 -55
- package/tools/build_report.py +0 -221
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mosaic-headless",
|
|
3
|
-
"version": "1.2.
|
|
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
|
-
"keywords": [
|
|
6
|
-
"wordpress",
|
|
7
|
-
"mosaic",
|
|
8
|
-
"mosaic-pro",
|
|
9
|
-
"nextend",
|
|
10
|
-
"page-builder",
|
|
11
|
-
"claude-code",
|
|
12
|
-
"agent-skill",
|
|
13
|
-
"ai-agent",
|
|
14
|
-
"headless",
|
|
15
|
-
"woocommerce",
|
|
16
|
-
"wp-cli"
|
|
17
|
-
],
|
|
18
|
-
"homepage": "https://github.com/Moksa1123/mosaic-headless#readme",
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/Moksa1123/mosaic-headless.git"
|
|
22
|
-
},
|
|
23
|
-
"bugs": {
|
|
24
|
-
"url": "https://github.com/Moksa1123/mosaic-headless/issues"
|
|
25
|
-
},
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"author": "moksa (https://moksaweb.com)",
|
|
28
|
-
"type": "module",
|
|
29
|
-
"bin": {
|
|
30
|
-
"mosaic-headless": "bin/install.mjs"
|
|
31
|
-
},
|
|
32
|
-
"files": [
|
|
33
|
-
"bin/",
|
|
34
|
-
"assets/",
|
|
35
|
-
"data/*.csv",
|
|
36
|
-
"references/",
|
|
37
|
-
"sites/_moksa.py",
|
|
38
|
-
"sites/moksa.json",
|
|
39
|
-
"tools/*.py",
|
|
40
|
-
"tools/*.php",
|
|
41
|
-
"SKILL.md",
|
|
42
|
-
"README.md",
|
|
43
|
-
"README.zh-TW.md",
|
|
44
|
-
"README.
|
|
45
|
-
"README.
|
|
46
|
-
"LICENSE"
|
|
47
|
-
],
|
|
48
|
-
"engines": {
|
|
49
|
-
"node": ">=18"
|
|
50
|
-
},
|
|
51
|
-
"scripts": {
|
|
52
|
-
"install-skill": "node bin/install.mjs",
|
|
53
|
-
"check": "node bin/check-release.mjs",
|
|
54
|
-
"preversion": "npm run check",
|
|
55
|
-
"version": "node bin/sync-version.mjs && git add SKILL.md assets/templates/platforms",
|
|
56
|
-
"postversion": "git push && git push --tags",
|
|
57
|
-
"prepublishOnly": "npm run check"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mosaic-headless",
|
|
3
|
+
"version": "1.2.1",
|
|
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
|
+
"keywords": [
|
|
6
|
+
"wordpress",
|
|
7
|
+
"mosaic",
|
|
8
|
+
"mosaic-pro",
|
|
9
|
+
"nextend",
|
|
10
|
+
"page-builder",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"agent-skill",
|
|
13
|
+
"ai-agent",
|
|
14
|
+
"headless",
|
|
15
|
+
"woocommerce",
|
|
16
|
+
"wp-cli"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/Moksa1123/mosaic-headless#readme",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Moksa1123/mosaic-headless.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Moksa1123/mosaic-headless/issues"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "moksa (https://moksaweb.com)",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"bin": {
|
|
30
|
+
"mosaic-headless": "bin/install.mjs"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin/",
|
|
34
|
+
"assets/",
|
|
35
|
+
"data/*.csv",
|
|
36
|
+
"references/",
|
|
37
|
+
"sites/_moksa.py",
|
|
38
|
+
"sites/moksa.json",
|
|
39
|
+
"tools/*.py",
|
|
40
|
+
"tools/*.php",
|
|
41
|
+
"SKILL.md",
|
|
42
|
+
"README.md",
|
|
43
|
+
"README.zh-TW.md",
|
|
44
|
+
"README.ja.md",
|
|
45
|
+
"README.ko.md",
|
|
46
|
+
"LICENSE"
|
|
47
|
+
],
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"install-skill": "node bin/install.mjs",
|
|
53
|
+
"check": "node bin/check-release.mjs",
|
|
54
|
+
"preversion": "npm run check",
|
|
55
|
+
"version": "node bin/sync-version.mjs && git add SKILL.md assets/templates/platforms",
|
|
56
|
+
"postversion": "git push && git push --tags",
|
|
57
|
+
"prepublishOnly": "npm run check"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -171,6 +171,28 @@ required children on commit.
|
|
|
171
171
|
A record committed with `"modified_gmt": "2026-09-05 17:00:00"` came back stored as
|
|
172
172
|
`16:59:16`. The server overwrites it. Do not use a value you sent as a local cache key.
|
|
173
173
|
|
|
174
|
+
## A page cache turns "it worked" into "the node does not exist"
|
|
175
|
+
|
|
176
|
+
Not a Mosaic failure - a failure of *checking* Mosaic, and it produces the exact
|
|
177
|
+
result this skill exists to prevent: a confident negative about something that is
|
|
178
|
+
actually there.
|
|
179
|
+
|
|
180
|
+
Commit succeeds. `build_site.py` reports the byte size the renderer produced. Then
|
|
181
|
+
the verifier fetches the URL, a full-page cache in front of WordPress (Varnish on
|
|
182
|
+
Cloudways, or any CDN) answers with the pre-commit HTML, and every declaration on a
|
|
183
|
+
node you have just added comes back `no-element`. Measured on this install: the
|
|
184
|
+
builder saw 138878 bytes, `curl` on the same URL a second later got 136021, and
|
|
185
|
+
seven declarations on two brand-new grid wrappers were reported missing while the
|
|
186
|
+
wrappers were sitting correctly in the database and in the committed JSON.
|
|
187
|
+
|
|
188
|
+
The tell is the byte count: if the size the builder reports and the size you fetch
|
|
189
|
+
disagree, you are not looking at what you wrote.
|
|
190
|
+
|
|
191
|
+
`tools/verify_rwd.py` now appends a unique `_v=<ms>` query string and sends
|
|
192
|
+
`Cache-Control: no-cache` on every fetch, so the assertion is always made against the
|
|
193
|
+
document that was actually committed. Do the same in anything else that checks a page
|
|
194
|
+
- including a browser: hard-reload is not always enough, a query string always is.
|
|
195
|
+
|
|
174
196
|
## Reproducing all of this
|
|
175
197
|
|
|
176
198
|
```bash
|
package/sites/_moksa.py
CHANGED
|
@@ -131,7 +131,7 @@ def mono(text, size="11px", color="--mk-muted", track="0.14em", **st):
|
|
|
131
131
|
fontSize=size, letterSpacing=track, **st)
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def figure(attr, num, size="
|
|
134
|
+
def figure(attr, num, size="56px", t="44px", m="34px"):
|
|
135
135
|
"""A number set as one masked box per digit.
|
|
136
136
|
|
|
137
137
|
A count-up needs JavaScript; a digit rolling out from behind its own edge does
|
|
@@ -149,8 +149,8 @@ def figure(attr, num, size="40px", t="34px", m="27px"):
|
|
|
149
149
|
"overflow:hidden;display:inline-block;"
|
|
150
150
|
"--d:%dms;" % (j * 70)}}},
|
|
151
151
|
"children": [T("h3", ch, color={"token": "--mk-ink"}, fontSize=size,
|
|
152
|
-
fontWeight="
|
|
153
|
-
lineHeight="1.
|
|
152
|
+
fontWeight="600", letterSpacing="-0.03em",
|
|
153
|
+
lineHeight="1.02", fontFamily=DISPLAY,
|
|
154
154
|
_t={"fontSize": t}, _m={"fontSize": m})]}
|
|
155
155
|
for j, ch in enumerate(num)
|
|
156
156
|
]}
|
|
@@ -172,7 +172,7 @@ def clause(num, en, zh, attr):
|
|
|
172
172
|
box(attr + "-t", {}, [
|
|
173
173
|
mono(en, size="11px", color="--mk-muted"),
|
|
174
174
|
T("h2", zh, color={"token": "--mk-ink"}, fontSize="34px",
|
|
175
|
-
fontWeight="600", letterSpacing="
|
|
175
|
+
fontWeight="600", letterSpacing="0.01em", lineHeight="1.35",
|
|
176
176
|
fontFamily=DISPLAY, marginTop="10px",
|
|
177
177
|
_t={"fontSize": "29px"}, _m={"fontSize": "23px"}),
|
|
178
178
|
]),
|
|
@@ -234,6 +234,16 @@ SPEC = [
|
|
|
234
234
|
("SUPPORT", "876", "技術支援與服務"),
|
|
235
235
|
]
|
|
236
236
|
|
|
237
|
+
# The masthead's right-hand column. A profile document states its terms in its own
|
|
238
|
+
# header, and it is the content that fills the frame the headline leaves empty.
|
|
239
|
+
SIDE = [
|
|
240
|
+
("DISCIPLINE", "Web / AI / Automation"),
|
|
241
|
+
("STACK", "WordPress · n8n · Claude"),
|
|
242
|
+
("ENGAGEMENT", "專案制 / 長期維運"),
|
|
243
|
+
("LEAD TIME", "3–8 週"),
|
|
244
|
+
("RESPONSE", "1 個工作天"),
|
|
245
|
+
]
|
|
246
|
+
|
|
237
247
|
SERVICES = [
|
|
238
248
|
("01", "WEB & E-COMMERCE", "網站與電商",
|
|
239
249
|
"品牌官網、電商平台與 WordPress 開發,乾淨的結構與好管理的後台。"),
|
|
@@ -659,7 +669,7 @@ FOOTER = box("mk-footer",
|
|
|
659
669
|
mono("MAKE WEB MEANINGFUL", size="11px", color="--mk-accent",
|
|
660
670
|
track="0.2em"),
|
|
661
671
|
T("h2", "打造有價值的網站體驗。", color={"token": "--mk-paper"},
|
|
662
|
-
fontSize="30px", fontWeight="500", letterSpacing="
|
|
672
|
+
fontSize="30px", fontWeight="500", letterSpacing="0.02em",
|
|
663
673
|
lineHeight="1.5", fontFamily=CJK, marginTop="16px",
|
|
664
674
|
_m={"fontSize": "22px"}),
|
|
665
675
|
box("mk-f-contact",
|
|
@@ -712,8 +722,8 @@ FOOTER = box("mk-footer",
|
|
|
712
722
|
|
|
713
723
|
# ── the page ──────────────────────────────────────────────────────────────────
|
|
714
724
|
HERO_LINE = dict(color={"token": "--mk-ink"}, fontSize="62px", fontWeight="600",
|
|
715
|
-
lineHeight="1.
|
|
716
|
-
_t={"fontSize": "
|
|
725
|
+
lineHeight="1.14", letterSpacing="0.005em", fontFamily=DISPLAY,
|
|
726
|
+
_t={"fontSize": "48px"}, _m={"fontSize": "32px"})
|
|
717
727
|
|
|
718
728
|
MASTHEAD = section("mk-mast", [wrap("mk-mast-in", [
|
|
719
729
|
# the document's own header block: what this is, where it is from, which revision
|
|
@@ -733,11 +743,19 @@ MASTHEAD = section("mk-mast", [wrap("mk-mast-in", [
|
|
|
733
743
|
{"display": "flex", "alignItems": "center", "marginTop": "10px"},
|
|
734
744
|
[box("mk-caret", {}, [])]),
|
|
735
745
|
]),
|
|
746
|
+
box("mk-mast-body",
|
|
747
|
+
{"display": "grid", "gridCols": "1.35fr .65fr", "columnGap": "56px",
|
|
748
|
+
"rowGap": "32px", "alignItems": "start", "marginTop": "26px"},
|
|
749
|
+
_t={"gridCols": "1.2fr .8fr", "columnGap": "36px"},
|
|
750
|
+
_m={"gridCols": "repeat(1, 1fr)", "columnGap": "0px", "rowGap": "26px",
|
|
751
|
+
"marginTop": "20px"},
|
|
752
|
+
children=[
|
|
753
|
+
box("mk-mast-left", {}, [
|
|
736
754
|
{"type": "text", "data": {"tagName": "p", "attrID": "mk-mast-lede"},
|
|
737
755
|
"style": bp({"color": {"token": "--mk-muted"}, "fontSize": "16px",
|
|
738
|
-
"lineHeight": "2", "marginTop": "
|
|
756
|
+
"lineHeight": "2", "marginTop": "0px", "maxWidth": "30em"},
|
|
739
757
|
None,
|
|
740
|
-
{"fontSize": "14px", "lineHeight": "1.95", "marginTop": "
|
|
758
|
+
{"fontSize": "14px", "lineHeight": "1.95", "marginTop": "0px"}),
|
|
741
759
|
"text": "我打造網站、開發軟體、導入 AI、串起自動化流程,"
|
|
742
760
|
"讓技術不只是工具,而是幫你省下時間、長出業績的數位夥伴。"},
|
|
743
761
|
{"type": "div", "data": {"attrID": "mk-mast-cta"},
|
|
@@ -747,19 +765,46 @@ MASTHEAD = section("mk-mast", [wrap("mk-mast-in", [
|
|
|
747
765
|
"children": [
|
|
748
766
|
# underlined links, not buttons: a document points, it does not sell
|
|
749
767
|
{"type": "button", "data": {"attrID": "mk-cta-%d" % n, "url": href},
|
|
750
|
-
"style": {"&": {"_":
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
768
|
+
"style": {"&": {"_": dict(
|
|
769
|
+
{"backgroundColor": {"token": "--mk-accent"},
|
|
770
|
+
"color": {"token": "--mk-paper"},
|
|
771
|
+
"paddingLeft": "22px", "paddingRight": "22px",
|
|
772
|
+
"paddingTop": "13px", "paddingBottom": "13px",
|
|
773
|
+
"customStyles": "border:1px solid rgb(255,90,54);"}
|
|
774
|
+
if n == 1 else
|
|
775
|
+
{"backgroundColor": "rgba(0,0,0,0)", "color": {"token": "--mk-ink"},
|
|
776
|
+
"paddingLeft": "0px", "paddingRight": "0px",
|
|
777
|
+
"paddingTop": "13px", "paddingBottom": "13px",
|
|
778
|
+
"customStyles": "border:1px solid rgba(0,0,0,0);"
|
|
779
|
+
"border-bottom-color:rgb(22,24,28);"},
|
|
780
|
+
fontSize="13px", fontFamily=MONO, letterSpacing="0.1em",
|
|
781
|
+
radius="0px", cursor="pointer", transitionAll="180ms ease")},
|
|
782
|
+
"hover": {"_": ({"backgroundColor": {"token": "--mk-ink"},
|
|
783
|
+
"customStyles": "border:1px solid rgb(22,24,28);"}
|
|
784
|
+
if n == 1
|
|
785
|
+
else {"color": {"token": "--mk-accent"}})}},
|
|
759
786
|
"text": text}
|
|
760
|
-
for n, (text, href) in enumerate([("→
|
|
761
|
-
("→
|
|
787
|
+
for n, (text, href) in enumerate([("服務項目 →", "#services"),
|
|
788
|
+
("精選作品 →", "#works")], start=1)
|
|
762
789
|
]},
|
|
790
|
+
]),
|
|
791
|
+
# the right-hand column: what a spec sheet puts in its header block
|
|
792
|
+
box("mk-mast-side",
|
|
793
|
+
{"display": "grid", "rowGap": "0px",
|
|
794
|
+
"customStyles": "border-top:1px solid " + RULE_INK + ";"},
|
|
795
|
+
_m={"customStyles": "border-top:1px solid " + RULE + ";"},
|
|
796
|
+
children=[
|
|
797
|
+
box("mk-mast-side-%d" % i,
|
|
798
|
+
{"display": "grid", "gridCols": "1fr auto",
|
|
799
|
+
"columnGap": "14px", "alignItems": "baseline",
|
|
800
|
+
"paddingTop": "11px", "paddingBottom": "11px",
|
|
801
|
+
"customStyles": ("" if i == 0
|
|
802
|
+
else "border-top:1px solid " + RULE + ";")},
|
|
803
|
+
[mono(k, size="10px", color="--mk-faint", track="0.18em"),
|
|
804
|
+
mono(v, size="12px", color="--mk-ink", track="0.02em")])
|
|
805
|
+
for i, (k, v) in enumerate(SIDE)
|
|
806
|
+
]),
|
|
807
|
+
]),
|
|
763
808
|
box("mk-spec-rule", {"marginTop": "56px"}, [], _m={"marginTop": "40px"}),
|
|
764
809
|
# the figures as a datasheet, not as four big numbers looking for attention
|
|
765
810
|
grid("mk-spec", 4, "0px", tcols=2, mcols=2,
|
|
@@ -787,7 +832,8 @@ MASTHEAD = section("mk-mast", [wrap("mk-mast-in", [
|
|
|
787
832
|
"columnGap": "3px", "marginTop": "12px"},
|
|
788
833
|
[figure("mk-fig-%d" % i, num),
|
|
789
834
|
T("p", "+", color={"token": "--mk-accent"},
|
|
790
|
-
fontSize="
|
|
835
|
+
fontSize="22px", fontFamily=DISPLAY, fontWeight="600",
|
|
836
|
+
_m={"fontSize": "16px"})]),
|
|
791
837
|
T("p", zh, color={"token": "--mk-muted"}, fontSize="12px",
|
|
792
838
|
marginTop="10px", lineHeight="1.7", _m={"fontSize": "11px"}),
|
|
793
839
|
])
|
|
@@ -970,8 +1016,8 @@ PRODUCT_SEC = section("products", [wrap("mk-prod-in", [
|
|
|
970
1016
|
mono("OUR PRODUCTS", size="11px", color="rgb(140,142,150)"),
|
|
971
1017
|
T("h2", "不只接案,也開發自己的產品",
|
|
972
1018
|
color={"token": "--mk-paper"}, fontSize="34px",
|
|
973
|
-
fontWeight="600", letterSpacing="
|
|
974
|
-
lineHeight="1.
|
|
1019
|
+
fontWeight="600", letterSpacing="0.01em",
|
|
1020
|
+
lineHeight="1.35", fontFamily=DISPLAY, marginTop="10px",
|
|
975
1021
|
_t={"fontSize": "29px"}, _m={"fontSize": "23px"}),
|
|
976
1022
|
]),
|
|
977
1023
|
]),
|
|
@@ -995,7 +1041,7 @@ PRODUCT_SEC = section("products", [wrap("mk-prod-in", [
|
|
|
995
1041
|
T("h3", name, color={"token": "--mk-paper"},
|
|
996
1042
|
fontSize="24px", fontWeight="600",
|
|
997
1043
|
fontFamily=DISPLAY, marginTop="9px",
|
|
998
|
-
letterSpacing="
|
|
1044
|
+
letterSpacing="0.01em", _m={"fontSize": "21px"}),
|
|
999
1045
|
# a property of the product, not a column of the
|
|
1000
1046
|
# table: as a fourth grid child it landed alone in
|
|
1001
1047
|
# the 72px number gutter on row two at tablet
|
|
@@ -1063,8 +1109,8 @@ CONTACT = section("contact", [wrap("mk-contact-in", [
|
|
|
1063
1109
|
mono("START A PROJECT", size="11px", color="--mk-muted"),
|
|
1064
1110
|
ml("h2", "準備好升級\n你的數位競爭力了嗎?",
|
|
1065
1111
|
color={"token": "--mk-ink"}, fontSize="44px",
|
|
1066
|
-
fontWeight="600", letterSpacing="
|
|
1067
|
-
lineHeight="1.
|
|
1112
|
+
fontWeight="600", letterSpacing="0.01em",
|
|
1113
|
+
lineHeight="1.3", fontFamily=DISPLAY, marginTop="12px",
|
|
1068
1114
|
_t={"fontSize": "36px"}, _m={"fontSize": "26px"}),
|
|
1069
1115
|
T("p", "先看方案抓預算,或直接告訴我們你想解決的問題,"
|
|
1070
1116
|
"一個工作天內回覆。",
|