【AI agent活用】作業中のSNS断ちを強制する！！ポモドーロタイマー付きChrome拡張機能を作ってみた

# はじめに

作業中についついSNSや動画サイトを開いてしまい、集中力が途切れてしまうことはありませんか？

「今度こそ集中するぞ！」と意気込んでも、気がつくとTwitterやYouTubeを開いてしまい、気づけば数時間経過...なんて経験、きっと多くの方が持っているのではないでしょうか。

そこで今回は、**ポモドーロテクニック**と**サイトブロック機能**を組み合わせた**Chrome拡張機能**を開発してみました。この記事では、
- Chrome拡張機能の開発のススメ
- AI agent(Codex)の活用方法

も含めて、Chrome拡張機能の作り方を詳しく解説していきます！

:::note info
リリースされているので，是非ご活用ください！
[拡張機能のリンク](https://chromewebstore.google.com/detail/pomodoro-blocker/namdghgkjdgkbpihcmgpoeophegcdkff?hl=ja)
:::

## 📱 完成した拡張機能の機能

まずは、今回作成した拡張機能の主な機能をご紹介します：

- **25分間のポモドーロタイマー**
- **タイマー実行中の集中力を妨げるサイトの自動ブロック**
- **アイコン上に残り時間を表示**
- **ブロック中のカスタムページ表示**
- **タイマー完了時の通知表示**

### デモ動画
![chrome-test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3795703/20d31012-ae5b-4858-b761-a080fbdab799.gif)

↑画質が荒いのですが、お許しください

## 🎯 なぜこの拡張機能を作ったのか

私自身、研究や仕事において在宅ワークが増える中で集中力の維持に課題を感じていました。特に：

1. **意志力に頼る限界**: 「見ないようにしよう」と思っても、つい開いてしまう
2. **既存ツールの不満**: 市販のサイトブロッカーは設定が複雑で使いづらい
3. **ポモドーロテクニックとの組み合わせ**: 25分という区切りでブロックしたい

これらの課題を解決するため、シンプルで使いやすい拡張機能を自作することにしました。

## 🤖 AI agentを活用した開発プロセス

今回の開発では、**Codex**という**ChatGPT内で動作するAI開発エージェント**を積極的に活用しました。AIツールを使うことで、開発効率が大幅に向上したので、その過程もご紹介します。

### AIとの対話例

**私**: 「ポモドーロタイマー付きのサイトブロッカーChrome拡張機能を作りたいです。Manifest V3で、25分間特定のサイトをブロックする機能を実装したいのですが、どのような構成にすべきでしょうか？」

**Codex**: 「Manifest V3でのサイトブロック機能でしたら、declarativeNetRequestを使用するのが最適です。以下のような構成をお勧めします...」

このように、AIと対話しながら設計を固めていきました。特に以下の点でAIが有効でした：

1. **技術選択の相談**: 使用パッケージの最新仕様に関するアドバイス
2. **コード生成**: 基本的な構造の雛形作成
3. **デバッグ支援**: エラーの原因特定と解決策の提案
4. **ベストプラクティスの確認**: セキュリティやパフォーマンスの観点

## 🏗️ 拡張機能の構成

Chrome拡張機能は以下のファイルで構成されています：

```
pomodoro-blocker-extension/
├── manifest.json          # 拡張機能の設定ファイル
├── popup.html             # ポップアップUI
├── popup.js               # タイマー制御ロジック
├── background.js          # サイトブロック制御
└── icons/                 # アイコンファイル
    └── icon.png
```

## 📝 開発ステップバイステップ

### Step 1: manifest.jsonの設定

Chrome拡張機能の心臓部となる`manifest.json`から始めます：

```json
{
  "manifest_version": 3,
  "name": "Pomodoro Blocker",
  "version": "1.0",
  "description": "25分間タイマー+特定サイトを集中のためブロックする拡張機能",
  "permissions": [
    "activeTab",
    "storage",
    "declarativeNetRequest",
    "notifications"
  ],
  "host_permissions": [
    "*://facebook.com/*",
    "*://twitter.com/*",
    "*://youtube.com/*"
    // その他ブロック対象サイト
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}
```

**ポイント**:
- `manifest_version: 3`で最新版を使用
- `declarativeNetRequest`でサイトブロック機能を実装
- `storage`でタイマー状態を永続化

### Step 2: ポップアップUI（popup.html）

ユーザーがクリックする拡張機能のポップアップを作成：

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Pomodoro Blocker</title>
    <style>
        body {
            width: 300px;
            height: 200px;
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 20px;
        }
        
        .timer-display {
            font-size: 48px;
            font-weight: bold;
            color: #333;
            margin: 20px 0;
        }
        
        button {
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        
        .start-btn {
            background-color: #4CAF50;
            color: white;
        }
        
        .stop-btn {
            background-color: #f44336;
            color: white;
        }
    </style>
</head>
<body>
    <h2>Pomodoro Blocker</h2>
    <div id="timer-display" class="timer-display">25:00</div>
    
    <div class="controls">
        <button id="start-btn" class="start-btn">開始</button>
        <button id="stop-btn" class="stop-btn">停止</button>
    </div>
    
    <script src="popup.js"></script>
</body>
</html>
```

### Step 3: タイマー制御（popup.js）

ポップアップの動作を制御するJavaScriptを実装：

```javascript
class PomodoroTimer {
    constructor() {
        this.duration = 25 * 60; // 25分（秒単位）
        this.timeLeft = this.duration;
        this.isRunning = false;
        
        this.timerDisplay = document.getElementById('timer-display');
        this.startBtn = document.getElementById('start-btn');
        this.stopBtn = document.getElementById('stop-btn');
        
        this.initializeEventListeners();
        this.loadState();
    }
    
    initializeEventListeners() {
        this.startBtn.addEventListener('click', () => this.startTimer());
        this.stopBtn.addEventListener('click', () => this.stopTimer());
    }
    
    startTimer() {
        this.isRunning = true;
        this.startTime = Date.now();
        this.startCountdown();
        
        // バックグラウンドスクリプトにブロック開始を通知
        chrome.runtime.sendMessage({
            action: 'startBlocking',
            duration: this.timeLeft
        });
    }
    
    startCountdown() {
        this.intervalId = setInterval(() => {
            const elapsed = Math.floor((Date.now() - this.startTime) / 1000);
            this.timeLeft = Math.max(0, this.duration - elapsed);
            
            this.updateDisplay();
            
            if (this.timeLeft <= 0) {
                this.timerComplete();
            }
        }, 1000);
    }
    
    updateDisplay() {
        const minutes = Math.floor(this.timeLeft / 60);
        const seconds = this.timeLeft % 60;
        this.timerDisplay.textContent = 
            `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
}

document.addEventListener('DOMContentLoaded', () => {
    new PomodoroTimer();
});
```

### Step 4: サイトブロック機能（background.js）

拡張機能のコア機能である、サイトブロック処理を実装：

```javascript
class PomodoroBlocker {
    constructor() {
        this.blockedSites = [
            'facebook.com',
            'twitter.com',
            'x.com',
            'instagram.com',
            'youtube.com',
            'netflix.com',
            'reddit.com'
            // その他ブロック対象サイト
        ];
        
        this.initializeEventListeners();
    }
    
    initializeEventListeners() {
        chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
            switch (message.action) {
                case 'startBlocking':
                    this.startBlocking(message.duration);
                    break;
                case 'stopBlocking':
                    this.stopBlocking();
                    break;
            }
        });
    }
    
    async startBlocking(duration) {
        this.isBlocking = true;
        
        // declarativeNetRequest用のルールを作成
        this.blockingRules = this.blockedSites.map((site, index) => ({
            id: index + 1,
            priority: 1,
            action: { 
                type: 'redirect', 
                redirect: { 
                    url: 'data:text/html;charset=utf-8,' + 
                         encodeURIComponent(this.createBlockPageContent(site)) 
                } 
            },
            condition: { 
                urlFilter: `||${site}^`,
                resourceTypes: ['main_frame']
            }
        }));

        // ブロックルールを適用
        await chrome.declarativeNetRequest.updateDynamicRules({
            addRules: this.blockingRules
        });
        
        // 指定時間後に自動停止
        setTimeout(() => {
            this.stopBlocking();
        }, duration * 1000);
    }
    
    createBlockPageContent(blockedSite) {
        return `
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>サイトがブロックされています</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            text-align: center;
        }
        .container {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            padding: 40px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div style="font-size: 72px;">🍅</div>
        <h1>サイトがブロックされています</h1>
        <p>ポモドーロタイマーが終了するまでお待ちください。</p>
        <p>集中して作業を続けましょう！</p>
    </div>
</body>
</html>`;
    }
}

new PomodoroBlocker();
```

## 🔧 開発で工夫したポイント

### 1. Manifest V3対応

Chrome拡張機能は2024年からManifest V3が必須となりました。従来のwebRequestからdeclarativeNetRequestへの移行が必要で、この部分でAIの助けが特に有効でした。

### 2. 状態の永続化

ブラウザを閉じてもタイマーが継続するよう、chrome.storage.localを使用して状態を保存しています。

### 3. リアルタイム表示

拡張機能のアイコンにバッジで残り時間を表示し、ユーザーが常に進捗を確認できるようにしました。

## 🚀 インストールと使い方

### インストール方法
リリースは申請中なので、以下のようにローカルで使用してください。

1. [GitHub](https://github.com/maruyamayasuaki/TimerBlockSNS-chrome_ex)からコードをダウンロード
2. Chrome の `chrome://extensions/` にアクセス
3. 「デベロッパーモード」を有効にする
4. 「パッケージ化されていない拡張機能を読み込む」をクリック
5. ダウンロードしたフォルダを選択

### 使い方

1. Chrome ツールバーの拡張機能アイコンをクリック
2. 「開始」ボタンでポモドーロタイマーを開始
3. 25分間、指定したサイトが自動的にブロックされます
4. タイマー完了時に通知が表示されます

## 🎨 あなた専用の拡張機能にカスタマイズ！

### ブロック対象サイトの変更

`background.js`の`blockedSites`配列を編集することで、ブロック対象を自由に変更できます：

```javascript
this.blockedSites = [
    'facebook.com',
    'twitter.com',
    'your-favorite-distraction.com'  // 追加
];
```

### タイマー時間の変更

`popup.js`の`duration`変数を変更することで、25分以外の時間に設定可能です：

```javascript
this.duration = 45 * 60; // 45分に変更
```

## 💡 AIツール活用のコツ

今回の開発を通じて学んだ、AIツールを効果的に活用するコツをまとめます：

### 1. 具体的な質問をする

❌ 悪い例: 「Chrome拡張機能を作りたい」
✅ 良い例: 「Manifest V3でサイトブロック機能を持つChrome拡張機能を作りたい。declarativeNetRequestを使用して、特定のドメインにアクセスした際にカスタムページにリダイレクトする方法を教えて」

### 2. エラーメッセージを共有する

エラーが発生した際は、エラーメッセージ全体をAIに共有することで、的確な解決策を得られます。

### 3. 段階的に開発する

すべてを一度に実装しようとせず、機能ごとに分けてAIに相談することで、より良いコードが得られます。

## 🔮 今後の改善案

現在の拡張機能をさらに発展させるアイデア：

- **統計機能**: 1日の集中時間や達成回数の記録
- **カスタムタイマー**: 5分、15分、30分など複数の時間設定
- **ホワイトリスト機能**: 仕事で必要なサイトの除外設定
- **同期機能**: 複数デバイス間での設定共有
- **集中度分析**: ブロックを試みた回数の分析

## 📚 参考リソース
Qita記事
- [Chrome拡張機能の実装（入門から公開まで）](https://qiita.com/Nozomuts/items/fc1d4f8fc995d830817d)
- [Chrome拡張機能を初めて作ってみた - （ 新規タブに恐竜を表示してかわいくする ）](https://qiita.com/yukinonyukinon/items/95873d43a33abbf41a16)

Document集
- [Chrome Extensions API Documentation](https://developer.chrome.com/docs/extensions/)
- [Manifest V3 Migration Guide](https://developer.chrome.com/docs/extensions/migrating/)
- [declarativeNetRequest API](https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/)

## まとめ

今回は、ポモドーロテクニックとサイトブロック機能を組み合わせたChrome拡張機能を開発しました。AIツールを活用することで、効率的に開発を進めることができ、特に最新のパッケージ仕様への対応において大きな助けとなりました。

この拡張機能を使うことで、作業中の誘惑を物理的に断ち切り、25分間の集中時間を確保できるようになります。ぜひ皆さんも試してみて、必要に応じてカスタマイズしてみてください！

何か質問やご意見がありましたら、コメント欄でお聞かせください。また、機能追加のアイデアなどもお待ちしています！