mcpField
B
bunwv

bunwv

github.com/natichaテスト・品質21941 回インストール24 週間前に更新
リポジトリ

bunwv について

bunwvは、永続化されたWebViewセッションでエージェントがブラウザーを操作するためのコマンドラインスキルです。操作間でページ状態を保ち、構造化された結果やエラー、スクリーンショット、イベントを扱えます。

主な機能

  1. 01永続化WebViewセッション
  2. 02ブラウザー操作とページ待機
  3. 03DOM評価と要素確認
  4. 04フォーム操作と送信
  5. 05スクリーンショットと画像変換
  6. 06コンソールとCDPイベントの取得

活用シーン

  1. 01複数手順のウェブサイト操作を自動化
  2. 02フォーム送信とページ遷移のテスト
  3. 03ページ内容やブラウザーエラーの調査
  4. 04UI確認時のスクリーンショット取得

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/naticha/bunwv --skill bunwv

インストール後、Claude Code で/bunwvを入力して読み込まれたか確認します。

詳細

bunwv

永続的な WebView セッションを使用したヘッドレスブラウザー自動化です。デーモンは単一の WebView インスタンスを起動したままにするため、ページの状態(DOM、モーダル、フォーム、SPA のルート、スクロール位置)はコマンド間で維持されます。

エージェント向けの使用パターン

bunwv は、個別のツール呼び出しで操作する AI エージェント向けに設計されています。信頼できる契約事項を以下に示します。

  • 成功した動詞は stdout に何も出力せず、終了コード 0 を返します。 click、type、navigate、press、scroll、scroll-to、clear、submit、resize、back/forward/reload、close、exists、wait-for、wait-for-gone、cdp-subscribe、cdp-unsubscribe はすべてこれに従います。読み取り動詞(status、evaluate、events、console、cdp、cdp-subscriptions、screenshot、sessions)は結果を出力します。
  • エラーは、安定した終了コードとともに stderr に JSON で出力されます。 stderr のテキストではなく、終了コードに基づいて分岐してください。
    • 0 正常、1 一般、2 使用方法、3 タイムアウト、4 要素が見つからない、5 デーモンに到達できない、6 バッチの一部失敗(batch --keep-going の場合のみ)。
  • 動詞の実行中に console.error/console.warn が自動的に通知されます。 動詞の実行中にページがエラーをログに出力すると、bunwv は stderr に {"console":[…]} を出力します。追加の呼び出しをしなくても失敗を確認できます。
  • イベントはカーソルで取得します。 events --since <seq> はカーソルより新しいエントリーと新しいカーソルを返します。ターンをまたいでカーソルを保持し、操作後に再取得してください。バッファーから古いエントリーが削除されている場合、応答には "truncated":true,"oldest":<seq> が含まれます。
  • バイナリー出力のファイルパス。 bunwv screenshot は、デフォルトでバイトデータを /tmp/bunwv-screenshot-<session>.jpg(JPEG @ q80)に書き込み、パスを stdout に出力します。画像を確認するには、そのパスに対して Read ツールを使用してください。
  • 統一されたエンベロープには --json を使用します。 --json を指定したコマンドは、{ok, data?, error?, exitCode} を単一の JSON 行として返します。簡潔な出力よりも統一された形式を使いたい場合に便利です。
  • 柔軟なフラグ構文。 --flag value、--flag=value、およびフラグの繰り返し(例:--mod Shift --mod Control)がすべて使用できます。フラグはコマンドの前後どちらにも指定できます。bunwv --json status と bunwv status --json は同じ意味です。
  • BUNWV_SESSION 環境変数 — 一度設定すれば、--session は省略できます。

コマンド

すべてのコマンドは bunwv <command> で実行します(bun install -g @naticha/bunwv でグローバルにインストールします)。

bunwv start [--width N] [--height N] [--data-store PATH] [--idle-timeout ms]
      [--backend webkit|chrome] [--chrome-path PATH] [--chrome-argv '[json]']
      [--chrome-url <ws-url>] [--url <initial-url>]
bunwv navigate <url>
bunwv click --selector <css> | --text <text> | --at <x,y>
      [--text-match exact|contains|regex]   # default: contains (trimmed)
      [--button left|right|middle] [--count 1|2|3]
      [--mod Shift] [--mod Control] [--mod Alt] [--mod Meta]
      [--timeout ms]
