cockpit browser
タスクのアプリ内ブラウザーでWebページを開き、人とエージェントが同じタブを安全に確認・操作・検証する方法です。
最新バージョンでは、画面や操作が一部異なる場合があります。
cockpit browserは、タスク単位のアプリ内ブラウザーで実際のWebページを開き、DOM、画像、操作結果を確認するための正式な操作面です。表示専用ではなく、クリック、入力、選択、アップロード、貼り付け、キー操作、スクロールまで行えます。
HTML Surfaceはエージェントが作ったレポートを表示する面です。外部サイトの移動、ログイン、フォーム操作、Web UI検証にはアプリ内ブラウザーを使います。
人とエージェントが同じページを使う
各タブには正本となるページインスタンスが一つあり、利用者がサイドパネルで見るページとエージェントが操作するページは同じです。タスク、タブ、右サイドパネルを切り替えるとページはウィンドウから外れますが、再読み込みされません。未送信フォーム、スクロール位置、SPA状態、popupやOAuthの文脈を維持します。
サイトへ送るUser-AgentはElectronの製品tokenを含まず、top pageと別processで動くcross-origin iframeを含むすべてのframeで同じ値を使います。frame間でbrowser情報を比較する認証やbot判定にも、一つのブラウザーとして応答します。
ブラウザーsessionとnavigation履歴は、タスクの完了・再開とアプリ再起動を越えて保存されます。再起動後のフォーム値とスクロール位置はbest effortで復元され、OSの資格情報ストアを利用できる場合は保存データを暗号化します。
アプリ再起動後、まだ使っていない保存済みタブはrendererを作らず、必要になるまで読み込みません。tabsでloaded: falseかつrendererResponsive: falseと表示されるのは停止ではなく、未読み込みの状態です。そのタブを選択する、サイドパネルへ表示する、またはtab IDを指定してコマンドを実行すると読み込みます。
パネルを隠したparked tabも表示せずに操作できます。macOSのSpaceを切り替えたり、黒い独立ウィンドウを表示したりせず、同じページへ入力します。
ダイアログなどのCockpitのオーバーレイがブラウザー領域と重なる間は、正本のページを一時的にparkし、空白の代わりに直前の静止snapshotを表示します。snapshotは操作できず、表示後のページ更新も反映しません。オーバーレイを閉じると同じlive pageへ戻り、フォームやページ状態を維持します。短時間でsnapshotを取得できなかった場合だけ、一時的に非表示であることを示す案内を表示します。
PWAからホストのタブを確認する
PWAのタスクパネルでCockpit Browserを選ぶと、そのタスクに割り当てられたBrowser Identity内のsessionとtabを選び、ホスト上の現在のviewportを静止画像として確認できます。選べるIdentityはタスクへ割り当てられたものに限ります。PWA側でパネルやタブを切り替えても、Desktopの選択中パネル、ホストページのnavigation、tabは変更しません。
表示中かつ接続中でPWAがforegroundにある間は、前回の取得完了から10秒後に更新します。「更新」はその場のviewportを取り直します。未読み込みの保存済みtabはPWAから起動せず、ホストで開くよう案内します。画像には取得時刻があり、切断中、取得失敗、20秒以上更新できない場合は古い状態として表示します。
「ホストのタブをスクロール」の上下左右は、ホストページ自体をviewportのおよそ80%ずつ動かしてから新しい画像を取得します。この操作はDesktop側のスクロール位置にも影響しますが、linkの選択、フォーム入力、送信は行いません。「拡大」は受信画像を原寸で表示し、PWA内だけでパンできます。これは10秒ごとの静止previewであり、動画配信や完全なremote browser操作ではありません。画像内の文字はscreen readerへテキストとして公開されません。
PWAへ渡す画像はJPEGで、最大1280px、base64化前256KiBまでに制限し、ディスクやPWAのbrowser storageへ保存しません。各要求はtask、割り当て済みIdentity、session、tabの所属を取得前後に検証します。metadataはtitleとoriginに限定し、URLのcredential、path、query、fragment、data URLのpayloadや、一般browser RPC、storage export、ローカルscreenshot pathは公開しません。
ページを開く
Desktopのアプリ内ブラウザーにある「検索または URL を入力」へキーワードを入力すると、Google検索を開きます。ドメイン名やIPアドレスはURLとして開き、localhost、127.x.x.x、[::1]はHTTP、それ以外のhostはHTTPSを補います。https:、file:、about:など明示したschemeはそのまま使います。空白を含む通常の文字列は、schemeのような接頭辞を含んでいても検索語として扱います。この検索判定は画面のアドレスバーだけに適用され、CLIのopenとgotoにはURLを渡します。
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座標で操作します。
開いているタブと音声を管理する
設定 → BrowserでタブとIdentityをまとめて管理します。左側の「すべて」またはIdentityを選ぶと、現在表示していないものも含めてタブ一覧を絞り込めます。Identityを選ぶと、タブ一覧の上に名前・色の編集、データ消去、削除の操作も表示されます。各タブの行でタスク、Identity、favicon、タイトル、URL、音声状態を確認できます。タスク名を選ぶと、そのタスクに移動してタブを表示します。ミュート、ミュート解除、閉じる操作はタブごとに適用します。
表示中のブラウザーパネルでも、音声を再生している現在のタブをミュートまたは解除できます。パネル、設定、CLIの操作は同じタブ単位の状態を更新します。
CLIのcockpit browser tabsではaudibleとmutedを確認できます。cockpit browser mute <tabId>またはcockpit browser unmute <tabId>は、タブを表示せずに操作できます。ミュート設定はタブ単位で保存され、アプリの再起動やレンダラーの再作成後も維持されます。タブを閉じると設定は破棄されます。ミュートしてもページは閉じず、音声以外の動作は停止しません。エージェントの操作には引き続きBrowser Identityのアクセス境界が適用され、Desktopの一覧表示によって別のIdentityへのアクセスが許可されることはありません。
「すべて」と各Identityのタブ一覧には「全てのタブを閉じる」ボタンがあります。確認ダイアログで対象とタブ数を確認して実行します。キャンセルした場合は何も閉じません。IdentityやCookie・ログイン情報は残りますが、未保存の入力内容は失われます。確認後に新しく開いたタブは対象外です。
CLIではcockpit browser tab close-all --confirmを使い、特定のIdentityだけを対象にするには--browser-identity <名前またはID>を追加します。タスク内で実行した場合は、そのタスクのセッションと割り当て済みIdentityの範囲に制限されます。タスク外では、Identityを指定しない場合にすべてのIdentityのタブを対象にします。
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
ログインと安全境界
アプリ内ブラウザーは、通知、位置情報、クリップボードの読み取り・書き込みなどのサイト権限を、Cockpitの確認画面を出さずに既定で許可します。OSやWeb API側の制約は引き続き適用されます。カメラ・マイクを含むメディア取得、画面収録、全画面化、自動全画面化、外部アプリを開く権限、キーボードロック、旧式の同期クリップボード読み取りは拒否します。信頼できるサイトだけを開いてください。この方針はすべてのBrowser Identityに共通で、Identityの分離によってサイト権限が制限されるわけではありません。
CookieやlocalStorageなどの分離、task・Autorunへの割り当て、system browserからのsession取込、消去と削除はBrowser Identityを参照してください。
エージェントがcockpit secret requestを使うと、Desktopの専用ウィンドウとAskタブ、またはHTTPS接続のPWAの「受信箱」に、表示中のパスワード欄へ一度だけ入力する依頼が届きます。PC、タスク、目的、Identity、実際のURLと入力欄を確認してから、利用者自身が値を入力します。Cockpitは指定された欄だけを埋め、送信ボタンを押しません。値をCLIやタスクへ返すこともありません。入力が完了、失敗、取消、または期限切れになると入力画面はすぐに消えます。利用条件、期限、保存と再試行の境界はセキュリティとデータを参照してください。
パスキーは署名済みmacOS版でTouch ID、WindowsでWindows Helloを利用できます。macOSのCockpitで使えるのは、アプリ内ブラウザーから登録したパスキーです。Safari、Chrome、iCloudキーチェーンで登録済みのパスキーを直接利用することはできません。
macOSとLinuxでは、USBセキュリティキーは限定的にしか使えません。PINの入力を求めない要求(サイトがallowCredentialsを指定する2段階認証など)であればキーをタッチするだけで完了しますが、「保存済みのパスキーでログイン」はブラウザーがユーザー検証を必須へ引き上げるため必ず失敗します。PIN設定済みのキーへの新規パスキー登録も同様で、スマートフォンやタブレットとの連携は利用できません。WindowsはすべてのトランスポートをOSのWebAuthnダイアログが扱うため、セキュリティキーやスマートフォンのパスキーも動作する見込みですが、まだ確認できていません。
Touch IDに一致するパスキーがない場合、ブラウザーパネルは理由と、新しいパスキーの登録、パスワード、cockpit browser import-sessionという代替手段を表示します。cockpit browser diagnosticsでは直近の試行をno-matching-credentialとして確認できます。macOSのimport-sessionはChrome、Brave、Edge、Arc、Vivaldi、Opera、Firefoxから対応するログイン状態を取り込む機能で、パスキー自体は取り込みません。
Linuxにはplatform authenticatorがないため、上記の制約付きのsecurity key、またはpasswordを使います。promptが出ない場合や失敗した場合はcockpit browser diagnosticsでplatform authenticatorと直近のWebAuthn試行を確認します。NotAllowedErrorは原因別に記録され、discoverable-credential-unavailableは保存済みパスキーでのログインが未対応であること、user-verification-unavailableは受け取れないPIN/ユーザー検証を求められたこと、not-allowedはキャンセル・タイムアウト・応答できる認証器がなかったことを表します。
外部ブラウザーでログインを終えてcockpit browser import-sessionで取り込む方法もありますが、これはパスキー認証への対応ではなく、取り込めるのはCookieとlocalStorageだけです。サイトによってはログイン状態が復元されません。
アプリ内ブラウザーからOSへ渡せる外部linkはHTTPとHTTPSです。mailtoは利用者自身の操作と明示確認が揃った場合だけ開き、ほかのschemeは拒否します。エージェントの自動操作は利用者自身の操作として扱われません。