mosaic-headless 1.17.0 → 1.17.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 +156 -71
- package/README.ko.md +159 -80
- package/README.md +115 -70
- package/README.zh-TW.md +140 -61
- package/SKILL.md +1 -1
- 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/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -3,120 +3,205 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
4
|
|
|
5
5
|
[Mosaic Pro](https://mosaicbuilder.com)(Nextend)のサイトを、データモデルを直接書いて
|
|
6
|
-
構築・変更する — ビジュアルエディタも DOM も使わない。
|
|
6
|
+
構築・変更する — ビジュアルエディタも DOM も使わない。Elementor のページを取り込む。
|
|
7
|
+
テーマをまるごと別のインストールへ移す。すべての主張は実際のサイトで計測済み。
|
|
7
8
|
|
|
8
9
|
*他の言語:[English](README.md) · [繁體中文](README.zh-TW.md) · [한국어](README.ko.md)*
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
13
|
+
## インストール
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx mosaic-headless # 対話式:プラットフォームを選ぶ
|
|
17
|
+
npx mosaic-headless claude-code --global # Claude Code、~/.claude/skills/ へ
|
|
18
|
+
npx mosaic-headless cursor --to ./my-project
|
|
19
|
+
npx mosaic-headless --list # 対応 8 プラットフォーム
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**更新は自動では起きない。** npm に新版が出ても、エージェントが読み込むフォルダは変わらない。
|
|
23
|
+
インストーラを `--force` 付きで再実行する(付けないと、手を入れた可能性のある SKILL.md の
|
|
24
|
+
上書きを拒否する):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx mosaic-headless@latest claude-code --global --force
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Python 3 と Playwright はツールを*動かす*ときに必要で、インストールには不要。
|
|
31
|
+
|
|
32
|
+
## これは何か
|
|
33
|
+
|
|
12
34
|
Mosaic はページを **23 個のカスタムテーブル**に保持する。`post_content` でもなければ
|
|
13
35
|
`postmeta` でもない。要素ひとつにつき 1 行、ツリー構造は `parentID` カラム、兄弟の順序は
|
|
14
|
-
fractional-index
|
|
15
|
-
|
|
36
|
+
fractional-index の文字列。エディタはこのモデルの一クライアントにすぎない。フォーマット
|
|
37
|
+
そのものではないし、なくても困らない。
|
|
16
38
|
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
このスキルはそのモデルの地図 — ソースを読んで得たものではなく、実際のインストールに対して
|
|
40
|
+
計測したもの — と、モデルを通して書き、出てきたものを検証し、Elementor からページを持ち込む
|
|
41
|
+
ためのツール群である。
|
|
19
42
|
|
|
20
|
-
##
|
|
43
|
+
## 唯一のルール
|
|
21
44
|
|
|
22
|
-
|
|
23
|
-
`data/`
|
|
45
|
+
**ノード型、プロパティ名、列挙値、スタイルキー、Free/Pro の判断を記憶から書かない。
|
|
46
|
+
`data/` で引く。**
|
|
24
47
|
|
|
25
|
-
しかも grep ではなく `mo.py` で引く。grep
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
`mo.py type` はその三つを一度に見せる。
|
|
48
|
+
しかも grep ではなく `mo.py` で引く。grep は打った質問には答えるが、本当に抱えている質問には
|
|
49
|
+
答えない。`accordion-content` を grep すればその型が存在することは分かる。スイープ表は
|
|
50
|
+
BROKE_PAGE だと言う — 置けば公開ページ全体が 54 バイトのエラー文字列になる。どちらも本当で、
|
|
51
|
+
どちらも間違った答えだ。行の横の注記は、その文字列が「親がない」ことを名指ししていること、
|
|
52
|
+
`accordion > accordion-item` の下に入れ子にすれば commit も描画も通り、キーボードで操作できる
|
|
53
|
+
開閉 UI までついてくることを言っている。`mo.py type` はその三つを一度に見せる。
|
|
32
54
|
|
|
33
55
|
```bash
|
|
34
56
|
python tools/mo.py type accordion-content # 1 つの型を、全ライブスイープに接続して表示
|
|
35
|
-
python tools/mo.py check div text button #
|
|
36
|
-
python tools/mo.py
|
|
37
|
-
python tools/mo.py
|
|
38
|
-
python tools/mo.py
|
|
57
|
+
python tools/mo.py check div text button # 安全でない/未知の型があれば 1 で終了
|
|
58
|
+
python tools/mo.py params text # 1 つの型に設定できるすべて
|
|
59
|
+
python tools/mo.py style --grouped # 単独では無効になる 20 個
|
|
60
|
+
python tools/mo.py states --verified # コンパイルされることが計測済みの状態
|
|
61
|
+
python tools/mo.py css grid-column # この CSS を出す Mosaic のキー
|
|
39
62
|
```
|
|
40
63
|
|
|
41
|
-
そのうえでページを見る。Mosaic
|
|
42
|
-
|
|
64
|
+
そのうえでページを見る。Mosaic には **7 つ**の失敗モードがあり、HTTP ステータスが変わるのは
|
|
65
|
+
そのうち 2 つだけ:
|
|
43
66
|
|
|
44
67
|
```
|
|
45
|
-
|
|
46
|
-
commit 中の PHP fatal HTTP 500
|
|
47
|
-
構造的に不正なノード HTTP 200
|
|
48
|
-
|
|
49
|
-
値の「形」が違う HTTP 200
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
バリデータの正常な拒否 HTTP 200 + 本文に `exceptions` 配列
|
|
69
|
+
commit 中の PHP fatal HTTP 500(122 型のうち 15 が plain div の下でこうなる)
|
|
70
|
+
構造的に不正なノード HTTP 200、commit 済み、DB に行あり、そして公開ページ全体が
|
|
71
|
+
54 バイトのエラー文字列になる
|
|
72
|
+
値の「形」が違う HTTP 200、保存済み、CSS ルールがただ出ない
|
|
73
|
+
ルールは正しく結果が違う HTTP 200、スタイルシートにあり、正しく、ブラウザが別の値を計算する
|
|
74
|
+
URL にテンプレートがない HTTP 406、未ログインには空の本文
|
|
75
|
+
内容による描画時 fatal HTTP 500 — commit は通り、Mosaic がページを解析する時に死ぬ。
|
|
76
|
+
`code` ノードの内容はテンプレートで、minifier が書く `@media(` は
|
|
77
|
+
関数呼び出しとして読まれる。`@media (` なら描画される。
|
|
78
|
+
build_page は前者を拒否する。
|
|
53
79
|
```
|
|
54
80
|
|
|
55
|
-
|
|
81
|
+
commit の成功はページが動く証拠ではないし、正しいスタイルシートもそうではない。ここの
|
|
82
|
+
ツールはすべて書いた後にページを取得し、5xx を空ページとして扱う — WordPress の
|
|
83
|
+
「重大なエラー」画面は 2,697 バイトで、素朴な「健全なページ」の下限より大きいからだ。
|
|
56
84
|
|
|
57
85
|
## 何を、どう検証したか
|
|
58
86
|
|
|
59
|
-
|
|
87
|
+
すべて実際のインストールに対して実行 — WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.7、
|
|
60
88
|
**ライセンスなし**:ライセンスが制限するのはテーマライブラリと更新であってノードファクトリ
|
|
61
|
-
|
|
89
|
+
ではないので、Pro の型も登録・描画される。
|
|
62
90
|
|
|
63
|
-
|
|
|
91
|
+
| 項目 | 結果 |
|
|
64
92
|
|---|---|
|
|
65
|
-
|
|
|
93
|
+
| **ノード型** | 122 / 122 を 1 型 1 ドキュメントでスイープ、commit → 描画 → 断言 → 削除:70 RENDERED、30 COMMITTED、15 COMMIT_5xx、7 BROKE_PAGE。描画されなかった行のうち 3 つは「必要な親なしで commit した」というスイープ手法の産物で、その旨が行の横にある |
|
|
66
94
|
| **スタイルプロパティ** | 98 / 98 を実ページに書き、コンパイル済み CSS と照合:58 COMPILED、18 ABSENT、21 SKIPPED |
|
|
67
|
-
| **ノードプロパティ** | 181 / 181
|
|
95
|
+
| **ノードプロパティ** | 181 / 181 を各プロパティ自身のバリデータ連鎖から導いた値で再探査:35 APPLIED、42 NO_EFFECT、55 NO_HOST、47 SKIPPED |
|
|
68
96
|
| **レスポンシブ** | 2 サイト計 731 件の `_t`/`_m` 宣言を、サイトが実際に配信したスタイルシートに対して 1 件ずつ断言 — 全件検証済み |
|
|
69
|
-
| **コンポーネント** | コンポーネント機構を端から端まで実行し **8 / 8**:カテゴリ配下に作成、ドキュメントを heal、書き込み可能な instance 経由でツリーを投入、読み取り専用の方は同じ書き込みを拒否(ネガティブコントロール)、最後に 2 つのインスタンスが 1 つの定義から描画 |
|
|
70
|
-
| **スタイル状態** | 53 状態のうち 52 を実ページに書き、テーブルが約束するセレクタと照合:**36 件が完全一致**、12 件 NO_HOST、3 件 SKIPPED、1 件 BROKE_PAGE。どの要素にも使えるグローバル 7 状態はすべて検証済み |
|
|
71
|
-
| **インタラクション** | JS アニメーション経路を、ネガティブコントロール付きで保存行を読み戻しながら検証:`propertyMetas` は**受理され保存される**。プロパティ値は依然としてバインドされないが、その境界は厳密になった |
|
|
72
|
-
| **入場アニメーション** | 単調時計でページ読み込み後の 15 時点をサンプリングし 8 項目を断言 — 再生されること、アニメーションする `@property` カウンタが 100 に達すること、ベールがヒットテストから外れること、ビューポート内に opacity 0 のまま取り残された要素がないこと、実際のクリックが文書に届くこと、`prefers-reduced-motion` ではベールがそもそも存在しないこと、そして全てが落ち着いた後もなお動いているものがあること。文書の初回レイアウトを待ってから始まるため、アニメーションの全くないページに対して遅れフレームは 1 つだけ |
|
|
73
|
-
| **常時アニメーション** | 隅で刷り続け、タップすると拡大する版 — **28 項目**:一時停止したタイムラインをスクラブして周期性を証明、5 つの幅 × 25 のスクロール位置でテキスト*と*操作要素の遮蔽を「決して読めない」を失敗条件として計測、ポインタでも Enter でも開くこと、reduced motion では静止すること。Mosaic 自身のアコーディオンの上に構築 |
|
|
74
|
-
| **アコーディオン** | `accordion-item` と `accordion-content` はスイープ表では BROKE_PAGE。ファクトリが要求する通りに入れ子にすれば commit も描画も通る、**7 件中 7 件**。注記はその行の横にある |
|
|
75
97
|
| **ブラウザ** | 配信された 2 ページを Chromium の 3 つのビューポートで計算スタイル 3,988 件読み取り:2,929 件が一致、912 件は比較不能として明示、**上書き 0 件** |
|
|
76
98
|
| **デザイン監査** | コントラスト、フォントフォールバック、CJK の字送り、横溢れ、テキストの切れ、1 行の文字数 — ブラウザ上で実行、**指摘 26 件、すべて理由付きで裁定済み** — 理由のない容認はリリースゲートが拒否する |
|
|
77
|
-
|
|
|
78
|
-
|
|
|
99
|
+
| **コンポーネント** | コンポーネントシステムを端から端まで駆動、**8 件中 8 件**:カテゴリの下に作成、ドキュメントが自己修復、書き込み可能インスタンス経由でツリーを充填、読み取り専用インスタンスは同じ書き込みを拒否(ネガティブコントロール)、ページ上の 2 インスタンスが 1 つの定義を 2 度描画 |
|
|
100
|
+
| **スタイル状態** | 53 状態のうち 52 を実ページに書き、表が約束するセレクタと照合:**36 が完全一致**、12 NO_HOST、3 SKIPPED、1 BROKE_PAGE。擬似クラスは大文字で出力される(`.M_EL9:HOVER`) |
|
|
101
|
+
| **インタラクション** | JS アニメーション経路をネガティブコントロール付きで探査し行を読み戻し:`propertyMetas` **は**受理・保存される;プロパティ値は依然として結び付かず、その境界は正確になった |
|
|
102
|
+
| **アコーディオン** | `accordion-item` と `accordion-content` はスイープ表では BROKE_PAGE。ファクトリが要求する通りに入れ子にすれば commit も描画も通る、**7 件中 7 件** |
|
|
103
|
+
| **入場アニメーション** | 単調時計で 15 時点をサンプリングし 8 項目を断言。文書の初回レイアウトを待ってから始まるため、アニメーションの全くないページに対して遅れフレームは 1 つだけ |
|
|
104
|
+
| **常時アニメーション** | 隅で刷り続け、タップすると拡大する版 — **28 項目**:一時停止したタイムラインをスクラブして周期性を証明、5 つの幅 × 25 のスクロール位置でテキスト*と*操作要素の遮蔽を「決して読めない」を失敗条件として計測、ポインタでも Enter でも開く、reduced motion では静止 |
|
|
105
|
+
| **Elementor 変換** | 本番サイトの全 Elementor ページ — 19 ページ、3,292 要素 — を変換・構築し、元と照合:**19 件中 19 件**、3,281 要素を運び、11 要素を明示的に除外。さらに変換後ページをレスポンシブ・ブラウザ・監査にかけ、指摘をすべて「継承」か「導入」かに分類:**導入 0 件** |
|
|
106
|
+
| **テーマの書き出し/読み込み** | 経路は二つ、どちらも往復検証済み。`theme_export.php` は WP-CLI で行を JSON として移し、id は不変。`theme_zip.py` は Mosaic **自身**の ZIP 書き出し/読み込みを駆動 — 読み込みは `--activate` を付けない限りテストモードに入る、既定がライブサイトの切り替えだからだ — **22 項目**でコピーを元とツリー単位で突き合わせる |
|
|
107
|
+
| **スキル自身** | `claude plugin eval .` — ユーザーが実際に尋ねる 5 問を各 3 回、スキルあり/なしの 2 腕、1 回ごとに LLM 審査 3 名。**あり:5 問すべて 1.00。なし:5 問すべて 0.00。** ベースラインの最善の回答は回答拒否だった |
|
|
108
|
+
| **ライブ計測** | REST ルート 114、element class 151、条件サブジェクト 59、23 テーブル / 206 カラム |
|
|
109
|
+
|
|
110
|
+
`SKIPPED`、`NO_HOST`、`INCONCLUSIVE` は合格率に決して繰り込まない。自らの盲点を成功として
|
|
111
|
+
数えるスイープこそ、このスキルが反対しているものだ。
|
|
112
|
+
|
|
113
|
+
### 書く前に知っておくべき結果
|
|
114
|
+
|
|
115
|
+
**`group` に属するプロパティは単独で設定しても無効。** 両方向で厳密:グループ外の 78 個は
|
|
116
|
+
58 COMPILED・0 ABSENT、グループ内の 20 個はすべて 0 COMPILED。`borderLeftWidth`、`outlineColor`、
|
|
117
|
+
`gridColumnStart` は一つのルールの三つの例。グループの形 — `border` は `{width, style, color}` —
|
|
118
|
+
か `customStyles` を使う。
|
|
79
119
|
|
|
80
|
-
|
|
81
|
-
|
|
120
|
+
**ブレークポイントの上書きはプロパティを「変える」ことはできても「消す」ことはできない。**
|
|
121
|
+
狭い画面の `customStyles` が単にボーダーを書かないだけなら、広い画面のボーダーは立ったままだ。
|
|
122
|
+
`border-left:0` と声に出す。
|
|
82
123
|
|
|
83
|
-
|
|
124
|
+
**`url` を受け取る型は 4 つだけ**:`button`、`menu-link`、`wysiwyg-link`、`dropdown-toggle`。
|
|
125
|
+
`text` や `image` に置くと、受理され、保存され、アンカーは一切出ない。代わりに `menu-link` で
|
|
126
|
+
包む — 任意の子を取り、`url` があれば本物の `<a href>` になる。
|
|
84
127
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
`{width, style, color}` を取る)、`customStyles` に落とす。
|
|
128
|
+
**画像の attachment protocol のパスは uploads ディレクトリからの相対。**
|
|
129
|
+
`wp-attachment://image/<id>/full/2026/09/pic.png` は解決され、添付の幅と高さも乗る。フルパスの
|
|
130
|
+
`wp-content/uploads/...` を渡すと — 一番自然な推測だが — Mosaic は uploads のベースをもう一度
|
|
131
|
+
前置し、しかもエラーを出さない。
|
|
90
132
|
|
|
91
|
-
|
|
92
|
-
狭い画面の `customStyles` が単に境界線を書いていないだけなら、広い画面の境界線は生き残り、
|
|
93
|
-
1 カラムに畳まれたレイアウトの真ん中に線を引く。**`border-left:0` と明示すること。**
|
|
94
|
-
|
|
95
|
-
## ツール
|
|
133
|
+
## Elementor → Mosaic
|
|
96
134
|
|
|
97
135
|
```bash
|
|
98
|
-
wp
|
|
99
|
-
python tools/
|
|
100
|
-
|
|
101
|
-
python tools/
|
|
102
|
-
|
|
103
|
-
wp eval-file tools/theme_import.php theme.json "名前" rebind activate
|
|
136
|
+
wp post meta get 2360 _elementor_data > page.json
|
|
137
|
+
python tools/from_elementor.py --data page.json --out spec.json --report conv.csv \
|
|
138
|
+
--uploads-base https://site/wp-content/uploads --slug works --post 208
|
|
139
|
+
python tools/build_site.py --config c.json --site spec.json
|
|
140
|
+
python tools/verify_conversion.py --data page.json --url https://site/works/ --report conv.csv
|
|
104
141
|
```
|
|
105
142
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
143
|
+
対象範囲は好みではなく数えて決めた:実サイト 19 ページのうち、container / heading /
|
|
144
|
+
text-editor / button / html / icon-list / divider / image で全要素の 99.6%。ロングテール —
|
|
145
|
+
loop grid、フォーム、カウントダウン、サードパーティ addon — は動的で、なるべきノードがない。
|
|
146
|
+
それぞれ名前と理由付きで報告され、黙って落とされることはなく、`--strict` は損失のある spec の
|
|
147
|
+
出力を拒否する。
|
|
148
|
+
|
|
149
|
+
レイアウト、タイポグラフィ、色、ボーダー、リンク、画像は 3 つのブレークポイントすべてで移る
|
|
150
|
+
(`_tablet`/`_mobile` → `_t`/`_m`)。移らないもの:入場アニメーション(Mosaic のインタラクション
|
|
151
|
+
結合は未解決)、shape divider、グラデーションオーバーレイ。検証ツールは構築後のページを元と
|
|
152
|
+
突き合わせ — 文字列、画像、リンク、見出しレベルをすべて — 初回から役に立った:`url` を無視する
|
|
153
|
+
ノードに書いていたせいで 21 リンク中 19 を落としていた変換器を捕まえた。
|
|
110
154
|
|
|
111
|
-
##
|
|
155
|
+
## ツール
|
|
112
156
|
|
|
113
|
-
|
|
157
|
+
| ツール | 役割 |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `mo.py` | 計測済みの表面を引く — **正面玄関** |
|
|
160
|
+
| `build_page.py` / `build_site.py` | ガード付きの書き込み経路で spec を commit;壊れると計測されたものは拒否 |
|
|
161
|
+
| `from_elementor.py` / `verify_conversion.py` | Elementor → Mosaic と、内容が届いたことの証明 |
|
|
162
|
+
| `verify_browser.py` | ブラウザがスタイルシートの約束通りに計算したか、デザイン監査に通るか |
|
|
163
|
+
| `verify_rwd.py` | すべての `_t`/`_m` 宣言が配信スタイルシートに届いているか |
|
|
164
|
+
| `verify_intro.py` / `verify_loop.py` | 「終わる」ロードアニメーション;ループし、何も隠さず、開く常時アニメーション |
|
|
165
|
+
| `theme_export.php` / `theme_import.php` | テーマ全体を JSON 行として WP-CLI で移動、id は不変 |
|
|
166
|
+
| `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic 自身の ZIP 書き出し/読み込みをエディタの外から駆動、コピーを元とツリー単位で照合、ライブテーマを拒否する完全削除 |
|
|
167
|
+
| `sweep_*.py` / `probe_*.py` | 表を作った計測器そのもの |
|
|
168
|
+
| `bootstrap_probe_theme.php` / `mint_session.php` | ライセンス不要の実験用テーマと、WP-CLI から作る REST セッション |
|
|
169
|
+
|
|
170
|
+
## 実例、ライブで
|
|
171
|
+
|
|
172
|
+
`sites/_moksa.py` はテーブルだけで本物のスタジオサイトを構築し、参照実装として同梱される。
|
|
173
|
+
**https://mosaic.moksaweb.com/** で公開中:1,286 ノードのホームページに、名前付き view timeline
|
|
174
|
+
によるスクロール追従の条項インデックス;浮世絵の版を一枚ずつ刷っていく入場シーケンス;
|
|
175
|
+
隅で永遠に刷り続け、タップで拡大する版;そして UI 全体が shortcode を実行する 1 つの `code`
|
|
176
|
+
ノードから届く WooCommerce の [My Account](https://mosaic.moksaweb.com/my-account/) ページ。
|
|
177
|
+
自前の JavaScript はどこにもない。
|
|
178
|
+
|
|
179
|
+
## どこから始めるか
|
|
180
|
+
|
|
181
|
+
1. `references/data-model.md` — ページが実際に住んでいる場所。
|
|
114
182
|
2. `references/write-protocol.md` — checkout / check / commit。
|
|
115
|
-
3. `references/failure-modes.md` — Mosaic
|
|
116
|
-
4. `references/responsive.md` —
|
|
183
|
+
3. `references/failure-modes.md` — Mosaic の失敗のしかた、計測版。**書く前に読む。**
|
|
184
|
+
4. `references/responsive.md` — 状態/ブレークポイント/プロパティの軸。
|
|
117
185
|
5. `references/styling.md` — スタイル値が CSS になるまで。
|
|
118
186
|
6. `references/design-system.md` — element class とデザイントークン。
|
|
119
187
|
|
|
188
|
+
## リリース
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm version minor # package.json、SKILL.md、8 つのプラットフォームテンプレートの版を上げ、
|
|
192
|
+
# commit、tag、push;tag が release.yml を起動する
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`bin/check-release.mjs` がすべてのリリースを門番する。検査するのは「検査しやすいこと」ではなく
|
|
196
|
+
「間違えやすいこと」:版番号の一致、`files` の各 glob が何かに一致すること、各検証 CSV の行数が
|
|
197
|
+
SKILL.md と 4 つの README が引用する数と等しいこと、未裁定のデザイン監査指摘がないこと、eval
|
|
198
|
+
スイートが存在すること、そして **tarball そのものの検査** — npm の `files` 許可リストは
|
|
199
|
+
`.gitignore` を上書きし、かつて本物のクライアントのサイトを公開直前のパッケージに入れかけた。
|
|
200
|
+
|
|
201
|
+
公開は npm の trusted publishing(OIDC):トークンはどこにもない。npmjs.com のパッケージ設定
|
|
202
|
+
Trusted Publisher にて:GitHub Actions、`Moksa1123` / `mosaic-headless`、workflow `release.yml`、
|
|
203
|
+
environment は**空**。
|
|
204
|
+
|
|
120
205
|
## ライセンス
|
|
121
206
|
|
|
122
|
-
MIT。Mosaic Pro
|
|
207
|
+
MIT。Mosaic Pro 自体はライセンスされたサードパーティ製ソフトウェアで、ここには**含まれない**。
|
package/README.ko.md
CHANGED
|
@@ -3,122 +3,201 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
4
|
|
|
5
5
|
[Mosaic Pro](https://mosaicbuilder.com)(Nextend) 사이트를 데이터 모델에 직접 써서
|
|
6
|
-
구축하고 수정한다 — 비주얼 에디터도, DOM도 쓰지 않는다.
|
|
6
|
+
구축하고 수정한다 — 비주얼 에디터도, DOM도 쓰지 않는다. Elementor 페이지를 들여온다.
|
|
7
|
+
테마를 통째로 다른 설치로 옮긴다. 모든 주장은 실제 사이트에서 측정했다.
|
|
7
8
|
|
|
8
9
|
*다른 언어: [English](README.md) · [繁體中文](README.zh-TW.md) · [日本語](README.ja.md)*
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
`postmeta`도 아니다. 요소 하나당 한 행, 트리 구조는 `parentID` 컬럼, 형제 순서는
|
|
14
|
-
fractional-index 문자열이다. 에디터는 이 모델의 한 클라이언트일 뿐이다.
|
|
15
|
-
포맷 그 자체가 아니며, 반드시 쓸 필요도 없다.
|
|
13
|
+
## 설치
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npx mosaic-headless # 대화형: 플랫폼 선택
|
|
17
|
+
npx mosaic-headless claude-code --global # Claude Code, ~/.claude/skills/ 에
|
|
18
|
+
npx mosaic-headless cursor --to ./my-project
|
|
19
|
+
npx mosaic-headless --list # 지원하는 8개 플랫폼
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**업데이트는 저절로 되지 않는다.** npm에 새 버전이 올라가도 에이전트가 읽는 폴더는 그대로다.
|
|
23
|
+
인스톨러를 `--force`와 함께 다시 실행할 것(없으면 손댔을지 모르는 SKILL.md 덮어쓰기를 거부한다):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx mosaic-headless@latest claude-code --global --force
|
|
27
|
+
```
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
Python 3와 Playwright는 도구를 *실행*할 때 필요하고, 설치에는 필요 없다.
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
`data/`에서 찾아볼 것.**
|
|
31
|
+
## 이것은 무엇인가
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
Mosaic은 페이지를 **23개의 커스텀 테이블**에 보관한다. `post_content`도 아니고 `postmeta`도
|
|
34
|
+
아니다. 요소 하나당 한 행, 트리 구조는 `parentID` 컬럼, 형제 순서는 fractional-index 문자열이다.
|
|
35
|
+
에디터는 이 모델의 한 클라이언트일 뿐이다. 포맷 자체가 아니고, 없어도 된다.
|
|
36
|
+
|
|
37
|
+
이 스킬은 그 모델의 지도 — 소스를 읽어 얻은 것이 아니라 실제 설치에 대해 측정한 것 — 에,
|
|
38
|
+
모델을 통해 쓰고, 나온 것을 검증하고, Elementor에서 페이지를 들여오는 도구를 더한 것이다.
|
|
39
|
+
|
|
40
|
+
## 단 하나의 규칙
|
|
41
|
+
|
|
42
|
+
**노드 타입, 프로퍼티 이름, 열거값, 스타일 키, Free/Pro 판단을 기억으로 쓰지 말 것.
|
|
43
|
+
`data/`에서 찾을 것.**
|
|
44
|
+
|
|
45
|
+
그리고 grep이 아니라 `mo.py`로 찾을 것. grep은 입력한 질문에 답할 뿐, 실제로 품고 있는 질문에는
|
|
46
|
+
답하지 않는다. `accordion-content`를 grep하면 그 타입이 존재한다는 것은 알 수 있다. 스윕 표는
|
|
47
|
+
BROKE_PAGE라고 말한다 — 하나 배치하면 공개 페이지 전체가 54바이트 에러 문자열이 된다. 둘 다
|
|
48
|
+
사실이고, 둘 다 틀린 답이다. 행 옆의 메모는 그 문자열이 "부모가 없다"를 지목한다는 것,
|
|
49
|
+
`accordion > accordion-item` 아래에 중첩하면 commit도 렌더링도 되고 키보드로 조작 가능한
|
|
50
|
+
펼침 UI까지 따라온다는 것을 말한다. `mo.py type`은 그 셋을 한 번에 보여준다.
|
|
32
51
|
|
|
33
52
|
```bash
|
|
34
53
|
python tools/mo.py type accordion-content # 타입 하나를 모든 라이브 스윕과 연결해 출력
|
|
35
|
-
python tools/mo.py check div text button #
|
|
36
|
-
python tools/mo.py
|
|
37
|
-
python tools/mo.py
|
|
38
|
-
python tools/mo.py
|
|
54
|
+
python tools/mo.py check div text button # 안전하지 않거나 모르는 타입이면 1로 종료
|
|
55
|
+
python tools/mo.py params text # 타입 하나에 설정 가능한 전부
|
|
56
|
+
python tools/mo.py style --grouped # 단독으로 설정하면 무효인 20개
|
|
57
|
+
python tools/mo.py states --verified # 컴파일됨이 측정된 상태들
|
|
58
|
+
python tools/mo.py css grid-column # 이 CSS를 내는 Mosaic 키
|
|
39
59
|
```
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
|
|
61
|
+
그다음 페이지를 본다. Mosaic에는 **일곱 가지** 실패 모드가 있고, HTTP 상태 코드가 바뀌는 것은
|
|
62
|
+
그중 둘뿐이다:
|
|
43
63
|
|
|
44
64
|
```
|
|
45
|
-
검증기의
|
|
46
|
-
commit 중 PHP fatal
|
|
47
|
-
구조적으로 잘못된 노드
|
|
48
|
-
|
|
49
|
-
값의 "
|
|
50
|
-
규칙은
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
검증기의 정상적 거부 HTTP 200 + 본문에 `exceptions` 배열
|
|
66
|
+
commit 중 PHP fatal HTTP 500 (122개 타입 중 15개가 plain div 아래에서 이렇게 됨)
|
|
67
|
+
구조적으로 잘못된 노드 HTTP 200, commit됨, DB에 행 있음, 그리고 공개 페이지 전체가
|
|
68
|
+
54바이트 에러 문자열이 됨
|
|
69
|
+
값의 "형태"가 틀림 HTTP 200, 저장됨, CSS 규칙이 그냥 안 나옴
|
|
70
|
+
규칙은 맞고 결과가 틀림 HTTP 200, 스타일시트에 있고, 맞고, 브라우저가 다른 값을 계산함
|
|
71
|
+
URL에 템플릿 없음 HTTP 406, 비로그인에게는 빈 본문
|
|
72
|
+
내용으로 인한 렌더 시 fatal HTTP 500 — commit은 통과했고, Mosaic이 페이지를 파싱할 때 죽는다.
|
|
73
|
+
`code` 노드의 내용은 템플릿이라, minifier가 쓰는 `@media(`는
|
|
74
|
+
함수 호출로 읽힌다. `@media (`는 렌더링된다. build_page는
|
|
75
|
+
전자를 거부한다.
|
|
53
76
|
```
|
|
54
77
|
|
|
55
|
-
|
|
78
|
+
commit 성공은 페이지가 동작한다는 증거가 아니고, 올바른 스타일시트도 마찬가지다. 여기의 모든
|
|
79
|
+
도구는 쓴 뒤 페이지를 가져오며, 5xx를 빈 페이지로 취급한다 — WordPress의 "치명적 오류" 화면은
|
|
80
|
+
2,697바이트로, 어떤 순진한 "정상 페이지" 하한보다 크기 때문이다.
|
|
56
81
|
|
|
57
|
-
## 무엇을, 어떻게
|
|
82
|
+
## 무엇을, 어떻게 검증했나
|
|
58
83
|
|
|
59
|
-
전부 실제
|
|
60
|
-
|
|
61
|
-
|
|
84
|
+
전부 실제 설치에서 실행 — WordPress 7.1, WooCommerce 11.1, Mosaic Pro 1.0.7, **라이선스 없음**:
|
|
85
|
+
라이선스가 막는 것은 테마 라이브러리와 업데이트지 노드 팩토리가 아니라서 Pro 타입도 등록되고
|
|
86
|
+
렌더링된다.
|
|
62
87
|
|
|
63
88
|
| 항목 | 결과 |
|
|
64
89
|
|---|---|
|
|
65
|
-
| **노드 타입** | 122 / 122
|
|
66
|
-
| **스타일
|
|
67
|
-
| **노드
|
|
90
|
+
| **노드 타입** | 122 / 122를 문서당 하나씩 스윕, commit → 렌더 → 단언 → 삭제: 70 RENDERED, 30 COMMITTED, 15 COMMIT_5xx, 7 BROKE_PAGE. 렌더되지 않은 행 중 셋은 "필요한 부모 없이 commit"한 스윕 방식의 산물이며, 그 사실이 행 옆에 적혀 있다 |
|
|
91
|
+
| **스타일 프로퍼티** | 98 / 98을 실제 페이지에 쓰고 컴파일된 CSS와 대조: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
|
|
92
|
+
| **노드 프로퍼티** | 181 / 181을 각 프로퍼티 자신의 검증기 체인에서 도출한 값으로 재탐사: 35 APPLIED, 42 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
|
|
68
93
|
| **반응형** | 두 사이트 합쳐 731개의 `_t`/`_m` 선언을, 사이트가 실제로 내보낸 스타일시트에 대해 하나씩 단언 — 전부 검증됨 |
|
|
69
|
-
| **컴포넌트** | 컴포넌트 체계를 끝까지 구동해 **8 / 8**: 카테고리 아래 생성, 문서 heal, 쓰기 가능한 instance로 트리 주입, 읽기 전용 쪽은 같은 쓰기를 거부(음성 대조군), 마지막으로 인스턴스 2개가 정의 하나로 렌더링 |
|
|
70
|
-
| **스타일 상태** | 53개 상태 중 52개를 실제 페이지에 쓰고 표가 약속한 셀렉터와 대조: **36개가 정확히 일치**, 12개 NO_HOST, 3개 SKIPPED, 1개 BROKE_PAGE. 어떤 요소에나 쓸 수 있는 전역 7개 상태는 전부 검증됨 |
|
|
71
|
-
| **인터랙션** | JS 애니메이션 경로를 음성 대조군과 함께, 저장된 행을 되읽으며 검증: `propertyMetas`는 **수용되고 저장된다**. 속성 값은 여전히 바인딩되지 않지만 그 경계는 이제 정확하다 |
|
|
72
|
-
| **인트로 애니메이션** | 단조 시계로 페이지 로드 후 15개 시점을 샘플링해 8가지를 단언 — 재생될 것, 애니메이션되는 `@property` 카운터가 100에 도달할 것, 베일이 히트 테스트에서 빠질 것, 뷰포트 안에 opacity 0으로 갇힌 요소가 없을 것, 실제 클릭이 문서에 닿을 것, `prefers-reduced-motion`에서는 베일이 아예 존재하지 않을 것, 그리고 모든 것이 가라앉은 뒤에도 여전히 움직이는 것이 있을 것. 문서의 첫 레이아웃을 기다린 뒤 시작하므로, 애니메이션이 전혀 없는 페이지 대비 늦은 프레임은 하나뿐 |
|
|
73
|
-
| **상시 애니메이션** | 구석에서 계속 자기를 찍어내고 탭하면 확대되는 판 — **28개 검사**: 일시정지한 타임라인을 스크럽해 주기성 증명, 다섯 폭 × 스물다섯 스크롤 지점에서 텍스트*와* 컨트롤의 가림을 "결코 읽을 수 없음"을 실패 조건으로 측정, 포인터와 Enter 양쪽으로 열림, reduced motion에서는 정지. Mosaic 자체 아코디언 위에 구축 |
|
|
74
|
-
| **아코디언** | `accordion-item`과 `accordion-content`는 스윕 표에서 BROKE_PAGE. 팩토리가 요구하는 대로 중첩하면 commit과 렌더링이 되며, **7건 중 7건**. 메모는 이제 그 행 옆에 있다 |
|
|
75
94
|
| **브라우저** | 전달된 두 페이지를 Chromium의 세 가지 뷰포트에서 계산 스타일 3,988건 판독: 2,929건 일치, 912건은 비교 불가로 명시, **덮어쓰기 0건** |
|
|
76
95
|
| **디자인 감사** | 명암비, 폰트 폴백, CJK 자간, 가로 넘침, 텍스트 잘림, 한 줄 글자 수 — 브라우저에서 실행, **지적 26건, 모두 서면으로 판정** — 이유 없는 승인은 릴리스 게이트가 거부한다 |
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
| **컴포넌트** | 컴포넌트 시스템을 끝에서 끝까지 구동, **8건 중 8건**: 카테고리 아래 생성, 문서 자가 치유, 쓰기 가능 인스턴스로 트리 채움, 읽기 전용 인스턴스는 같은 쓰기를 거부(네거티브 컨트롤), 페이지의 두 인스턴스가 하나의 정의를 두 번 렌더 |
|
|
97
|
+
| **스타일 상태** | 53개 상태 중 52개를 실제 페이지에 쓰고 표가 약속한 셀렉터와 대조: **36개 정확히 일치**, 12 NO_HOST, 3 SKIPPED, 1 BROKE_PAGE. 의사 클래스는 대문자로 출력된다(`.M_EL9:HOVER`) |
|
|
98
|
+
| **인터랙션** | JS 애니메이션 경로를 네거티브 컨트롤과 함께 탐사하고 행을 읽어 되돌림: `propertyMetas`**는** 수락·저장된다; 프로퍼티 값은 여전히 바인딩되지 않으며, 그 경계는 이제 정확하다 |
|
|
99
|
+
| **아코디언** | `accordion-item`과 `accordion-content`는 스윕 표에서 BROKE_PAGE. 팩토리가 요구하는 대로 중첩하면 commit과 렌더링이 되며, **7건 중 7건** |
|
|
100
|
+
| **인트로 애니메이션** | 단조 시계로 15개 시점을 샘플링해 8가지를 단언. 문서의 첫 레이아웃을 기다린 뒤 시작하므로, 애니메이션이 전혀 없는 페이지 대비 늦은 프레임은 하나뿐 |
|
|
101
|
+
| **상시 애니메이션** | 구석에서 계속 자기를 찍어내고 탭하면 확대되는 판 — **28개 검사**: 일시정지한 타임라인을 스크럽해 주기성 증명, 다섯 폭 × 스물다섯 스크롤 지점에서 텍스트*와* 컨트롤의 가림을 "결코 읽을 수 없음"을 실패 조건으로 측정, 포인터와 Enter 양쪽으로 열림, reduced motion에서는 정지 |
|
|
102
|
+
| **Elementor 변환** | 운영 사이트의 모든 Elementor 페이지 — 19페이지, 3,292 요소 — 를 변환·구축하고 원본과 대조: **19건 중 19건**, 3,281 요소 이전, 11 요소 명시적 제외. 이어 변환된 페이지를 반응형·브라우저·감사에 통과시키고 모든 지적을 "상속"과 "도입"으로 분류: **도입 0건** |
|
|
103
|
+
| **테마 내보내기/가져오기** | 두 경로, 모두 왕복 검증. `theme_export.php`는 WP-CLI로 행을 JSON으로 옮기며 id는 그대로. `theme_zip.py`는 Mosaic **자체**의 ZIP 내보내기/가져오기를 구동 — 가져오기는 `--activate`가 없으면 테스트 모드에 놓이는데, 기본값이 라이브 사이트 전환이기 때문이다 — **22개 검사**로 사본을 원본과 트리 단위로 대조 |
|
|
104
|
+
| **스킬 자체** | `claude plugin eval .` — 사용자가 실제로 묻는 5문항을 각 3회, 스킬 있음/없음 두 팔로, 매회 LLM 심사 3명. **있음: 5문항 모두 1.00. 없음: 5문항 모두 0.00.** 베이스라인의 최선은 답변 거부였다 |
|
|
105
|
+
| **라이브 측정** | REST 라우트 114, element class 151, 조건 subject 59, 23 테이블 / 206 컬럼 |
|
|
106
|
+
|
|
107
|
+
`SKIPPED`, `NO_HOST`, `INCONCLUSIVE`는 결코 합격률에 섞지 않는다. 자기 사각지대를 성공으로
|
|
108
|
+
세는 스윕이야말로 이 스킬이 반대하는 것이다.
|
|
109
|
+
|
|
110
|
+
### 쓰기 전에 알아둘 결과
|
|
111
|
+
|
|
112
|
+
**`group`에 속한 프로퍼티는 단독으로 설정하면 무효다.** 양방향 모두 정확: 그룹 밖 78개는
|
|
113
|
+
58 COMPILED·0 ABSENT, 그룹 안 20개는 모두 0 COMPILED. `borderLeftWidth`, `outlineColor`,
|
|
114
|
+
`gridColumnStart`는 한 규칙의 세 사례다. 그룹 형태 — `border`는 `{width, style, color}` — 나
|
|
115
|
+
`customStyles`를 쓸 것.
|
|
116
|
+
|
|
117
|
+
**브레이크포인트 오버라이드는 프로퍼티를 "바꿀" 수는 있어도 "지울" 수는 없다.** 좁은 화면의
|
|
118
|
+
`customStyles`가 테두리를 그저 언급하지 않으면, 넓은 화면의 테두리는 그대로 서 있다.
|
|
119
|
+
`border-left:0`을 소리 내어 말할 것.
|
|
120
|
+
|
|
121
|
+
**`url`을 받는 타입은 넷뿐**: `button`, `menu-link`, `wysiwyg-link`, `dropdown-toggle`.
|
|
122
|
+
`text`나 `image`에 두면 수락되고, 저장되고, 앵커는 전혀 나오지 않는다. 대신 `menu-link`로
|
|
123
|
+
감쌀 것 — 어떤 자식이든 받고, `url`이 있으면 진짜 `<a href>`가 된다.
|
|
124
|
+
|
|
125
|
+
**이미지의 attachment protocol 경로는 uploads 디렉터리 기준 상대 경로다.**
|
|
126
|
+
`wp-attachment://image/<id>/full/2026/09/pic.png`는 해석되고 첨부의 가로·세로도 붙는다.
|
|
127
|
+
전체 경로 `wp-content/uploads/...`를 주면 — 가장 자연스러운 추측이지만 — Mosaic이 uploads
|
|
128
|
+
베이스를 한 번 더 앞에 붙이고, 에러도 내지 않는다.
|
|
129
|
+
|
|
130
|
+
## Elementor → Mosaic
|
|
82
131
|
|
|
83
|
-
|
|
132
|
+
```bash
|
|
133
|
+
wp post meta get 2360 _elementor_data > page.json
|
|
134
|
+
python tools/from_elementor.py --data page.json --out spec.json --report conv.csv \
|
|
135
|
+
--uploads-base https://site/wp-content/uploads --slug works --post 208
|
|
136
|
+
python tools/build_site.py --config c.json --site spec.json
|
|
137
|
+
python tools/verify_conversion.py --data page.json --url https://site/works/ --report conv.csv
|
|
138
|
+
```
|
|
84
139
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`{width, style, color}`를 받는다) `customStyles`로 내려간다.
|
|
140
|
+
범위는 취향이 아니라 세어서 정했다: 실제 사이트 19페이지에서 container / heading /
|
|
141
|
+
text-editor / button / html / icon-list / divider / image가 전체 요소의 99.6%다. 롱테일 —
|
|
142
|
+
loop grid, 폼, 카운트다운, 서드파티 addon — 은 동적이라 될 노드가 없다. 각각 이름과 이유와
|
|
143
|
+
함께 보고되며 조용히 버려지지 않고, `--strict`는 손실 있는 spec 출력을 거부한다.
|
|
90
144
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
145
|
+
레이아웃, 타이포그래피, 색, 테두리, 링크, 이미지가 세 브레이크포인트 모두에서 넘어간다
|
|
146
|
+
(`_tablet`/`_mobile` → `_t`/`_m`). 넘어가지 않는 것: 진입 애니메이션(Mosaic의 인터랙션
|
|
147
|
+
바인딩은 미해결), shape divider, 그라데이션 오버레이. 검증기는 구축된 페이지를 원본과
|
|
148
|
+
대조하며 — 모든 문자열, 이미지, 링크, 제목 레벨 — 첫 회부터 제 몫을 했다: `url`을 무시하는
|
|
149
|
+
노드에 써서 21개 링크 중 19개를 잃던 변환기를 잡아냈다.
|
|
95
150
|
|
|
96
151
|
## 도구
|
|
97
152
|
|
|
153
|
+
| 도구 | 역할 |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `mo.py` | 측정된 표면을 조회 — **정문** |
|
|
156
|
+
| `build_page.py` / `build_site.py` | 가드된 쓰기 경로로 spec을 commit; 깨진다고 측정된 것은 거부 |
|
|
157
|
+
| `from_elementor.py` / `verify_conversion.py` | Elementor → Mosaic, 그리고 내용이 도착했다는 증명 |
|
|
158
|
+
| `verify_browser.py` | 브라우저가 스타일시트의 약속대로 계산했는지, 디자인 감사를 통과하는지 |
|
|
159
|
+
| `verify_rwd.py` | 모든 `_t`/`_m` 선언이 전달된 스타일시트에 도달하는지 |
|
|
160
|
+
| `verify_intro.py` / `verify_loop.py` | "끝나는" 로드 애니메이션; 루프하고, 아무것도 가리지 않고, 열리는 상시 애니메이션 |
|
|
161
|
+
| `theme_export.php` / `theme_import.php` | 테마 전체를 JSON 행으로 WP-CLI를 통해 이동, id 그대로 |
|
|
162
|
+
| `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic 자체 ZIP 내보내기/가져오기를 에디터 밖에서 구동, 사본을 원본과 트리 단위로 대조, 라이브 테마를 거부하는 깨끗한 삭제 |
|
|
163
|
+
| `sweep_*.py` / `probe_*.py` | 표를 만든 계측기 그 자체 |
|
|
164
|
+
| `bootstrap_probe_theme.php` / `mint_session.php` | 라이선스 없는 실험용 테마와 WP-CLI에서 만드는 REST 세션 |
|
|
165
|
+
|
|
166
|
+
## 실제 예제, 라이브로
|
|
167
|
+
|
|
168
|
+
`sites/_moksa.py`는 테이블만으로 진짜 스튜디오 사이트를 구축하며 참조 구현으로 동봉된다.
|
|
169
|
+
**https://mosaic.moksaweb.com/** 에 올라가 있다: 1,286 노드의 홈페이지에 이름 있는 view
|
|
170
|
+
timeline으로 스크롤을 추적하는 조항 인덱스; 우키요에 판을 한 장씩 찍어내는 진입 시퀀스;
|
|
171
|
+
구석에서 영원히 찍어내고 탭하면 확대되는 판; 그리고 UI 전체가 shortcode를 실행하는 하나의
|
|
172
|
+
`code` 노드로 들어오는 WooCommerce [My Account](https://mosaic.moksaweb.com/my-account/)
|
|
173
|
+
페이지. 자체 JavaScript는 어디에도 없다.
|
|
174
|
+
|
|
175
|
+
## 어디서 시작할까
|
|
176
|
+
|
|
177
|
+
1. `references/data-model.md` — 페이지가 실제로 사는 곳.
|
|
178
|
+
2. `references/write-protocol.md` — checkout / check / commit.
|
|
179
|
+
3. `references/failure-modes.md` — Mosaic이 실패하는 방식, 측정판. **쓰기 전에 읽을 것.**
|
|
180
|
+
4. `references/responsive.md` — 상태/브레이크포인트/프로퍼티 축.
|
|
181
|
+
5. `references/styling.md` — 스타일 값이 CSS가 되기까지.
|
|
182
|
+
6. `references/design-system.md` — element class와 디자인 토큰.
|
|
183
|
+
|
|
184
|
+
## 릴리스
|
|
185
|
+
|
|
98
186
|
```bash
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
python tools/verify_rwd.py --config c.json --site sites/moksa.json --csv rwd.csv
|
|
102
|
-
python tools/copy_styles.py --config c.json --from a --to-prefix b- --only "&._m"
|
|
103
|
-
wp eval-file tools/theme_export.php active > theme.json
|
|
104
|
-
wp eval-file tools/theme_import.php theme.json "이름" rebind activate
|
|
187
|
+
npm version minor # package.json, SKILL.md, 8개 플랫폼 템플릿의 버전을 올리고
|
|
188
|
+
# commit, tag, push; tag가 release.yml을 트리거
|
|
105
189
|
```
|
|
106
190
|
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
## 어디부터 읽을 것인가
|
|
191
|
+
`bin/check-release.mjs`가 모든 릴리스를 지킨다. 검사하는 것은 "검사하기 쉬운 것"이 아니라
|
|
192
|
+
"틀리기 쉬운 것": 버전 번호 일치, `files`의 각 glob이 무언가와 매칭, 각 검증 CSV의 행 수가
|
|
193
|
+
SKILL.md와 네 README가 인용하는 수와 같음, 판정되지 않은 디자인 감사 지적 없음, eval 스위트
|
|
194
|
+
존재, 그리고 **tarball 자체 검사** — npm의 `files` 허용 목록은 `.gitignore`를 덮어쓰며, 한때
|
|
195
|
+
실제 고객의 사이트를 게시 직전의 패키지에 넣을 뻔했다.
|
|
113
196
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
4. `references/responsive.md` — state / breakpoint / property 축.
|
|
118
|
-
5. `references/styling.md` — 스타일 값이 CSS가 되기까지.
|
|
119
|
-
6. `references/design-system.md` — element class와 디자인 토큰.
|
|
197
|
+
게시는 npm trusted publishing(OIDC)으로: 토큰은 어디에도 없다. npmjs.com 패키지 설정의
|
|
198
|
+
Trusted Publisher: GitHub Actions, `Moksa1123` / `mosaic-headless`, workflow `release.yml`,
|
|
199
|
+
environment는 **비움**.
|
|
120
200
|
|
|
121
201
|
## 라이선스
|
|
122
202
|
|
|
123
|
-
MIT. Mosaic Pro 자체는
|
|
124
|
-
**포함되어 있지 않다**.
|
|
203
|
+
MIT. Mosaic Pro 자체는 라이선스된 서드파티 소프트웨어이며 여기에 **포함되지 않는다**.
|
package/README.md
CHANGED
|
@@ -3,19 +3,42 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
4
|
|
|
5
5
|
Build and modify [Mosaic Pro](https://mosaicbuilder.com) (Nextend) sites by writing
|
|
6
|
-
the data model directly — no visual editor, no DOM.
|
|
6
|
+
the data model directly — no visual editor, no DOM. Convert Elementor pages into it.
|
|
7
|
+
Move whole themes between installs. Every claim measured on a live site.
|
|
7
8
|
|
|
8
9
|
*Read this in [繁體中文](README.zh-TW.md) · [日本語](README.ja.md) · [한국어](README.ko.md)*
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx mosaic-headless # interactive: pick a platform
|
|
17
|
+
npx mosaic-headless claude-code --global # Claude Code, into ~/.claude/skills/
|
|
18
|
+
npx mosaic-headless cursor --to ./my-project
|
|
19
|
+
npx mosaic-headless --list # all eight platforms
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Updating does not happen on its own.** A new version on npm changes nothing in
|
|
23
|
+
the folder your agent loads; re-run the installer with `--force` (without it, it
|
|
24
|
+
refuses to overwrite a SKILL.md you may have edited):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx mosaic-headless@latest claude-code --global --force
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Python 3 and Playwright are needed to *run* the tools, not to install.
|
|
31
|
+
|
|
32
|
+
## What this is
|
|
33
|
+
|
|
12
34
|
Mosaic keeps a page in **23 custom database tables**, not in `post_content` and not
|
|
13
35
|
in `postmeta`. One row per element, the tree carried by a `parentID` column, sibling
|
|
14
36
|
order by a fractional-index string. The editor is one client of that model. It is not
|
|
15
37
|
the format, and you do not need it.
|
|
16
38
|
|
|
17
39
|
This skill is the map of that model — measured against a live install rather than
|
|
18
|
-
read off the source
|
|
40
|
+
read off the source — plus the tools to write through it, check what came out, and
|
|
41
|
+
bring pages in from Elementor.
|
|
19
42
|
|
|
20
43
|
## The one rule
|
|
21
44
|
|
|
@@ -33,13 +56,14 @@ keyboard-operable disclosure. `mo.py type` shows all three at once.
|
|
|
33
56
|
```bash
|
|
34
57
|
python tools/mo.py type accordion-content # one type, joined to every live sweep
|
|
35
58
|
python tools/mo.py check div text button # exits 1 on an unsafe or unknown type
|
|
59
|
+
python tools/mo.py params text # everything settable on one type
|
|
36
60
|
python tools/mo.py style --grouped # the 20 that are inert set on their own
|
|
37
61
|
python tools/mo.py states --verified # the states measured to compile
|
|
38
|
-
python tools/mo.py
|
|
62
|
+
python tools/mo.py css grid-column # which Mosaic key drives this CSS
|
|
39
63
|
```
|
|
40
64
|
|
|
41
|
-
Then check the page. Mosaic has
|
|
42
|
-
HTTP status code
|
|
65
|
+
Then check the page. Mosaic has **seven** failure modes and only two of them change
|
|
66
|
+
the HTTP status code:
|
|
43
67
|
|
|
44
68
|
```
|
|
45
69
|
clean validator rejection HTTP 200 + an `exceptions` array in the body
|
|
@@ -50,10 +74,17 @@ wrong value SHAPE HTTP 200, stored, and the CSS rule is simply absent
|
|
|
50
74
|
right rule, wrong result HTTP 200, in the stylesheet, correct, and the BROWSER
|
|
51
75
|
computes something else
|
|
52
76
|
no template for the URL HTTP 406 with an EMPTY BODY for anyone not logged in
|
|
77
|
+
render-time fatal from HTTP 500 - the commit went through, the page dies when
|
|
78
|
+
CONTENT Mosaic parses it. A `code` node's content is a template:
|
|
79
|
+
`@media(` as every minifier writes it is read as a
|
|
80
|
+
function call. `@media (` renders. build_page refuses
|
|
81
|
+
the former.
|
|
53
82
|
```
|
|
54
83
|
|
|
55
84
|
A successful commit is not evidence of a working page, and neither is a correct
|
|
56
|
-
stylesheet.
|
|
85
|
+
stylesheet. Every tool here fetches the page afterwards — and treats a 5xx as an
|
|
86
|
+
empty page, because WordPress's "critical error" screen is 2,697 bytes and larger
|
|
87
|
+
than any naive healthy-page floor.
|
|
57
88
|
|
|
58
89
|
## What was verified, and how
|
|
59
90
|
|
|
@@ -63,25 +94,27 @@ factories, so Pro types register and render regardless.
|
|
|
63
94
|
|
|
64
95
|
| pass | result |
|
|
65
96
|
|---|---|
|
|
66
|
-
| **node types** | 122 / 122 swept one per document, committed → rendered → asserted → deleted: 70 RENDERED, 30 COMMITTED, 15 COMMIT_5xx, 7 BROKE_PAGE |
|
|
97
|
+
| **node types** | 122 / 122 swept one per document, committed → rendered → asserted → deleted: 70 RENDERED, 30 COMMITTED, 15 COMMIT_5xx, 7 BROKE_PAGE. Three of the non-rendering rows are artefacts of committing without the required parent, and say so beside the row |
|
|
67
98
|
| **style properties** | 98 / 98 written to a live page and checked against the compiled CSS: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
|
|
68
99
|
| **node properties** | 181 / 181 re-probed with a value shaped by each property's own validator chain: 35 APPLIED, 42 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
|
|
69
100
|
| **responsive** | 731 `_t`/`_m` declarations across two sites asserted against the stylesheet the site actually served — all verified |
|
|
70
|
-
| **components** | the component system driven end to end, **8 of 8**: created under a category, document healed, tree filled through the writable instance, the read-only one refused the same write as a negative control, and two instances on a page rendering one definition twice |
|
|
71
|
-
| **style states** | 52 of the 53 states written to a live page and matched against the selector the table promises: **36 compiled exactly**, 12 NO_HOST, 3 SKIPPED, 1 BROKE_PAGE. All seven globally usable states verified |
|
|
72
|
-
| **interactions** | the JS animation path probed with negative controls and the row read back: `propertyMetas` **is** accepted and stored; the property values still do not bind, and the boundary is now exact |
|
|
73
|
-
| **entrance animation** | the page-load sequence sampled at fifteen timestamps on a monotonic clock and asserted on eight counts — it plays, its animated `@property` counter reaches 100, the veil leaves hit-testing, nothing in the viewport is stranded at opacity 0, a real click reaches the document, under `prefers-reduced-motion` the veil never exists, and something is still moving once everything has settled. Costs one late frame over a page with no animation at all, because it waits for the document's first layout |
|
|
74
|
-
| **perpetual animation** | a corner plate that keeps printing itself and opens to full size when tapped, **28 checks**: periodicity proved by scrubbing a paused timeline, occlusion of text *and* controls at five widths and twenty-five scroll stops with "never readable" as the failing condition, opened by pointer and by Enter, still under reduced motion. Built on Mosaic's own accordion |
|
|
75
|
-
| **accordion** | `accordion-item` and `accordion-content` sit in the sweep table as BROKE_PAGE; nested as their factory requires they commit and render, **7 of 7**. The note now lives beside the row |
|
|
76
101
|
| **browser** | 3,988 computed-style readings on two delivered pages in Chromium at three viewports: 2,929 compared and agreed, 912 not-comparable and labelled, **0 overridden** |
|
|
77
102
|
| **design audit** | contrast, font fallback, CJK tracking, overflow, clipped text, line measure — run in the browser, **26 findings, every one ruled on in writing** — an acknowledgement without a reason is refused by the release gate |
|
|
78
|
-
| **
|
|
103
|
+
| **components** | the component system driven end to end, **8 of 8**: created under a category, document healed, tree filled through the writable instance, the read-only one refused the same write as a negative control, two instances on a page rendering one definition twice |
|
|
104
|
+
| **style states** | 52 of the 53 states written to a live page and matched against the selector the table promises: **36 compiled exactly**, 12 NO_HOST, 3 SKIPPED, 1 BROKE_PAGE. Pseudo-classes are emitted UPPERCASE (`.M_EL9:HOVER`) |
|
|
105
|
+
| **interactions** | the JS animation path probed with negative controls and the row read back: `propertyMetas` **is** accepted and stored; the property values still do not bind, and the boundary is now exact |
|
|
106
|
+
| **accordion** | `accordion-item` and `accordion-content` sit in the sweep table as BROKE_PAGE; nested as their factory requires they commit and render, **7 of 7** |
|
|
107
|
+
| **entrance animation** | the page-load sequence sampled at fifteen timestamps on a monotonic clock and asserted on eight counts. Costs one late frame over a page with no animation at all, because it waits for the document's first layout |
|
|
108
|
+
| **perpetual animation** | a corner plate that keeps printing itself and opens to full size when tapped, **28 checks**: periodicity by scrubbing a paused timeline, occlusion of text *and* controls at five widths and twenty-five scroll stops with "never readable" as the failing condition, opened by pointer and by Enter, still under reduced motion |
|
|
109
|
+
| **Elementor conversion** | every Elementor page of a production site — 19 pages, 3,292 elements — converted, built and checked against its source: **19 of 19**, 3,281 elements carried, 11 declared. Then the converted page through rwd, browser and the audit, with every finding classified inherited-or-introduced: **0 introduced** |
|
|
110
|
+
| **theme export/import** | two paths, both round-tripped. `theme_export.php` moves rows as JSON over WP-CLI, ids intact. `theme_zip.py` drives Mosaic's **own** ZIP export/import — import lands in test mode unless told `--activate`, because the default is to switch the live site — and **22 checks** hold the copy against the source tree for tree |
|
|
111
|
+
| **the skill itself** | `claude plugin eval .` — five cases a user would ask, three runs each, with and without the skill loaded, three LLM judges a run. **With: 1.00 on all five. Without: 0.00 on all five.** The baseline's best answer was to refuse |
|
|
79
112
|
| **measured live** | 114 REST routes, 151 element classes, 59 condition subjects, 23 tables / 206 columns |
|
|
80
113
|
|
|
81
114
|
`SKIPPED`, `NO_HOST` and `INCONCLUSIVE` are never folded into a pass rate. A sweep
|
|
82
115
|
that scores its own blind spots as successes is the thing this skill argues against.
|
|
83
116
|
|
|
84
|
-
###
|
|
117
|
+
### Results worth knowing before you write anything
|
|
85
118
|
|
|
86
119
|
**A property that belongs to a `group` is inert when set on its own.** Exact in both
|
|
87
120
|
directions: 78 ungrouped properties gave 58 COMPILED and 0 ABSENT; all 20 grouped
|
|
@@ -90,24 +123,66 @@ three instances of one rule, not three oddities. Use the grouped shape — `bord
|
|
|
90
123
|
takes `{width, style, color}` — or `customStyles`.
|
|
91
124
|
|
|
92
125
|
**A breakpoint override can CHANGE a property but never REMOVE one.** Narrow-screen
|
|
93
|
-
`customStyles` that merely omits a border leaves the wide-screen border standing
|
|
94
|
-
|
|
126
|
+
`customStyles` that merely omits a border leaves the wide-screen border standing.
|
|
127
|
+
Say `border-left:0` out loud.
|
|
95
128
|
|
|
96
|
-
|
|
129
|
+
**Only four types take a `url`**: `button`, `menu-link`, `wysiwyg-link`,
|
|
130
|
+
`dropdown-toggle`. On a `text` or an `image` it is accepted, stored, and emits no
|
|
131
|
+
anchor. Wrap the thing in a `menu-link` instead — it takes any children and becomes
|
|
132
|
+
a real `<a href>`.
|
|
133
|
+
|
|
134
|
+
**An image's attachment-protocol path is relative to the uploads directory.**
|
|
135
|
+
`wp-attachment://image/<id>/full/2026/09/pic.png` resolves and carries the
|
|
136
|
+
attachment's width and height. Give it the full `wp-content/uploads/...` path — the
|
|
137
|
+
obvious guess — and Mosaic prefixes the uploads base a second time, silently.
|
|
138
|
+
|
|
139
|
+
## Elementor → Mosaic
|
|
97
140
|
|
|
98
141
|
```bash
|
|
99
|
-
wp
|
|
100
|
-
python tools/
|
|
101
|
-
|
|
102
|
-
python tools/
|
|
103
|
-
|
|
104
|
-
wp eval-file tools/theme_import.php theme.json "Name" rebind activate
|
|
142
|
+
wp post meta get 2360 _elementor_data > page.json
|
|
143
|
+
python tools/from_elementor.py --data page.json --out spec.json --report conv.csv \
|
|
144
|
+
--uploads-base https://site/wp-content/uploads --slug works --post 208
|
|
145
|
+
python tools/build_site.py --config c.json --site spec.json
|
|
146
|
+
python tools/verify_conversion.py --data page.json --url https://site/works/ --report conv.csv
|
|
105
147
|
```
|
|
106
148
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
149
|
+
Scope was decided by counting, not by taste: across a real site's 19 pages,
|
|
150
|
+
container / heading / text-editor / button / html / icon-list / divider / image are
|
|
151
|
+
99.6% of every element present. The long tail — loop grids, forms, countdowns,
|
|
152
|
+
third-party addons — is dynamic and has no node to become; each is reported by
|
|
153
|
+
name and reason, never dropped, and `--strict` refuses to write a lossy spec.
|
|
154
|
+
|
|
155
|
+
Layout, typography, colour, borders, links and images cross over, at all three
|
|
156
|
+
breakpoints (`_tablet`/`_mobile` → `_t`/`_m`). What does not: entrance animations
|
|
157
|
+
(Mosaic's interaction binding is unsolved), shape dividers, gradient overlays. The
|
|
158
|
+
verifier then holds the built page against the source — every string, image, link
|
|
159
|
+
and heading level — and it earned its place at once: it caught the converter losing
|
|
160
|
+
19 of 21 links by writing `url` onto nodes that ignore it.
|
|
161
|
+
|
|
162
|
+
## Tools
|
|
163
|
+
|
|
164
|
+
| tool | does |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `mo.py` | query the measured surface — **the front door** |
|
|
167
|
+
| `build_page.py` / `build_site.py` | commit a spec through the guarded write path; refuses what is measured to break |
|
|
168
|
+
| `from_elementor.py` / `verify_conversion.py` | Elementor → Mosaic, and proof the content arrived |
|
|
169
|
+
| `verify_browser.py` | does the browser compute what the stylesheet promised, and does it pass a design audit |
|
|
170
|
+
| `verify_rwd.py` | does every `_t`/`_m` declaration reach the served stylesheet |
|
|
171
|
+
| `verify_intro.py` / `verify_loop.py` | a page-load sequence that ENDS; a perpetual one that loops, hides nothing, and opens |
|
|
172
|
+
| `theme_export.php` / `theme_import.php` | a whole theme as JSON rows over WP-CLI, ids intact |
|
|
173
|
+
| `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic's own ZIP export/import from outside the editor, the copy held against the source, and a clean delete that refuses the live theme |
|
|
174
|
+
| `sweep_*.py` / `probe_*.py` | the instruments the tables were made with |
|
|
175
|
+
| `bootstrap_probe_theme.php` / `mint_session.php` | a licence-free scratch theme and a REST session from WP-CLI |
|
|
176
|
+
|
|
177
|
+
## The worked example, live
|
|
178
|
+
|
|
179
|
+
`sites/_moksa.py` builds a real studio site through the tables alone and ships as
|
|
180
|
+
the reference. It is up at **https://mosaic.moksaweb.com/**: a homepage of 1,286
|
|
181
|
+
nodes with a scroll-tracking clause index on named view timelines, an entrance
|
|
182
|
+
sequence that prints an ukiyo-e sheet one carved block at a time, a corner plate
|
|
183
|
+
that keeps printing forever and opens when tapped, and a WooCommerce
|
|
184
|
+
[My Account](https://mosaic.moksaweb.com/my-account/) page whose UI arrives through
|
|
185
|
+
one `code` node running a shortcode. No JavaScript of its own anywhere.
|
|
111
186
|
|
|
112
187
|
## Where to start
|
|
113
188
|
|
|
@@ -120,51 +195,21 @@ clause index built on named view timelines and no JavaScript.
|
|
|
120
195
|
|
|
121
196
|
## Releasing
|
|
122
197
|
|
|
123
|
-
One command. The version lives in three places — `package.json`, the SKILL.md
|
|
124
|
-
frontmatter an agent reads, and the frontmatter each platform template writes on
|
|
125
|
-
install — and nothing keeps them together on its own.
|
|
126
|
-
|
|
127
198
|
```bash
|
|
128
|
-
npm version
|
|
199
|
+
npm version minor # bumps package.json, SKILL.md and eight platform templates,
|
|
200
|
+
# commits, tags, pushes; the tag triggers release.yml
|
|
129
201
|
```
|
|
130
202
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
unless the tag matches `package.json`, re-runs the release checks, proves the
|
|
142
|
-
installer runs, prints the tarball, then publishes with provenance and opens a
|
|
143
|
-
GitHub release.
|
|
144
|
-
|
|
145
|
-
`bin/check-release.mjs` is the gate, and it checks the things that are easy to get
|
|
146
|
-
wrong rather than the things that are easy to check:
|
|
147
|
-
|
|
148
|
-
- the three version numbers agree
|
|
149
|
-
- every glob in `files` matches something
|
|
150
|
-
- the row counts in the verification CSVs still equal the numbers SKILL.md quotes
|
|
151
|
-
- `SKIPPED` labels survive into the shipped data, because a sweep that hides its
|
|
152
|
-
blind spots is the failure this skill argues against
|
|
153
|
-
- **the tarball itself is inspected**, not the intent. npm's `files` allowlist
|
|
154
|
-
*overrides* `.gitignore`: naming a directory ships everything inside it, ignored
|
|
155
|
-
or not. Listing `sites/` once put a real client's generator and content into the
|
|
156
|
-
tarball — gitignored, and about to be published anyway.
|
|
157
|
-
|
|
158
|
-
Publishing runs on npm trusted publishing (OIDC): npm trusts this repository's
|
|
159
|
-
`release.yml` directly, so there is no token in the repository's secrets and
|
|
160
|
-
nothing to rotate. Provenance is attached automatically.
|
|
161
|
-
|
|
162
|
-
One-time setup, on npmjs.com under the package's Settings → Trusted Publisher:
|
|
163
|
-
publisher `GitHub Actions`, organisation `Moksa1123`, repository
|
|
164
|
-
`mosaic-headless`, workflow filename `release.yml`, environment name left
|
|
165
|
-
**empty** — the workflow declares no environment, and a value here that the run
|
|
166
|
-
does not match is refused. The connection cannot be edited afterwards, only
|
|
167
|
-
deleted and recreated.
|
|
203
|
+
`bin/check-release.mjs` gates every release on the things that are easy to get
|
|
204
|
+
wrong: the version numbers agree, every `files` glob matches, every verification
|
|
205
|
+
CSV still has the row count SKILL.md and the four READMEs quote, no design-audit
|
|
206
|
+
finding is unreviewed, the eval suite is present, and **the tarball itself is
|
|
207
|
+
inspected** — npm's `files` allowlist overrides `.gitignore`, and once put a real
|
|
208
|
+
client's site into a package that was about to publish.
|
|
209
|
+
|
|
210
|
+
Publishing runs on npm trusted publishing (OIDC): no token anywhere. Setup on
|
|
211
|
+
npmjs.com under the package's Trusted Publisher: GitHub Actions, `Moksa1123` /
|
|
212
|
+
`mosaic-headless`, workflow `release.yml`, environment **empty**.
|
|
168
213
|
|
|
169
214
|
## Licence
|
|
170
215
|
|
package/README.zh-TW.md
CHANGED
|
@@ -3,110 +3,189 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/mosaic-headless)
|
|
4
4
|
|
|
5
5
|
直接寫入資料模型來建置與修改 [Mosaic Pro](https://mosaicbuilder.com)(Nextend)網站——
|
|
6
|
-
不開視覺編輯器,不碰 DOM
|
|
6
|
+
不開視覺編輯器,不碰 DOM。把 Elementor 頁面轉進來。把整個主題搬到另一個站。
|
|
7
|
+
每一項宣稱都在真實站台上量過。
|
|
7
8
|
|
|
8
9
|
*其他語言:[English](README.md) · [日本語](README.ja.md) · [한국어](README.ko.md)*
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
13
|
+
## 安裝
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx mosaic-headless # 互動式:選平台
|
|
17
|
+
npx mosaic-headless claude-code --global # Claude Code,裝到 ~/.claude/skills/
|
|
18
|
+
npx mosaic-headless cursor --to ./my-project
|
|
19
|
+
npx mosaic-headless --list # 全部八個平台
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**更新不會自己發生。** npm 上有新版,不代表你的 agent 載入的那個資料夾有變;要重跑安裝器並加
|
|
23
|
+
`--force`(不加的話它會拒絕覆蓋你可能改過的 SKILL.md):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx mosaic-headless@latest claude-code --global --force
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Python 3 和 Playwright 是*跑工具*時才需要,安裝不用。
|
|
30
|
+
|
|
31
|
+
## 這是什麼
|
|
32
|
+
|
|
12
33
|
Mosaic 把一個頁面放在 **23 張自訂資料表**裡,不在 `post_content`,也不在 `postmeta`。
|
|
13
34
|
一個元素一列,樹狀結構靠 `parentID` 欄位,同層順序是一個 fractional-index 字串。
|
|
14
35
|
編輯器只是這個模型的其中一個客戶端。它不是格式本身,而且你不需要它。
|
|
15
36
|
|
|
16
|
-
|
|
37
|
+
這個技能就是那個模型的地圖——對照真實站台量出來的,不是讀原始碼讀出來的——外加一組
|
|
38
|
+
工具:透過模型寫入、檢查寫出來的東西、把 Elementor 的頁面搬進來。
|
|
17
39
|
|
|
18
|
-
##
|
|
40
|
+
## 唯一的規則
|
|
19
41
|
|
|
20
|
-
|
|
42
|
+
**絕對不要憑記憶寫任何節點型別、屬性名稱、列舉值、樣式鍵或 Free/Pro 的判斷。去 `data/` 查。**
|
|
21
43
|
|
|
22
|
-
而且要用 `mo.py` 查,不要用 grep。grep
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
而且要用 `mo.py` 查,不要用 grep。grep 回答你打出來的問題,不回答你真正的問題。問它
|
|
45
|
+
`accordion-content`,它確認這個型別存在;掃描表則說 BROKE_PAGE——放一個下去,整個公開頁面
|
|
46
|
+
會變成一段 54 bytes 的錯誤字串。兩個都是真的,也都是錯的答案:列旁邊的註記說那段字串
|
|
47
|
+
指名的是「缺少父層」,而照 `accordion > accordion-item` 嵌套後它能寫入、能渲染,還免費送你
|
|
48
|
+
一個鍵盤可操作的展開元件。`mo.py type` 一次把三者都給你。
|
|
27
49
|
|
|
28
50
|
```bash
|
|
29
51
|
python tools/mo.py type accordion-content # 一個型別,接上所有線上掃描結果
|
|
30
|
-
python tools/mo.py check div text button #
|
|
31
|
-
python tools/mo.py style --grouped # 那 20 個單獨設定必然無效的屬性
|
|
32
|
-
python tools/mo.py states --verified # 實測會編譯出來的狀態
|
|
52
|
+
python tools/mo.py check div text button # 遇到不安全或不存在的型別就以 1 退出
|
|
33
53
|
python tools/mo.py params text # 一個型別上所有能設的東西
|
|
54
|
+
python tools/mo.py style --grouped # 單獨設定就無效的那 20 個
|
|
55
|
+
python tools/mo.py states --verified # 實測會編譯的狀態
|
|
56
|
+
python tools/mo.py css grid-column # 哪個 Mosaic 鍵驅動這條 CSS
|
|
34
57
|
```
|
|
35
58
|
|
|
36
|
-
然後去看頁面。Mosaic
|
|
59
|
+
然後去看頁面。Mosaic 有**七種**失敗模式,只有兩種會改變 HTTP 狀態碼:
|
|
37
60
|
|
|
38
61
|
```
|
|
39
|
-
|
|
40
|
-
commit 時 PHP fatal
|
|
41
|
-
結構無效的節點
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
62
|
+
驗證器乾淨拒絕 HTTP 200 + 內文帶 `exceptions` 陣列
|
|
63
|
+
commit 時 PHP fatal HTTP 500(122 個型別裡有 15 個放在一般 div 下會這樣)
|
|
64
|
+
結構無效的節點 HTTP 200、已寫入、資料庫有那一列,然後整個公開頁面
|
|
65
|
+
變成 54 bytes 的錯誤字串
|
|
66
|
+
值的「形狀」錯了 HTTP 200、存進去了,CSS 規則就是不出現
|
|
67
|
+
規則對、結果錯 HTTP 200、樣式表裡有、寫得對,瀏覽器算出另一個值
|
|
68
|
+
該網址沒有模板 HTTP 406,未登入者拿到空白內文
|
|
69
|
+
內容造成渲染時 fatal HTTP 500——commit 通過了,Mosaic 解析頁面時死掉。`code` 節點
|
|
70
|
+
的內容是模板:壓縮 CSS 慣用的 `@media(` 會被讀成函式呼叫。
|
|
71
|
+
`@media (` 就正常。build_page 會拒絕前者。
|
|
46
72
|
```
|
|
47
73
|
|
|
48
|
-
|
|
74
|
+
commit 成功不代表頁面能用,樣式表正確也不代表。這裡每個工具都會在寫入後把頁面抓回來——
|
|
75
|
+
而且把 5xx 當成空頁面,因為 WordPress 的「嚴重錯誤」畫面有 2,697 bytes,比任何天真的
|
|
76
|
+
「健康頁面」門檻都大。
|
|
49
77
|
|
|
50
78
|
## 驗證了什麼,怎麼驗的
|
|
51
79
|
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
全部在真實站台上跑——WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.7,**未授權**:
|
|
81
|
+
授權鎖的是主題庫和更新,不是節點工廠,所以 Pro 型別照樣註冊、照樣渲染。
|
|
54
82
|
|
|
55
83
|
| 項目 | 結果 |
|
|
56
84
|
|---|---|
|
|
57
|
-
| **節點型別** | 122 / 122
|
|
58
|
-
| **樣式屬性** | 98 / 98
|
|
59
|
-
| **節點屬性** | 181 / 181
|
|
85
|
+
| **節點型別** | 122 / 122 逐一放進獨立文件,寫入 → 渲染 → 斷言 → 刪除:70 RENDERED、30 COMMITTED、15 COMMIT_5xx、7 BROKE_PAGE。未渲染的當中有三個是「沒給父層」的掃描方法產物,註記就在列旁 |
|
|
86
|
+
| **樣式屬性** | 98 / 98 寫進真實頁面、對照編譯出的 CSS:58 COMPILED、18 ABSENT、21 SKIPPED |
|
|
87
|
+
| **節點屬性** | 181 / 181 用各自驗證鏈推出的值重新探測:35 APPLIED、42 NO_EFFECT、55 NO_HOST、47 SKIPPED |
|
|
60
88
|
| **響應式** | 兩個站共 731 條 `_t`/`_m` 宣告,對照網站實際送出的樣式表逐條斷言——全數通過 |
|
|
61
|
-
| **元件系統** | 完整驅動過一遍,**8 / 8**:在分類下建立、文件 heal、透過可寫的 instance 填入內容、唯讀的那個作為負對照組確實拒絕同一個寫入,最後兩個實例在頁面上由同一份定義渲染兩次 |
|
|
62
|
-
| **樣式狀態** | 53 個狀態中的 52 個寫進真實頁面,對照表格承諾的選擇器逐一比對:**36 個完全吻合**、12 個 NO_HOST、3 個 SKIPPED、1 個 BROKE_PAGE。七個可用於任何元素的狀態全數驗證 |
|
|
63
|
-
| **互動動畫** | 帶負對照組並讀回儲存列來探測 JS 動畫路徑:`propertyMetas` **確實**會被接受並儲存;屬性值仍然無法綁定,但界線現在很精確 |
|
|
64
|
-
| **入口動畫** | 以單調時鐘在載入後十五個時間點取樣、做八項斷言——它有播、被動畫的 `@property` 計數器跑到 100、遮罩退出點擊判定、視窗內沒有任何內容卡在 opacity 0、真實點擊落在文件上、`prefers-reduced-motion` 下遮罩根本不存在、而一切靜止後仍有東西在動。相較於完全沒有動畫的同一頁只多掉一幀,因為它會等文件第一次排版做完才開始 |
|
|
65
|
-
| **永續動畫** | 右下角一塊不斷自我印刷、點了會放大的版子,**28 項檢查**:暫停時間軸逐格比對證明週期性、在五個寬度、二十五個捲動停點量文字*與*控制項的遮擋、以「永遠讀不到」為失敗條件、用指標和 Enter 都能打開、reduced motion 下靜止。建在 Mosaic 自己的 accordion 上 |
|
|
66
|
-
| **accordion** | `accordion-item` 與 `accordion-content` 在掃描表裡是 BROKE_PAGE;照工廠要求的方式嵌套後能寫入、能渲染,**7 之 7**。註記現在就在那一列旁邊 |
|
|
67
89
|
| **瀏覽器** | 在 Chromium 三個視窗寬度上對兩個交付頁面做 3,988 次計算樣式讀取:2,929 條比對相符、912 條標為無法比對、**0 條被覆蓋** |
|
|
68
90
|
| **設計稽核** | 對比度、字體回退、CJK 字距、水平溢出、文字裁切、每行字數——在瀏覽器裡跑,**26 項發現,每一項都有書面裁定**——沒寫理由的 acknowledge 會被發布閘門拒絕 |
|
|
69
|
-
|
|
|
91
|
+
| **元件** | 元件系統從頭驅動到尾,**8 之 8**:在分類下建立、文件自癒、透過可寫實例填入樹、唯讀實例拒絕同一筆寫入作為負控制、頁面上兩個實例渲染同一個定義 |
|
|
92
|
+
| **樣式狀態** | 53 個狀態中的 52 個寫進真實頁面,對照表格承諾的選擇器:**36 個完全吻合**、12 NO_HOST、3 SKIPPED、1 BROKE_PAGE。偽類是大寫輸出的(`.M_EL9:HOVER`) |
|
|
93
|
+
| **互動** | JS 動畫路徑以負控制探測並讀回資料列:`propertyMetas` **會**被接受並儲存;屬性值仍然綁不上,但邊界現在是精確的 |
|
|
94
|
+
| **accordion** | `accordion-item` 與 `accordion-content` 在掃描表裡是 BROKE_PAGE;照工廠要求嵌套後能寫入、能渲染,**7 之 7** |
|
|
95
|
+
| **入口動畫** | 以單調時鐘在十五個時間點取樣、做八項斷言。相較於完全沒有動畫的同一頁只多掉一幀,因為它會等文件第一次排版做完才開始 |
|
|
96
|
+
| **永續動畫** | 右下角一塊不斷自我印刷、點了會放大的版子,**28 項檢查**:暫停時間軸逐格比對證明週期性、五個寬度、二十五個捲動停點量文字*與*控制項的遮擋、以「永遠讀不到」為失敗條件、指標和 Enter 都能打開、reduced motion 下靜止 |
|
|
97
|
+
| **Elementor 轉換** | 一個正式站的全部 Elementor 頁面——19 頁、3,292 個元素——轉換、建置、對照來源檢查:**19 之 19**,3,281 個元素搬過去、11 個書面宣告。再把轉出的頁面跑過響應式、瀏覽器和稽核,每一項發現都分類為「繼承」或「引入」:**引入 0 個** |
|
|
98
|
+
| **主題匯出/匯入** | 兩條路徑,都來回驗證過。`theme_export.php` 用 WP-CLI 把資料列搬成 JSON、ID 不變。`theme_zip.py` 驅動 Mosaic **自己**的 ZIP 匯出匯入——匯入預設進 test mode,要 `--activate` 才上線,因為它的預設是直接切換 live 站——**22 項檢查**逐表、逐樹比對副本與來源 |
|
|
99
|
+
| **技能本身** | `claude plugin eval .`——五個使用者真的會問的問題,各跑三次,有載技能和沒載各一臂,每次三個 LLM 裁判。**有:五題全 1.00。沒有:五題全 0.00。** 基準線最好的回答是拒答 |
|
|
70
100
|
| **線上量測** | 114 條 REST 路由、151 個 element class、59 個條件主體、23 張表 / 206 個欄位 |
|
|
71
101
|
|
|
72
|
-
`SKIPPED`、`NO_HOST`、`INCONCLUSIVE`
|
|
73
|
-
|
|
102
|
+
`SKIPPED`、`NO_HOST`、`INCONCLUSIVE` 從不折算進通過率。把自己的盲點算成成功的掃描,
|
|
103
|
+
正是這個技能反對的東西。
|
|
74
104
|
|
|
75
|
-
###
|
|
105
|
+
### 動手前值得知道的結果
|
|
76
106
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
要用就用群組形狀——`border` 收 `{width, style, color}`——或者退回 `customStyles`。
|
|
107
|
+
**屬於某個 `group` 的屬性單獨設定時無效。** 兩個方向都精確:78 個未分組屬性給出 58 COMPILED、
|
|
108
|
+
0 ABSENT;20 個分組屬性全部 0 COMPILED。所以 `borderLeftWidth`、`outlineColor`、`gridColumnStart`
|
|
109
|
+
是同一條規則的三個實例。用分組形狀——`border` 吃 `{width, style, color}`——或 `customStyles`。
|
|
81
110
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
**要把 `border-left:0` 明講出來。**
|
|
111
|
+
**斷點覆寫可以「改」一個屬性,永遠不能「拿掉」一個。** 窄螢幕的 `customStyles` 只是不提邊框,
|
|
112
|
+
寬螢幕的邊框就繼續站在那裡。把 `border-left:0` 說出口。
|
|
85
113
|
|
|
86
|
-
|
|
114
|
+
**只有四個型別吃 `url`**:`button`、`menu-link`、`wysiwyg-link`、`dropdown-toggle`。放在 `text`
|
|
115
|
+
或 `image` 上會被接受、被存下、然後不產生任何錨點。改用 `menu-link` 包起來——它接受任意子節點,
|
|
116
|
+
一有 `url` 就變成真正的 `<a href>`。
|
|
117
|
+
|
|
118
|
+
**圖片的 attachment protocol 路徑是相對 uploads 目錄的。**
|
|
119
|
+
`wp-attachment://image/<id>/full/2026/09/pic.png` 能解析,還會帶出附件的寬高。給它完整的
|
|
120
|
+
`wp-content/uploads/...` 路徑——最直覺的猜法——Mosaic 會把 uploads 前綴再接一次,而且不報錯。
|
|
121
|
+
|
|
122
|
+
## Elementor → Mosaic
|
|
87
123
|
|
|
88
124
|
```bash
|
|
89
|
-
wp
|
|
90
|
-
python tools/
|
|
91
|
-
|
|
92
|
-
python tools/
|
|
93
|
-
|
|
94
|
-
wp eval-file tools/theme_import.php theme.json "名稱" rebind activate
|
|
125
|
+
wp post meta get 2360 _elementor_data > page.json
|
|
126
|
+
python tools/from_elementor.py --data page.json --out spec.json --report conv.csv \
|
|
127
|
+
--uploads-base https://site/wp-content/uploads --slug works --post 208
|
|
128
|
+
python tools/build_site.py --config c.json --site spec.json
|
|
129
|
+
python tools/verify_conversion.py --data page.json --url https://site/works/ --report conv.csv
|
|
95
130
|
```
|
|
96
131
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
132
|
+
範圍是數出來的,不是憑喜好定的:一個真實站的 19 頁裡,container / heading / text-editor /
|
|
133
|
+
button / html / icon-list / divider / image 佔了全部元素的 99.6%。長尾——loop grid、表單、倒數、
|
|
134
|
+
第三方 addon——是動態的,沒有節點可以變成;每一個都按名稱和原因列進報告、絕不默默丟掉,
|
|
135
|
+
`--strict` 則拒絕產出有損的 spec。
|
|
136
|
+
|
|
137
|
+
版面、字體、顏色、邊框、連結、圖片都會過去,三個斷點都帶(`_tablet`/`_mobile` → `_t`/`_m`)。
|
|
138
|
+
不會過去的:進場動畫(Mosaic 的互動綁定未解)、shape divider、漸層疊加。驗證器接著拿建好的
|
|
139
|
+
頁面對照來源——每個字串、圖片、連結、標題層級——它馬上就證明了自己的價值:抓到轉換器把
|
|
140
|
+
`url` 寫在不理它的節點上,漏了 21 個連結中的 19 個。
|
|
141
|
+
|
|
142
|
+
## 工具
|
|
143
|
+
|
|
144
|
+
| 工具 | 用途 |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `mo.py` | 查詢量測過的表面——**正門** |
|
|
147
|
+
| `build_page.py` / `build_site.py` | 透過有守門的寫入路徑 commit 一份 spec;量到會壞的一律拒絕 |
|
|
148
|
+
| `from_elementor.py` / `verify_conversion.py` | Elementor → Mosaic,以及內容確實到達的證明 |
|
|
149
|
+
| `verify_browser.py` | 瀏覽器算出來的是不是樣式表承諾的,以及有沒有通過設計稽核 |
|
|
150
|
+
| `verify_rwd.py` | 每條 `_t`/`_m` 宣告有沒有進到送出的樣式表 |
|
|
151
|
+
| `verify_intro.py` / `verify_loop.py` | 會「結束」的載入動畫;會循環、不遮東西、能打開的永續動畫 |
|
|
152
|
+
| `theme_export.php` / `theme_import.php` | 整個主題以 JSON 資料列透過 WP-CLI 搬移,ID 不變 |
|
|
153
|
+
| `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | 在編輯器外驅動 Mosaic 自己的 ZIP 匯出匯入、副本對來源逐樹比對、以及拒絕刪 live 主題的乾淨刪除 |
|
|
154
|
+
| `sweep_*.py` / `probe_*.py` | 那些表格是用這些儀器量出來的 |
|
|
155
|
+
| `bootstrap_probe_theme.php` / `mint_session.php` | 免授權的實驗主題,以及從 WP-CLI 鑄出 REST session |
|
|
156
|
+
|
|
157
|
+
## 線上的工作範例
|
|
158
|
+
|
|
159
|
+
`sites/_moksa.py` 只透過資料表建出一個真實的工作室網站,隨套件出貨作為參考。它就在
|
|
160
|
+
**https://mosaic.moksaweb.com/**:1,286 個節點的首頁,用具名 view timeline 做捲動追蹤的條款索引;
|
|
161
|
+
一段一次印一塊版、把浮世繪印出來的入口動畫;一塊在角落永遠印下去、點了會放大的版子;
|
|
162
|
+
還有一個 WooCommerce [My Account](https://mosaic.moksaweb.com/my-account/) 頁,它的 UI 全部
|
|
163
|
+
透過一個跑 shortcode 的 `code` 節點進來。全程沒有自己寫任何 JavaScript。
|
|
164
|
+
|
|
165
|
+
## 從哪裡開始
|
|
166
|
+
|
|
167
|
+
1. `references/data-model.md`——頁面實際住在哪裡。
|
|
168
|
+
2. `references/write-protocol.md`——checkout / check / commit。
|
|
169
|
+
3. `references/failure-modes.md`——Mosaic 怎麼失敗,量測版。**動手前先讀。**
|
|
170
|
+
4. `references/responsive.md`——狀態/斷點/屬性三軸。
|
|
171
|
+
5. `references/styling.md`——樣式值怎麼變成 CSS。
|
|
172
|
+
6. `references/design-system.md`——element class 與設計 token。
|
|
173
|
+
|
|
174
|
+
## 發版
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm version minor # 更新 package.json、SKILL.md 和八個平台模板的版號,
|
|
178
|
+
# commit、打 tag、push;tag 觸發 release.yml
|
|
179
|
+
```
|
|
100
180
|
|
|
101
|
-
|
|
181
|
+
`bin/check-release.mjs` 把關每一次發版,檢查的是容易出錯而不是容易檢查的事:版號一致、
|
|
182
|
+
`files` 的每個 glob 都對到東西、每張驗證表的列數仍然等於 SKILL.md 和四份 README 引用的數字、
|
|
183
|
+
沒有未裁定的設計稽核發現、eval 套件在場,以及**直接檢查 tarball 本身**——npm 的 `files` 白名單
|
|
184
|
+
會蓋過 `.gitignore`,曾經把一個真實客戶的網站放進即將發布的套件裡。
|
|
102
185
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
3. `references/failure-modes.md` —— Mosaic 怎麼壞的,都是量出來的。**動筆前先讀。**
|
|
106
|
-
4. `references/responsive.md` —— state / breakpoint / property 這個軸。
|
|
107
|
-
5. `references/styling.md` —— 一個樣式值怎麼變成 CSS。
|
|
108
|
-
6. `references/design-system.md` —— element class 與設計 token。
|
|
186
|
+
發布走 npm trusted publishing(OIDC):哪裡都沒有 token。npmjs.com 套件設定的 Trusted Publisher:
|
|
187
|
+
GitHub Actions、`Moksa1123` / `mosaic-headless`、workflow `release.yml`、environment **留空**。
|
|
109
188
|
|
|
110
189
|
## 授權
|
|
111
190
|
|
|
112
|
-
MIT。Mosaic Pro
|
|
191
|
+
MIT。Mosaic Pro 本身是授權的第三方軟體,**不**包含在此。
|
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 (122 node types, 181 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 151 element classes, 74 dynamic variables, 12 interaction triggers, 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, 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 from outside the editor and holds the copy against the source tree for tree.
|
|
5
5
|
license: "MIT"
|
|
6
6
|
author: "moksa (https://moksaweb.com)"
|
|
7
|
-
version: "1.17.
|
|
7
|
+
version: "1.17.1"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Headless Mosaic
|
|
@@ -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.17.
|
|
23
|
+
"version": "1.17.1"
|
|
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.17.
|
|
23
|
+
"version": "1.17.1"
|
|
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.17.
|
|
23
|
+
"version": "1.17.1"
|
|
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.17.
|
|
23
|
+
"version": "1.17.1"
|
|
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.17.
|
|
23
|
+
"version": "1.17.1"
|
|
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,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mosaic-headless",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.1",
|
|
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",
|