bunwv exists <selector>                     # silent; exit 0 if present, 4 if not
bunwv type <text>
bunwv press <key> [--mod Shift] [--mod Control] ...
bunwv clear <selector>
bunwv submit [--form <selector>] [--button <text>]
bunwv scroll <dx> <dy>
bunwv scroll-to <selector> [--block start|center|end|nearest] [--timeout ms]
bunwv screenshot [--format png|jpeg|webp|avif|heic] [--quality 0-100]
      [--max-width N] [--max-height N]
      [--placeholder | --metadata]
      [--encoding blob|buffer|base64|shmem] [--out <path>|-]
bunwv image <input> [--out <path>|-] [--format ...] [--quality N]
      [--resize WxH | --max-width N | --max-height N]
      [--rotate 90|180|270] [--flip] [--flop] [--metadata] [--placeholder]
bunwv evaluate <expression>
bunwv console [--clear] [--since <seq>]       # terse "<seq> [<level>] <message>", cursor-based
bunwv events [--since <seq>]
bunwv cdp <method> [--params '{}']
bunwv cdp-subscribe <CDP.event> [<CDP.event> ...]
bunwv cdp-unsubscribe <CDP.event> [<CDP.event> ...]
bunwv cdp-subscriptions
bunwv wait-for <selector> | --url <substring> | --title <substring>
      [--timeout ms]
bunwv wait-for-gone <selector> | --url <substring> | --title <substring>
      [--timeout ms]
bunwv batch [--file <path>] [--keep-going]  # stdin NDJSON of JSON arrays
bunwv status [--json]
bunwv resize <width> <height>
bunwv back / forward / reload
bunwv sessions
bunwv close [--all]
bunwv help

すべてのコマンドで、--json(エンベロープを有効化)、--session <name>(または BUNWV_SESSION 環境変数)、および上記の柔軟なフラグ構文を使用できます。

デフォルトのビューポートは、スクリーンショットを読みやすくするため 1920x1080 です。

セッション管理

セッションは名前付きで分離されています。各セッションは、個別の Unix ソケット上で独自のデーモンを実行します。デフォルトのセッション名は default です。--session <name> または BUNWV_SESSION 環境変数で変更できます。

bunwv start                          # starts "default" session
bunwv start --session cmais          # separate "cmais" session
BUNWV_SESSION=cmais bunwv navigate http://localhost:3000
bunwv sessions                       # list all running sessions
bunwv close --session cmais          # stop a specific session
bunwv close --all                    # stop every running session

自動シャットダウン:デーモンは、30 分間操作がないと終了します。--idle-timeout で変更できます。

bunwv start --idle-timeout 3600000   # 1 hour
bunwv start --idle-timeout 0         # never auto-shutdown

再利用の検出:既存のセッションに対して bunwv start を実行すると、現在の URL を出力して終了コード 0 を返します。

ベストプラクティス:会話の開始時に bunwv sessions を実行し、孤立したデーモンがないか確認してください。不要なものは bunwv close --all で終了します。

基本的な操作ループ

確認してから操作し、再度確認します。基本的な単一ターンのループは次のとおりです。

  1. デーモンを起動します:bunwv start(すでに起動している場合は何もしません)
  2. 移動します:bunwv navigate http://localhost:3000
  3. スクリーンショットを取得します:bunwv screenshot — /tmp/bunwv-screenshot-<session>.png を stdout に出力します
  4. Read ツールでスクリーンショットを読み取ります
  5. 操作します:bunwv click --selector "button.submit"(または --text)
  6. 次のスクリーンショットを取得する前に、bunwv wait-for --url "/next"(または wait-for "<selector>")を実行します
  7. 再度スクリーンショットを取得して確認します
  8. タスクが完了したら bunwv close を実行します

複数ステップのフローでは、bunwv batch(以下を参照)を優先してください。シーケンス全体が 1 つのプロセスで実行され、確認できる NDJSON トランスクリプトが返されます。

要素のクリック

click は多態的です。--selector、--text、--at のいずれか1つだけを使用してください:

bunwv click --selector "button.submit"
bunwv click --text "Sign In"                             # default: trimmed contains match
bunwv click --text "Sign In" --text-match exact
bunwv click --text "^Sign.+In$" --text-match regex
bunwv click --at 100,200

