marko-ui について
marko-ui は、レジストリの Marko 6 UI コンポーネントを扱う CLI スキルです。検索、ドキュメント確認、追加、変更チェックを支援します。
主な機能
- 01コンポーネントレジストリの検索
- 02コンポーネントドキュメントの確認
- 03コンポーネントの追加と比較
- 04プロジェクト設定の検査
- 05エージェント用一覧の同期
活用シーン
- 01適切な Marko 6 コンポーネントの検索
- 02マークアップ作成前の props 確認
- 03UI コンポーネントの追加や更新
- 04ローカル変更とレジストリ版の比較
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ svallory/ marko-ui --skill marko-uiインストール後、Claude Code で/marko-uiを入力して読み込まれたか確認します。
詳細
marko-ui
marko-ui は Marko 6 向けの shadcn/ui です。Zag.js のステートマシンによって動作し、Tailwind v4 でスタイルが設定された、アクセシブルなコンポーネントを提供します。以下のすべての作業には marko-ui CLI を使用してください。レジストリにすでにあるコンポーネントを手書きしたり、コンポーネントのプロパティを推測したりしないでください。
プロジェクトのパッケージランナー(bunx marko-ui、npx marko-ui、pnpm dlx marko-ui)で CLI を実行します。stdin が TTY でない場合、すべてのコマンドは非対話型になります。確認には「はい」が選択され、init は既定値を使用し、コンポーネント名を指定せずに実行した add はピッカーを開かずに 2 を終了コードとして終了します。
まず、このプロジェクトで使われているディストリビューションを確認します
components.json の distribution を確認してください(存在しない場合は copy です)。コンポーネントの取得方法とカスタマイズ方法は、これによって変わります。
copy(既定) | import | |
|---|---|---|
| コンポーネントの場所 | ui エイリアス配下のプロジェクト内(src/components/ui/<name>/) | node_modules/@marko-ui/shadcn |
| コンポーネントの取得 | marko-ui add <name> -y | 追加不要 — @marko-ui/shadcn/ui/<name>/<name>.marko をインポートします |
| カスタマイズ | コンポーネントファイルを編集します(プロジェクトのコードです) | プロジェクトのスタイルシートから mu-* フッククラスをオーバーライドします |
components.json がない場合、marko-ui はセットアップされていません。marko-ui init を実行してください(エージェントのドキュメントも書き込むには --agents を追加します)。
ワークフロー
marko-ui search -q <query>— コンポーネントを検索します(機械可読な出力には--jsonを指定します)。各項目の名前、タイトル、説明に含まれる完全な単語と照合します。単語を追加するほど順位が絞り込まれ、入力した単語のいずれにも一致しない項目は除外されます。項目はどれもコンテキストを消費するため、名前を推測する前に検索してください。インストール済みのコンポーネントは、プロジェクトのAGENTS.mdに記載されています。marko-ui docs <name>— コンポーネントのドキュメントを Markdown 形式で表示します。インストール方法、使い方、パーツ、プロパティ、イベント、キーボード操作/アクセシビリティ、その後に基本的なサンプルが続きます。このセッションで使ったことのないコンポーネントのマークアップを書く前に、必ずこれを読んでください。 意図的に簡潔にまとめており、サンプルは最大3つ(最初のサンプルと、必須としてマークされたサンプル)で、残りは「その他のサンプル」に一覧表示されます。--examplesはすべてのサンプルを表示し、--example <id…>は指定したサンプルのみを表示します。--listはインデックスを表示します。docs <name> --jsonは、以下のエンベロープに、同じ Markdown(およびその生成元の構造化モデル)を返します。この Markdown はあなた向けに整えられています。デモのソースではメンテナーのコメントが削除され、プロパティ一覧はプロパティごとに1行(name: type = default — description)となり、= fixed Xのセルはコンポーネントがその値を設定することを示し、指定した値は無視されます。また、ほとんどのプロパティは省略可能なため、| undefinedは省略されます(必須プロパティには印が付きます)。デフォルト値の記載がない場合は、記録されていないことを意味し、デフォルト値がないという意味ではありません。スニペット内のインポートパスはプロジェクト独自のcomponents.json(distribution+aliases.ui)に従うため、読んだ内容がそのままプロジェクトに適用されます。プロジェクトにインストール済みのコンポーネントの場合、docsはネットワークを使わず、インストール済みバージョンを説明します。copy 配布では、addが取得してnode_modules/.cache/marko-ui/にキャッシュしたコピーを読み込みます(ドキュメントファイルを取得できなかったaddでもインストールは行われますが、DOCS_CACHE_FAILED警告が表示され、docsは後からレジストリを読み込みます)。import 配布では、インストール済みの@marko-ui/shadcn内のドキュメントを読み込みます。また、インストール行は省略されます。この場合、stderr にはsource: installed (…)と表示されます(--jsonの場合はdata.components[].source)。インストール済みバージョンではなくレジストリの最新ドキュメント(アップグレード時に適用される内容)を読むには、--remoteを指定します。レジストリのドキュメントは項目が参照するコンポーネントごとのファイルであるため、show <name>が出力するのはcomponentDocsRefURL であり、ドキュメントそのものではありません。これがないレジストリ項目にはドキュメントがなく、docsはその旨を伝えます(NOT_FOUND。showの使用を提案します)。未インストールのコンポーネントはレジストリから取得され、対応する正確なコマンドmarko-ui add <name> -yが表示されます。marko-ui show <name>— レジストリ項目を JSON で表示します。--filesは書き込まれるファイルの一覧を表示し、--depsは npm およびレジストリの依存関係を表示します。showはどのモードでも JSON コマンドのため、--jsonを指定できますが、動作は変わりません。また、showが失敗した場合は、ターミナル上でも stdout にmarko-ui/errorエンベロープが出力されます。パイプに出力されるものと同じドキュメントであり、文章による説明ではありません。いずれの場合も stdout を解析してください。marko-ui add <name> -y --json— インストールします(copy 配布)。自分で実行する場合は、必ず--jsonを指定してください。これにより、created/updated/skippedの各ステータスになったファイル、インストールされた依存関係、警告が返されるため、処理結果を確認するために人向けの出力を解析する必要はありません。--dry-runはdryRun: trueと PLANNED ステータスを含む同じ形式でプレビューします(--dry-run --json)。--overwriteはローカルファイルを置き換えます。marko-ui diff <name> --json— ローカルでの編集内容とレジストリのバージョンを比較します。各ファイルのステータス(unchanged/modified/missing)と、変更があるファイルについては ANSI なしのプレーンテキストによる統合差分を表示します。差分の有無にかかわらずokはtrueです。diffは報告するものであり、良し悪しを判定するものではありません。marko-ui doctor --json— ヘルスチェックを実行します。終了コード3は問題があることを示し、失敗した各チェックには、修正に使うコマンド(または1行の操作)を含むfixフィールドがあります。作業完了を報告する前に、init/addの後で実行してください。marko-ui agents sync --json— コンポーネントの追加または削除後に、AGENTS.mdのコンポーネント一覧を更新します。agentsChangedはファイルに実際の変更があったかどうかを示し、skillsはインストールされたエージェントスキルと、すでに存在していたエージェントスキルを示します。marko-ui manifestは、正確な仕様が必要な場合に、すべてのコマンド、フラグ、終了コード、エラーコードを JSON として出力します。marko-ui manifest <command>は、そのコマンド(名前またはエイリアス)と終了コードだけを出力します。単一のフラグを確認するときは、こちらのほうが効率的です。存在しない名前を指定すると、使用方法のエラー(終了コード 2)になります。
JSON の読み取り
すべての --json ペイロードは、{ "$type", "version", "ok", "data" } という単一のドキュメントです。data を読む前に $type に応じて分岐してください。$type は marko-ui/search、marko-ui/status、marko-ui/show、marko-ui/docs、marko-ui/docs.list、marko-ui/doctor、marko-ui/registry.list、または marko-ui/manifest です。出力は 1 行の最小形式(パイプまたはプログラムの場合)で、stdout がターミナルの場合にのみ整形されます。この出力を読むのは通常プログラムであり、インデントにはトークンが必要になるためです。--pretty フラグはありません。
search の項目には、name、短い type("ui"、"block")、description、registry が含まれます。そこから導き出せる情報はありません。デフォルト以外のレジストリから結果をインストールするには、<registry>/<name> を渡してください。data 内の addArgument に、このルールが一度だけ記載されます。検索結果にデフォルト以外のレジストリが含まれる場合に限ります。
status は config.distribution、config.visualStyle、config.iconLibrary を報告します。config.resolvedPaths では cwd(絶対パスで一度だけ)を示し、それ以外のすべてのパスはそれを基準とした相対パスで示します。
失敗時は、エラーの読み取りで説明されている marko-ui/error エンベロープが返され、文章にはなりません。すべてのモード(ターミナルを含む)でこれが当てはまるコマンドは show だけです。これはどのモードでも JSON コマンドなので、失敗時も stdout にドキュメントが出力されます。
コマンドによる変更の読み取り
add、init、eject、diff、agents sync はすべて同じ 3 つの
形式を返すため、1 つのパーサーですべてに対応できます。
files:{ path, status }。cwdを基準とした相対パスです(先頭で一度だけ示されます)。warnings:{ code, message, fix }。警告は失敗ではありません。コマンドは処理を完了しており、okはtrueのままです。警告には残っている作業が示されます。コードはmarko-ui manifestのwarningCodesに記載されています。人間向けの出力にも同じmessageとfixが表示されるため、読んだ内容と解析した内容に食い違いはありません。next:次に実行する価値のあるコマンドです。内容を再推測せず、これに従ってください。
status の値は文章ではなく、定義済みの語彙です。
| status | 意味 |
|---|---|
created | この実行で、存在しなかったファイルを書き込みました |
updated | この実行で、既存のファイルを置き換えました |
unchanged | ファイルはすでにレジストリとバイト単位で一致していました |
skipped | ファイルが存在し、内容が異なっていましたが、そのまま残されました(--overwrite を指定していれば置き換えられていました) |
removed | 古いアイコンマップをこの実行で削除しました |
missing | (diff のみ)レジストリにはありますが、プロジェクトにはありません |
skipped と unchanged は異なる状態です。 変更のないコンポーネントに対して add を再実行すると、skipped ではなく unchanged が報告されます。skipped はファイルに差分があり、何も置き換えられなかったことを意味します。ユーザーにインストール済みと伝える前に、必ずステータスを確認してください。「この実行で書き込んだ」ことを意味するステータスは created だけです。
add では、items.resolved(実際にインストールされたものです。要求したもの以外に、レジストリの依存関係も含まれる場合があります。add button で utils も解決されることがあります)、dependencies(installed/present/failed)、およびプレビュー時の dryRun: true も確認してください。プレビュー時のステータスは実際に確認されたものではなく、計画上のものです。
エラーの読み方
結果は stdout に、問題はすべて stderr に出力されます。 CLI をパイプや stdout のキャプチャで実行すると、コマンドのペイロードだけが取得されます。ログ行、警告、失敗テキストは含まれません。stderr をデータとして解析しないでください。
--json を指定した場合、失敗時には次の形式の JSON オブジェクトが 1 つだけ stdout に出力されます。
{
"$type": "marko-ui/error",
"version": 1,
"ok": false,
"error": {
"code": "NOT_FOUND",
"message": "Registry item \"buton\" was not found. Did you mean \"button\"?",
"suggestion": "Did you mean \"button\"?",
"details": { "itemName": "buton", "suggestions": ["button"] }
}
}
メッセージのテキストではなく、error.code に基づいて分岐してください。すべてのコードは marko-ui manifest の errorCodes に記載されています。よく使われるものは、NOT_FOUND(不明な項目)、NOT_CONFIGURED(components.json がない、またはレジストリが設定されていない)、INVALID_CONFIG、NETWORK_ERROR(レジストリ/ドキュメントのホストに到達できない — 終了コード 4)、FETCH_ERROR(ホストが 5xx または 429 で応答 — 終了コード 4。後で再試行してください)、MISSING_ENV_VARS、MONOREPO_ROOT(リポジトリのルートではなく、ワークスペースから実行した)、USAGE_ERROR(不明なコマンドやフラグを含む、不正な呼び出し)、CHECK_FAILED(doctor/validate/agents --check で問題が見つかった)、PROJECT_NOT_FOUND(そのディレクトリに Marko プロジェクトがない)です。
接続エラー(ポート接続拒否、DNS エラー、タイムアウト)は、レジストリを使用するすべてのコマンドで終了コード 4 の NETWORK_ERROR になります。サーバーが 5xx または 429 で応答した場合は、同じく終了コード 4 の FETCH_ERROR です。レジストリで障害が発生しており、同じコマンドが後で成功する可能性があります。その他のすべての HTTP ステータスは、固有のコードとともに終了コード 1 になります。UNAUTHORIZED(401)、FORBIDDEN(403)、NOT_FOUND(404)、GONE(410)、400 など予期しない 4xx に対する REQUEST_REJECTED が該当します。再試行しても変わりません。
レジストリのインデックスに到達できた場合、details.suggestions に「もしかして」の候補が含まれるため、説明文を解析せずに再試行できます。よくあるケースは、docs、show、add、diff で不明な項目名を指定した場合です。
details にスタックトレース、ホームディレクトリ以下の絶対パス、認証情報を含む URL が入ることはありません。パスは短縮され、レジストリ URL からはクエリ文字列と認証情報が取り除かれます。スタックは MARKO_UI_DEBUG が設定されている場合に限り、stderr に出力されます。
複数の名前のうち 1 つが失敗しても、ほかの名前は成功することがあります。marko-ui docs nope button は、button の Markdown を stdout に出力し、nope については stderr に報告して、終了コード 1 で終了します。
終了コード:0 は成功 · 1 は操作上の失敗 · 2 は使用方法のエラー(コードは USAGE_ERROR のみ。引数またはフラグ値が不正、もしくは不足している場合。プロジェクトがない、初期化されていない、またはディストリビューションが異なる場合は、それぞれ固有のコードで終了コード 1) · 3 はチェックで問題が見つかった · 4 はレジストリに到達できない、またはレジストリで障害が発生している(接続エラー、5xx、429)。marko-ui manifest には 2 つのテーブル(exitCodes、errorCodes)が記載されています。
コンポーネントの使用
import Dialog from "../components/ui/dialog/dialog.marko";
import Button from "../components/ui/button/button.marko";
<let/open=false/>
<Dialog open:=open>
<@trigger|props|>
<Button ...props>Edit profile</Button>
</@trigger>
<@title>Edit profile</@title>
<@description>Make changes to your profile here.</@description>
<p>Form fields go here.</p>
</Dialog>
- パーツは属性タグ(
<@trigger>、<@title>)であり、個別にインポートするサブコンポーネントではありません。marko-ui docs <name>には、各コンポーネントのパーツが一覧表示されます。 <@trigger|props|>は、レンダリングする要素に展開して渡すためのマシン用 props を提供します。 Radix のasChildに相当します。- 状態は
:=でバインドします(open:=open、value:=value、checked:=checked)。または、値とそのxChangeハンドラーを渡します(open=open openChange=(v) => { open = v })。 - copy ディストリビューションでは、プロジェクトに独自の
marko.jsonがない場合、addはタグライブラリ(marko.json)も生成するため、インポートなしでインストールしたコンポーネントをタグとして使用できます(<Button>、<CardHeader>)。明示的なインポートも常に使用できます。 - コンポーネントを
Inputとしてインポートしないでください。 Marko の予約済み props 型と名前が衝突します。入力コンポーネントはTextInputとしてインポートします。
コンポーネントが気付かれずに壊れる落とし穴
以下はいずれも実際のバグにつながったものです。作業を終える前に、コードをこのリストと照らし合わせてください。
- 制御された props はマシンを固定します。 対応する
openChange/valueChange/checkedChange(または:=バインド)なしでopen=/value=/checked=を指定すると、コンポーネントはその状態に固定されます。初期値だけを設定する場合は、defaultOpen=/defaultValue=/defaultChecked=を使ってください。 - ブール値の
aria-*/data-*属性は正しくシリアライズされません。 Marko はブール値のtrueを属性値なしで出力するため、aria-selected=(bool)はaria-selected=""を出力し、data-active=(bool)はdata-[active=true]:の Tailwind バリアントに一致しません。String(...)で囲んでください。 - Zag の値をタグ境界の外に渡したり、状態に保持したりしないでください。 マシンサービスと
apiオブジェクトには関数が含まれており、再開時にシリアライズできません。プレーンデータを渡すか、テンプレート内でクロージャーを記述し(parentApi=() => api())、使用箇所でapi()を呼び出してください。 - 子の属性タグ本体内で、親コンポーネントの
api()を読み取らないでください。 代わりに、クロージャーとして子の入力に渡してください。オーバーレイを開いた後にTypeError: ... is not a functionが発生するのがその症状です。 - 何も変わらないオーバーライド(import 配布)。 スタイルレイヤーは
layer(components)でインポートする必要があり、対応する@custom-variant style-<name>の行がプロジェクトのスタイルシートに存在しなければなりません。どちらが欠けても、エラーは表示されません。 - スタイルが適用されないコンポーネント(コピー配布)。 テーマのスタイルシートが読み込まれていません。
components.jsonでtailwind.cssとして記録されたファイルがルートレイアウトからインポートされていること、および Vite の設定に@tailwindcss/viteがあることを確認してください。marko-ui initは両方を設定しますが、手作業で設定すると一方を見落としがちです。 "Cannot find module @zag-js/..."またはmarko-zag。 コンポーネントの npm 依存関係が不足しています。marko-ui addでインストールできます。marko-ui show <name> --depsで依存関係の一覧を確認できます。
Marko 6 の言語仕様(<let>、<const>、<for>、イベントハンドラー、テンプレート内の TypeScript)については marko6 スキルを、@marko/run のルーティングについては marko-run を使ってください。
コンポーネントの編集(コピー配布)
このファイルはプロジェクトのコードです。各 .marko ファイルの先頭には、各パーツの Tailwind クラスを格納する static const styles = { ... } ブロックがあります。クラスはそこで変更してください。インタラクティブなコンポーネントでは、1 つのタグ <zag/api=() => machine from=input/> でマシンを接続します。このタグは input からマシンの props を取り出し、api ゲッターを返します。キーボード操作、フォーカス管理、ARIA はマシンが担うため、スタイルの変更でアクセシビリティが損なわれることはありません。編集後に marko-ui diff <name> を実行すると、レジストリとの差分を確認できます。
詳細
- ドキュメント:https://marko-ui.saulo.tech/docs(コンポーネントのページは Markdown 形式:
/docs/components/<name>.md) - 新しいコンポーネントの作成:https://marko-ui.saulo.tech/docs/creating-components
- エージェントのセットアップとトラブルシューティング:https://marko-ui.saulo.tech/docs/working-with-ai