cockpit browser
タスクのアプリ内ブラウザーでWebページを開き、人とエージェントが同じタブを安全に確認・操作・検証する方法です。
cockpit browserは、タスク単位のアプリ内ブラウザーで実際のWebページを開き、DOM、画像、操作結果を確認するための正式な操作面です。表示専用ではなく、クリック、入力、選択、アップロード、貼り付け、キー操作、スクロールまで行えます。
HTML Surfaceはエージェントが作ったレポートを表示する面です。外部サイトの移動、ログイン、フォーム操作、Web UI検証にはアプリ内ブラウザーを使います。
人とエージェントが同じページを使う
各タブには正本となるページインスタンスが一つあり、利用者がサイドパネルで見るページとエージェントが操作するページは同じです。タスク、タブ、右サイドパネルを切り替えるとページはウィンドウから外れますが、再読み込みされません。未送信フォーム、スクロール位置、SPA状態、popupやOAuthの文脈を維持します。
ブラウザーsessionとnavigation履歴は、タスクの完了・再開とアプリ再起動を越えて保存されます。再起動後のフォーム値とスクロール位置はbest effortで復元され、OSの資格情報ストアを利用できる場合は保存データを暗号化します。
アプリ再起動後、まだ使っていない保存済みタブはrendererを作らず、必要になるまで読み込みません。tabsでloaded: falseかつrendererResponsive: falseと表示されるのは停止ではなく、未読み込みの状態です。そのタブを選択する、サイドパネルへ表示する、またはtab IDを指定してコマンドを実行すると読み込みます。
パネルを隠したparked tabも表示せずに操作できます。macOSのSpaceを切り替えたり、黒い独立ウィンドウを表示したりせず、同じページへ入力します。
ダイアログなどのCockpitのオーバーレイがブラウザー領域と重なる間は、正本のページを一時的にparkし、空白の代わりに直前の静止snapshotを表示します。snapshotは操作できず、表示後のページ更新も反映しません。オーバーレイを閉じると同じlive pageへ戻り、フォームやページ状態を維持します。短時間でsnapshotを取得できなかった場合だけ、一時的に非表示であることを示す案内を表示します。
ページを開く
cockpit browser open https://example.com --json
cockpit browser tabs --summary --json
cockpit browser show --json
Cockpitタスク内では、sessionやtask IDを省略すると現在のタスクを使います。openは直近のsessionと選択中のタブを再利用します。未送信内容を残す場合は--new-tabを付けます。
cockpit browser open https://example.com/form --new-tab --json
cockpit browser goto <tabId> https://example.com/next --json
cockpit browser reload <tabId> --json
tabs --summaryは、選択状態、本文先頭のpreview、読み込み時間、renderer応答、直近のnavigation errorを返します。popupまたはページ側のwindow.close()もCockpitのタブ状態へ反映されます。
snapshotとscreenshotを使い分ける
cockpit browser snapshot <tabId> --json
cockpit browser snapshot <tabId> --wait-for-text "Ready" --timeout 10000 --json
cockpit browser screenshot <tabId> --full-page --output ./page.png --json
snapshotは表示テキスト、link、button、input、role、accessible name、selectorを返します。操作対象を特定し、状態を機械的に確認するときに使います。screenshotは見た目、配置、画像、canvasなどの視覚確認に使います。
screenshot --full-pageは、windowをスクロールする長いページを最大4096 CSS pxの区画に分けて結合します。document自体がスクロールせず内部のoverflow領域がスクロールするページでは、最も長い一つのscroll containerを動かして結合し、終了後にscroll位置を戻します。結果のdocumentHeight、capturedHeight、scrolledElementで範囲を確認し、20,000 px上限、同じframeの反復、複数または入れ子のscroll領域などで全体を取得できない場合はwarningを確認します。
locatorはopen shadow rootをたどります。通常のCSS selectorに加え、host >>> innerでshadow境界を明示できます。closed shadow rootはページ外から参照できないため、必要ならscreenshot座標で操作します。
main frameのJavaScriptを実行する
DOMに表示されないframework state、localStorage、要素のpropertyなどを確認するときはevaluateを使います。
cockpit browser evaluate <tabId> --expression "document.title"
cockpit browser evaluate <tabId> --expression "JSON.parse(localStorage.getItem('draft')).body" --json
cat inspect.js | cockpit browser evaluate <tabId> --stdin
JavaScriptはタブのmain frameだけで実行され、iframeには入りません。top-levelのawaitを利用でき、Promiseは完了まで待機します。結果はJSONへ直列化できる値である必要があり、DOM node、function、symbol、循環参照は返せません。実行にuser gestureは付かないため、利用者操作を必要とするWeb APIの代わりにはなりません。長いscriptは--expression-fileまたは--stdinで渡します。
意味のある名前で操作する
cockpit browser click <tabId> --role button --name "Submit" --json
cockpit browser type <tabId> --role textbox --name "Email" --text "name@example.com" --json
cockpit browser select <tabId> --selector "#plan" --option-text "Team" --json
cockpit browser scroll-into-view <tabId> --role button --name "Continue" --json
可能なら--roleと--nameを使い、次に安定したCSS selector、最後にviewport座標を使います。accessible nameはaria-labelledby、aria-label、label、alt、value、本文、titleから計算されます。既定は大文字・小文字を区別しない完全一致で、--name-match prefix|containsを明示できます。
候補がない、複数ある、すべて非表示の場合は、それぞれbrowser_target_not_found、browser_target_ambiguous、browser_target_not_visibleとして候補情報を返します。曖昧なまま最初の候補を操作しません。
操作前にCockpitは、windowとscroll可能な祖先を横方向・縦方向の両方へ動かして対象を表示します。大きなcard linkの本文など、指定した子要素の中央がlink本体に当たらない場合は、最も近いclick可能な祖先を保ったまま複数の安全な点を試します。modalやbannerなど無関係な要素に覆われている場合はクリックせず、browser_click_target_unreachableと候補点の診断を返します。
操作結果を事後条件で検証する
cockpit browser click <tabId> --role button --name "Save" \
--wait-for-text "Saved" --timeout 10000 --json
cockpit browser click <tabId> --selector "#checkout" \
--wait-for-url "*/complete" \
--wait-for-response-url "*/api/orders*" \
--wait-for-response-status "200-299" --json
クリック結果のchangedとchangeSignalsは、URL、DOM、フォーム値など観測できた変化を示します。changed: falseは成功の証明ではありません。URL、表示テキスト、selector状態、新しいタブ、通信statusなど、依頼の成功条件に合うpostconditionを付けます。
eventDispatched: falseでもinputDelivered: trueの場合、イベント伝播が止められていても操作は作用した可能性があります。二重送信を避けるため、同じクリックをすぐ繰り返さず、snapshotで現在のページ状態を確認します。
通信の検証結果はmethod、status、query値とhashをmaskしたURLだけを返します。request・responseのbody、header、payloadは返しません。
入力、貼り付け、アップロード、dialog
cockpit browser paste <tabId> --selector "[contenteditable]" --text "長い本文" --json
cockpit browser upload <tabId> --role button --name "Attach a file" --path ./build.zip --json
cockpit browser upload <tabId> --click-role button --click-name "画像を追加" --path ./cover.png --json
cockpit browser upload <tabId> --await-chooser --path ./cover.png --json
cockpit browser press <tabId> --selector "#search" --key Enter --json
cockpit browser dismiss-dialog <tabId> --button-text "OK" --json
typeは対象の値を置き換えて最終値を検証します。pasteは実際のclipboard paste eventを送り、指定テキストが反映されたかを検証して、元のclipboard表現を復元します。clipboardにテキストがなく画像だけがある場合は、その画像をPNGとしてpaste eventのfilesとitemsへ渡し、ページが画像を受け取ったかと画像要素が表示されたかを報告します。受信後2秒以内に表示を確認できなければverified: falseとwarningを返すため、再貼り付けする前にページを確認します。
uploadはOSのfile pickerを開かず、file inputまたはそれを含むdropzoneへファイルを設定します。click handler内で一時的なfile inputを作るページでは、--click-*でchooserを開くcontrolを指定するか、直前のclickが記憶したchooserを--await-chooserで受け取ります。chooserは最大60秒だけ記憶され、navigationまたはchooserを開かない次のclickで破棄されます。showOpenFilePickerのようにinput要素を持たないchooserには対応しません。結果のtargetとchooserで実際にファイルを渡した対象を確認します。
dismiss-dialogはJavaScript dialogを先に扱い、なければ表示中のHTML dialogを操作します。--rejectで否定側を選べます。送信、購入、公開、削除など外部状態を変える操作は、postconditionが設定できても利用者の承認境界を越えません。
読み込み不良とrenderer停止を復旧する
tabsのhealthで次を区別します。
| 値 | 意味 |
|---|---|
loadingDurationMs |
Chromiumが読み込み中と報告している時間 |
rendererResponsive |
ページrendererが短いJavaScript pingへ応答したか |
lastNavigationError |
直近のmain-frame読み込み失敗 |
siteが遅いだけなら待機し、navigation errorならURLや接続を確認します。rendererが停止した場合は、同じtab ID、URL、session、Browser Identityを保ったままrendererだけを作り直せます。
cockpit browser tab recreate <tabId> --json
ログインと安全境界
CookieやlocalStorageなどの分離、task・Autorunへの割り当て、Chrome session取込、消去と削除はBrowser Identityを参照してください。
パスキーは署名済みmacOS版でTouch ID、WindowsでWindows Helloを利用できます。macOSのCockpitで使えるのは、アプリ内ブラウザーから登録したパスキーです。Safari、Chrome、iCloudキーチェーンで登録済みのパスキーを直接利用することはできません。
Touch IDに一致するパスキーがない場合、ブラウザーパネルは理由と、新しいパスキーの登録、パスワード、cockpit browser import-sessionという代替手段を表示します。cockpit browser diagnosticsでは直近の試行をno-matching-credentialとして確認できます。import-sessionはmacOSのChromeからログイン状態を取り込む機能で、パスキー自体は取り込みません。
Linuxにはplatform authenticatorがないため、roaming security keyまたはpasswordを使います。promptが出ない場合はcockpit browser diagnosticsでplatform authenticatorと直近のWebAuthn試行を確認します。
アプリ内ブラウザーからOSへ渡せる外部linkはHTTPとHTTPSです。mailtoは利用者自身の操作と明示確認が揃った場合だけ開き、ほかのschemeは拒否します。エージェントの自動操作は利用者自身の操作として扱われません。