x.com (Twitter) のツイート一覧でブックマークボタンの隣に送信ボタンを注入し、クリックするとそのツイートの URL と投稿時刻を、popup で登録した有効な Discord webhook 全てへ転送する Chrome 拡張 (Manifest V3) です。
pnpm installpnpm install の prepare スクリプトで husky の git hooks・WXT の型生成・Panda CSS のコード生成が走ります。
| コマンド | 内容 |
|---|---|
pnpm dev |
Chrome を起動し拡張を読み込んだ状態で開発 (WXT dev サーバ + HMR) |
pnpm build |
本番ビルドを .output/chrome-mv3/ に出力 |
pnpm zip |
Chrome Web Store 提出用に .output/ を zip 化 |
pnpm lint |
oxlint + oxfmt --check |
pnpm fmt |
oxlint --fix + oxfmt (フォーマット適用) |
pnpm typecheck |
@typescript/native-preview (tsgo) による型チェック |
pnpm test |
vitest (unit; node 環境) |
pnpm test:browser |
vitest browser mode (Playwright provider; コンポーネント/DOM 抽出のテスト) |
実装をする前にライブラリの挙動を確認する場合は context7 や Web 検索で調査してから進めてください。
- unit (
pnpm test):shared/**/*.test.tsの pure function / RPC route テスト。vitest.config.tsは**/*.browser.test.*を除外 - browser (
pnpm test:browser):vitest.browser.config.ts(Playwright provider)で popup コンポーネントの振る舞いテストと、x.com の DOM fixture を組み立てて検証するshared/tweet/extract.browser.test.tsを実行
- 拡張アイコンをクリックして popup を開く
- 「ADD WEBHOOK」フォームに名前と Discord webhook URL (
https://discord.com/api/webhooks/...) を入力して追加 - リストの各行でトグルボタンにより有効/無効を切り替え、ゴミ箱ボタン+確認ダイアログで削除できる
- x.com のツイート一覧を開くと、各ツイートのブックマークボタンの隣に送信ボタンが表示される
- 送信ボタンを押すと、そのツイートの URL と投稿時刻 (
<t:unix:f>形式) が、有効な webhook 全てに Discord メッセージとして送信される。ボタンは送信中→成功/エラーの状態を短時間表示し、詳細はブラウザの console に出力される
popup / content script は runtime.sendMessage 経由で background service worker 上の Hono app に RPC を投げる構成です(hc<AppType> + custom fetch でトンネルする実装は .claude/skills/hono-rpc-runtime-messaging/SKILL.md を参照)。popup の UI・トークンは .claude/skills/cannelloni-design-system/SKILL.md の Cannelloni デザインシステムに従っています。
┌──────────────────────────┐ ┌───────────────────────┐
│ content script (x.com) │ │ popup (React) │
│ bookmark 隣にボタン注入 │ │ webhook 管理 │
└───────────┬──────────────┘ └──────────┬────────────┘
│ rpc.rpc.send.$post │ rpc.rpc.webhooks.*
└───────── runtime.sendMessage ───┘
▼
┌──────────────────────────────┐
│ background SW (Hono app) │
│ CRUD → browser.storage.local │
│ send → fetch(discord.com) │
└──────────────────────────────┘
データモデル・RPC routes・payload 形式・エラーハンドリングの詳細な設計は以下を参照してください。
- 設計仕様:
docs/superpowers/specs/2026-08-20-twitter-webhook-extension-design.md - RPC 実装パターン:
.claude/skills/hono-rpc-runtime-messaging/SKILL.md - デザインシステム:
.claude/skills/cannelloni-design-system/SKILL.md
自動テスト (pnpm test / pnpm test:browser) で pure function・RPC route・popup コンポーネントはカバーしていますが、実ブラウザでの拡張読み込みと x.com 上の挙動は手動で確認してください。
pnpm buildで.output/chrome-mv3/を生成する(またはpnpm devで HMR 付きの開発ビルドを起動する)- Chrome で
chrome://extensionsを開き、デベロッパーモードを ON にする - 「パッケージ化されていない拡張機能を読み込む」で
.output/chrome-mv3を選択する
- webhook 登録: popup を開き、Discord webhook URL を1件登録する。リストに表示され、初期状態で有効 (enabled) になっていることを確認する
- cold SW 起動確認: 拡張をリロード(service worker を停止させる)した直後、popup を開かずに x.com を開いてツイートの送信ボタンを押す。background service worker がモジュールスコープに状態を持たず
browser.storage.localから読み直せていれば、popup を経由しなくても正常に送信できる - per-row トグル: popup でリストの行のトグルボタンを押し、無効にした webhook が x.com からの送信で使われない(有効な webhook にのみ届く)ことを確認する
- per-row 削除: 削除ボタン→確認ダイアログ→確定の流れで1件削除し、リストから消えることを確認する
- Discord が非 2xx を返す(例: webhook URL を無効な ID に書き換える): 送信ボタンが error 状態になり、console に失敗した webhook 名とステータスが出力されることを確認する
- 有効な webhook が 0 件: 全ての webhook を無効化またはリストを空にした状態で送信ボタンを押し、error 状態になり console に「送信先なし」である旨が出力されることを確認する
- ツイート情報抽出の失敗: 抽出できない DOM 構造(例: 想定外のページ)でボタンを押した場合、error 状態になり console にエラーが出力され、どの webhook にも送信されないことを確認する