cdp について
cdpは、ページの確認や制御された操作を行うための、browser-harness-jsを基盤とするブラウザー自動化スキルです。対象を限定したスナップショットやロケーター、操作検証を備え、許可確認と自動再試行を行わない設計を示します。
主な機能
- 01ブラウザー接続と許可対象の選択
- 02ページスナップショットと差分の取得
- 03ロケーターによるガード付き操作
- 04操作結果の検証と状態の再読み取り
- 05明示的なCDP呼び出しとページ管理
活用シーン
- 01ページ構造や操作状態の確認
- 02許可されたオリジン上の入力やクリック
- 03操作後のページ変化の検証
- 04古い対象や不明な結果の診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ monotykamary/ browser-harness-js --skill cdpインストール後、Claude Code で/cdpを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlextension/manifest.jsonsw.jsinteraction-skills/accessibility-tree.mdagent-operating-loop.mdagent-signals.mdcaptcha.mdconnection.mdcookies.mdcoordinate-fallback.mdcross-origin-iframes.mddialogs.mddownloads.mddrag-and-drop.mddropdowns.mdiframes.mdjson-navigation.mdlifecycle-readiness.mdmake-video.mdmedia-capture.mdnetwork-requests.mdprint-as-pdf.mdrecord-cross-tab.mdreverse-engineer-api.mdrich-editors.mdscreenshots.mdscrolling.mdshadow-dom.mdsnapshot.mdtabs.md詳細
Browser / Page / Locator
browser-harness-js は、永続的な Node デーモン内で JavaScript を実行します。一連の処理には、引用符で囲んだヒアドキュメントを使用してください。トップレベルの await は使用できますが、複数の文を含むスニペットには return が必要です。呼び出し間で状態を保持するには globalThis に保存してください。ローカルの const バインディングは保持されません。返された文字列はそのまま出力され、オブジェクトは JSON として出力されます。コンソール出力は CLI の応答ではなく、デーモンのログに出力されます。
接続とスコープ
browser-harness-js <<'EOF'
await browser.connect(); // or { port: 9222 } / { wsUrl: 'ws://…' }
return await browser.tabs(); // inspect; never silently pick tabs[0]
EOF
認可された対象には明示的な許可リストを指定して接続するか、バックグラウンドタブを開いてください。
globalThis.page = await browser.attach(authorizedTargetId, {
allowedOrigins: ['https://example.com']
});
// Alternative: browser.open('https://example.com', { allowedOrigins: […] })
return await page.snapshot();
オリジンは、信頼できないページコンテンツではなく、ユーザーまたはホストの権限に基づきます。オリジンは HTTP(S) の完全一致で 1〜32 個指定し、パスやワイルドカードは使用できません。ページ操作はセッションと接続世代を固定し、変更可能なアクティブ対象は使用しません。browser.connect() は OS のキー入力を送信せず、ブラウザーをアクティブ化しません。
読み取り、操作、検証
return await page.getByRole('textbox', { name: 'Search' }).fill('browser harness');
return await page.getByRole('button', { name: 'Search' }).click({
verify: snapshot => snapshot.tree.includes('Search results')
});
各操作では対象を厳密に 1 つ解決し、その状態を確認してから、識別情報、オリジン、鮮度、操作可能性を再検証したうえで一度だけ操作し、結果を読み返します。デフォルトでは、信頼済みの CDP マウス/キーボード入力を使用します。画面外にあるサポート対象には、ガード付きのスクロールで表示した後、新たに検証します。座標を使った盲目的なクリックは行いません。操作の自動再試行や、生の入力へのフォールバックはありません。
| API | 意味 |
|---|---|
page.snapshot(options?) | {id,url,title,tree,diff,truncated,omissions}。参照は内部で管理されます |
page.locator('sAb3dEf6hJk9m_2e9') | このページの最新スナップショットに表示された参照です。生のバックエンド ID ではありません |
page.locator('#search') | メインフレーム内の標準 CSS。アクセシビリティ対応要素が厳密に 1 つ必要です |
page.getByRole('button', {name:'Save'}) | デフォルトではネイティブ AX のロール/名前に完全一致します。exact:false では、大文字と小文字を区別する名前の部分一致を使用します |
getByRole(…, {context:'group: Outbound'}) | 名前付きの最も近い非コントロール祖先で対象を絞り込みます |
locator.click() / .fill(text) / .press(key) | ガード付きクリック、値全体の置換、または許可リスト内のキー入力 |
locator.selectOption(labelOrIndex) | ネイティブの select にある、一意なオプションラベルまたは 0 始まりのインデックスを指定します。HTML の value ではありません |
locator.scrollIntoView() | サポート対象をガード付きでスクロールします |
page.frames() / page.frame(frameId).snapshot() | 許可された同一プロセスおよびプロセス間のフレームを検出/読み取ります |
page.goto(url) | 許可リスト内のナビゲーションです。期限内に読み込みを待機し、操作のレシートを返します |
page.info() / page.signals() | スコープ内の情報/ダイアログ状態と、読み出し可能な上限付きイベントダイジェストを返します |
page.close() / page.dispose() | タブを閉じる/タブを閉じずにラッパーと所有するアタッチメントを解放します |
fill と selectOption は、新しいコントロール値を自動的に検証します。クリックやキー入力の目的を確認するには、同期的な verify(snapshot) 判定関数を指定するか、確実な読み戻しを行ってください。結果には status、reason、verified(true、false、null のいずれか)が含まれ、通常は新しい snapshot も含まれます。読み取りに失敗した場合は verificationError に示されます。executed が意味するのは入力が送信されたことだけであり、タスクの成功ではありません。
stale:新しい証拠を取得して再検討します。blocked/オリジン拒否:停止するか、権限を取得します。生の CDP を使って回避してはいけません。outcome_unknown:まず状態を確認します。効果を自動的に再実行してはいけません。
ページ操作およびロケーター操作では、{timeoutMs, signal} を指定できます。デフォルトの期限は 10 秒、最大は 60 秒で、キュー内の待ち時間も含みます。期限切れの呼び出しは以降の送信を停止しますが、すでに送信された入力を取り消すことはできません。保留中のトランスポート呼び出しがある場合、解決するまでキューは隔離された状態に保たれます。
スナップショットと制限
return await page.snapshot({ interactive: true });
// Or { selector: '#results' }, { ref: 'sAb3dEf6hJk9m_2e9' }, { frameId }, { maxDepth: 4 }
フルスナップショットでは、テーブル/行/セルの関係、値、名前付きコンテキスト、コンテンツが保持されます。インタラクティブモードでは読み取りテキストが省略されます。参照は、次のスナップショット、raw 呼び出し、アクション、またはドキュメントの変更時に期限切れになります。推測したり、バックエンド ID に変換したり、古い参照を再利用したりしないでください。新しいロール/CSS ロケーターは改めて解決されます。
差分は、一致するスナップショット範囲ごとに管理され、表示される参照の変動は無視されます。最初の差分はツリー全体です。変更がない場合は (no changes) が返されます。深さ制限と省略されたフレームは明示されます。文字数の上限を超えると、ツリーを通知なく切り詰めて返すのではなく、エラーが発生します。デフォルトの上限は、50,000 文字、深さ 50、32 フレームです。snapshot.md を参照してください。
スナップショットで読み取れる範囲は、アクションエンジンがサポートする範囲より広い場合があります。フレーム内のアクション、閉じたシャドウルート内のアクション、キャンバス、サポートされていないカスタムウィジェットの操作は、フェイルクローズで失敗し、通知なく別の方法に振り分けられることはありません。これは定義されたページ/ロケーター API であり、Playwright と完全な互換性があるわけではありません。セレクター DSL、nth-match フォールバック、自動待機/再試行ループ、任意のリッチエディターへの入力には対応していません。機密性の高いコントロールはガードによって除外され、保護対象/パスワードのような AX 値はマスキングされますが、これは DLP ではありません。
Jev を含む、範囲が限定された判断
globalThis.seen = await page.observe({ maxElements: 64 });
return seen;
// After an authorized decision selects an offered target and operation:
// return await page.act(seen, {targetId: chosenId, operation:'click'}, {verify});
観測情報は、不透明な一度限りのハンドル、操作、コンテキスト、リビジョンを提供します。スナップショット参照は確認した内容を示しますが、観測ハンドルが許可するのは再検証済みの操作に限られます。これらは相互に置き換えられません。
page.waitForChange(seen.revision, {waitMs:5000}) は {changed,observation} を返します。変更があっただけでは、目標が達成されたことの確認にはなりません。操作コントラクト を参照してください。
明示的な raw CDP
既知の決定論的な操作や、サポートされていない操作には、同等の権限チェックを行う page.cdp('Domain.method', params) を使用してください。これは観測情報を無効にし、ガード付き API のオリジンポリシーを適用しません。型付きの session.Domain.method、cdp(sessionId,method,params)、CDP、Session、listPageTargets、detectBrowsers、resolveWsUrl、ext は、既存の raw スクリプトで引き続き利用できます。並行処理では session.use() を呼び出さないでください。明示的なセッション ID で振り分けてください。
レシピ:接続、
ライフサイクル、
シグナル、
AX の内部、
リッチエディター、
スクリーンショット、
記録。記録用グローバルは引き続き
startRecording、stopRecording、recordingStatus です。まず同意を求めてください。
更新後に browser-harness-js --version と --status の結果を照合してください。
--restart は SDK ファイルを再読み込みしますが、デーモンのグローバルとアタッチメントは破棄されます。再接続して再アタッチしてください。古いデーモン を参照してください。