修飾キー、ボタン、クリック回数はそれぞれ独立しています:

bunwv click --selector "#ctx" --button right                # context menu
bunwv click --selector ".item" --count 2                    # double-click
bunwv click --selector "a" --mod Shift                      # shift+click
bunwv click --selector "a" --mod Meta --mod Shift           # cmd+shift+click
bunwv click --selector "button" --timeout 60000             # longer actionability wait

--text はデフォルトで前後の空白を除いた部分一致(大文字と小文字を区別)です。厳密な一致には --text-match exact を、正規表現パターンには --text-match regex を使用してください。--selector と --text はどちらも、アクション可能になるまで待機したうえで、ネイティブの isTrusted: true イベントを生成します。--at は待機をスキップします。

入力フィールドのクリアと編集

React の入力欄をクリアするために Cmd+A / Backspace を使用しないでください。React の状態が更新されません。clear を使用してください:

bunwv clear "input[name='email']"
bunwv click --selector "input[name='email']"
bunwv type "[email protected]"

既存の入力値を編集するときは、必ず clear、click、type の順に実行してください。

要素、URL、タイトルの待機

ページの変更を引き起こすアクションの後には wait-for を使用してください:

bunwv click --text "Save Changes"
bunwv wait-for-gone "[role='dialog']"                # wait for modal to close
bunwv screenshot

bunwv click --text "Edit"
bunwv wait-for "[role='dialog']"                     # wait for modal to appear
bunwv wait-for --url "/dashboard"                    # wait until URL contains substring
bunwv wait-for --title "Home"                        # wait until <title> contains substring

--url は location.href をポーリングし、--title は document.title をポーリングします。<selector>、--url、--title のいずれか1つが必須です。デフォルトのタイムアウトは10秒です。

存在の確認

手軽な確認には exists を使用してください(出力なし。存在する場合は終了コード0、存在しない場合は4):

bunwv exists "[data-loaded]"
if [ $? -eq 0 ]; then ... fi

evaluate "!!document.querySelector(...)" よりも exists を優先してください。トークン数が少なく、動作も明確です。

ページデータの抽出

evaluate は結果を JSON リテラルとして出力します。文字列は引用符付き、数値は引用符なし、オブジェクトは構造化 JSON として返されます:

bunwv evaluate "document.title"                              # "Example"
bunwv evaluate "document.querySelectorAll('.error').length"  # 3
bunwv evaluate "[...document.querySelectorAll('h2')].map(h => h.textContent)"

文(const、let、if など)は自動的に IIFE でラップされます。

フォームの送信

送信ボタンをクリックする代わりに submit を使用してください。form.requestSubmit() を使うため、React フォームで受け付けられます(JS の .click() は isTrusted:false を生成するため、多くの React ハンドラーで無視されます):

bunwv submit                                    # first form on page
bunwv submit --button "Save Changes"            # submit via a specific button
bunwv submit --form "form.edit-quote"           # target a specific form

送信後は、結果として DOM が変化するまで待機してください:

bunwv submit --button "Save Changes"
bunwv wait-for-gone "[role='dialog']"
bunwv screenshot

フォームへの入力

まず入力欄をクリックしてから、テキストを入力してください。フィールド間の移動には Tab を使用します:

bunwv click --selector "input[name='email']"
bunwv type "[email protected]"
bunwv press Tab
bunwv type "password123"
bunwv submit --button "Sign In"

認証情報は .env に記述します(Bun が自動的に読み込みます)。シェルは CLI 引数内の $VAR を展開します:

bunwv type "$TEST_EMAIL"

認証の保持

デーモンの再起動後も Cookie と localStorage を保持するには、--data-store を使用してください:

bunwv start --data-store ./bunwv-session

一度ログインすれば、以降のセッションでも認証状態が維持されます。

コンソール出力の取得によるデバッグ

ページのコンソール出力は自動的に取得されます。動詞の実行中に発生した console.error / console.warn のエントリは、動詞の応答とともに stderr に出力されます。バッファ全体を取得するには:

bunwv console                    # terse: "<seq> [<level>] <message>", one per line
bunwv console --clear            # print then clear
bunwv console --since 42         # only entries with seq > 42 (matches events cursor model)
bunwv --json console              # {messages:[…], cursor, truncated?, oldest?}

簡潔な出力では、各エントリが1行に収まるよう、メッセージ内の \n と \r がエスケープされます。バッファが空の場合は何も出力されません(終了コード0)。--since には、確認した最大の seq(各行の最初のフィールド)を指定してください。生のメッセージテキスト(複数行のスタックトレースなど)や切り詰めの通知が必要な場合は --json を使用します。

ナビゲーションと CDP イベント

ナビゲーションイベントとサブスクライブ済みの CDP イベントはリングバッファに格納されます。カーソルを使って取得してください:

bunwv events                          # full buffer, prints {events, cursor}
bunwv events --since 42                # only events with seq > 42

CDP イベントをサブスクライブします(Chrome バックエンドのみ。先にドメインを有効にしてください)。1回の呼び出しで複数のタイプを指定できます:

bunwv cdp Network.enable
bunwv cdp-subscribe Network.responseReceived Network.requestWillBeSent
bunwv navigate https://example.com
bunwv events --since 0                 # inspect events
bunwv cdp-unsubscribe Network.responseReceived Network.requestWillBeSent
bunwv cdp-subscriptions                # list active subscriptions, one per line

バッファ内で古いエントリが削除されている場合、events は "truncated":true,"oldest":<seq> を返します。

スクリーンショットのオプション

デフォルトでは、セッションごとのファイルに JPEG(品質80)を書き込み、そのパスを出力します。JPEG がデフォルトなのは、通常、同じ表示領域の PNG と比べてサイズが5~15分の1になり、スクリーンショットの反復処理のコストを大幅に抑えられるためです。

bunwv screenshot                                    # /tmp/bunwv-screenshot-<session>.jpg (JPEG @ q80)
bunwv screenshot --format png                       # opt back into PNG for pixel-exact comparisons
bunwv screenshot --format webp --quality 70         # smaller again at the cost of decode speed
bunwv screenshot --max-width 1024                   # cap longest side; aspect preserved; never upscales
bunwv screenshot --max-width 800 --max-height 600   # bound both axes
bunwv screenshot --out shot.jpg                     # write to a specific path
bunwv screenshot --out -                            # bytes to stdout
bunwv screenshot --encoding base64                  # base64 string to stdout

すべてのピクセルが不要な場合の低コストなプレビュー:

bunwv screenshot --metadata     # {"width":1920,"height":1080,"format":"png"} — size-check before Reading
bunwv screenshot --placeholder  # data:image/png;base64,... (tiny blur-up preview, no file)

--placeholder と --metadata はファイルを書き込む代わりに、構造化出力を stdout に出力します。また、互いに併用できません。--encoding shmem との併用もできません。

プラットフォームに関する注意: --format avif と --format heic のエンコードがサポートされるのは、Apple Silicon 搭載の macOS / Windows のみです。それ以外のプラットフォームでは、構造化エラーが返されます。ポータブルなコードには jpeg / webp / png を使用してください。

--encoding shmem(Kitty ターミナル)は {name, size} を出力し、呼び出し側がリンク解除できるよう POSIX shm セグメントを残します。この方法では Bun.Image パイプラインを経由しないため、--max-width / --max-height / --placeholder / --metadata は併用すると拒否されます。

任意の画像を変換する:bunwv image

スクリーンショットのループ外にあるローカル画像ファイル(アップロード、ダウンロードしたアセット、フィクスチャ)には、bunwv image が CLI プロセス内で直接 Bun.Image を実行します。デーモンもセッションも必要ありません。

bunwv image input.png                                  # input.jpg (jpeg @ q80, same dir)
bunwv image input.png --out small.webp --max-width 512 # webp, capped at 512 wide, aspect preserved
bunwv image input.png --resize 200x200                 # explicit resize (may distort if aspect differs)
bunwv image input.png --rotate 90                      # rotate 90/180/270
bunwv image input.png --flip                           # vertical flip; --flop is horizontal
bunwv image input.png --metadata                       # {"width","height","format"} JSON on stdout
bunwv image input.png --placeholder                    # data: URL on stdout

--format が指定されていない場合、出力形式は --out の拡張子から推測されます。それ以外の場合は JPEG がデフォルトです。--out を省略すると、結果は入力ファイルと同じ場所に新しい拡張子で書き込まれます。

Chrome バックエンドと CDP

macOS では WebKit がデフォルトです。Linux/Windows では Chrome が自動的に使用されます。次のように、どこでも上書きできます。

bunwv start --backend chrome
bunwv start --chrome-path /path/to/chromium
bunwv start --chrome-argv '["--headless=new"]'
bunwv start --chrome-url ws://127.0.0.1:9222/devtools/browser/<id>   # attach to an existing Chrome

生の CDP 呼び出し(Chrome のみ):

bunwv cdp "Page.getLayoutMetrics"
bunwv cdp "Runtime.evaluate" --params '{"expression": "1+1"}'
bunwv cdp "Emulation.setDeviceMetricsOverride" --params '{"width":375,"height":812,"deviceScaleFactor":2,"mobile":true}'

WebKit バックエンドでは CDP を使用できません。

クラッシュするバックエンドのデバッグ

バックエンドプロセスの標準入出力をデーモンの標準入出力にルーティングします(人間によるデバッグ専用。エージェントには不要です)。

bunwv start --backend chrome --chrome-stderr inherit
bunwv start --webkit-stderr inherit

バッチモード

bunwv batch は、多数のコマンドを単一のプロセスで実行します。動詞ごとにソケットの往復は 1 回で、コマンドごとの Bun 起動はありません。標準入力の各行は引数の JSON 配列で、各応答は標準出力に NDJSON エンベロープとして出力されます。batch のフラグ(例:--session)は、その行で個別に指定されない限り、すべての行に引き継がれます。

$ cat <<'EOF' | bunwv batch --session cmais --keep-going
["navigate","http://localhost:3000/login"]
["click","--selector","input[name='email']"]
["type","[email protected]"]
["press","Tab"]
["type","hunter2"]
["submit","--button","Sign In"]
["wait-for","--url","/dashboard"]
["screenshot"]
EOF
{"argv":[...],"ok":true,"exitCode":0}
{"argv":[...],"ok":true,"exitCode":0}
...

--keep-going を指定すると、いずれかの行が失敗してもリスト全体を実行します。失敗した行があればプロセスは終了コード 6(batch-partial)で終了し、すべて成功した場合は 0 で終了します。--keep-going を指定しない場合は、失敗した行の終了コードで終了します。--file <path> を指定すると、標準入力の代わりにファイルから読み込みます。

stdout フィールドにはコマンドの簡潔な出力が含まれます(例:evaluate の場合は "\"Example Domain\"")。stdoutBytes は、screenshot --out - などのバイナリ出力を Base64 で表したものです。

エラーからの復旧

コマンドが失敗するかタイムアウトした場合:

  1. スクリーンショットを撮ってページの状態を確認します
  2. bunwv console を実行して、キャプチャされたエラーを確認します
  3. bunwv events --since 0 を実行して、ナビゲーション/CDP イベントを確認します
  4. bunwv evaluate を実行して DOM を調べます
  5. デーモンに接続できない場合(終了コード 5)、bunwv start を実行します。データストアには認証情報が保持されています

ソケットの権限

各セッションの Unix ソケット(/tmp/bunwv-<session>.sock)と PID ファイルは chmod 0600 に設定されており、デーモンを起動したユーザーだけが接続できます。共有マシン(コンテナー、ビルド用マシン)では、他のローカルユーザーがブラウザーセッションを操作するのを防げます。

既知の制限事項

  • macOS:WebKit がデフォルトです(依存関係なし)。Linux/Windows:Chrome が自動検出されます。--backend で上書きできます。
  • click --selector/--text は、操作可能な状態(表示されている、安定している、遮られていない)になるまで自動的に待機します。 WebView のデフォルトは 30 秒です。--timeout で上書きできます。
  • --text のデフォルトは、前後の空白を除いた部分文字列一致(含む)です。 --text-match exact|regex で変更できます。
  • --at は操作可能になるまでの待機をスキップします — 正確な座標を把握している必要があります。CSS やテキストでうまくいかない場合は、evaluate と getBoundingClientRect() を使用してください。
  • React の入力欄では clear が必要です — Cmd+A/Backspace では React の内部状態は更新されません。
  • CDP は Chrome のみ対応です。 WebKit では bunwv cdp と bunwv cdp-subscribe は拒否されます。
  • イベントバッファー:1000 件または 10 MB のいずれかに達した時点で上限になります。古いエントリーは通知なしで破棄されます。見落としたイベントがある場合、events --since は truncated を報告します。

コメント