# ブログ半自動化構築スキル — 導入プロンプト（このファイルを丸ごとAIに渡してください）

---

## 【受け取った方へ】使い方（ここだけ読めばOK）

1. **Claude Code**（または Codex）を起動する。
2. このファイルを **AIにドラッグ＆ドロップで添付**（またはファイルを開いて全文コピー → AIに貼り付け）して送信する。
3. AIが自動でスキルを組み立てます。終わったら **AIを完全に終了して再起動**。
4. `/blog-builder` で起動します。

**ZIPの手動保存・解凍なしで復元できます。** 配布ZIPと同じ 8 ファイルをテキストで収録しています。復元後の依存ツール導入は説明書に従います。OSや環境による確認・警告が出る場合もあります。

うまくいかない時は「スキルが作れているか確認して」とAIに伝えてください。

---

あなた（AI）はこれから、「ブログ半自動化構築スキル」を利用者のPCに構築します。以下の指示に厳密に従ってください。

## 手順

0. 実行環境（Mac / Windows）を確認する。**手順1〜3ではファイル復元だけを行う。** 配布ファイルは本文にそろっている。外部ツールの依存導入は手順4で行う。

1. 作業フォルダ `~/Downloads/AI顧問スキル/blog-builder_配布パッケージ/` を作成する（Windows は `%USERPROFILE%\Downloads\AI顧問スキル\blog-builder_配布パッケージ\`）。
   - 同名フォルダが既にある場合は新しい作業フォルダへ復元する。導入先の旧版を別の場所にバックアップし、mydata・本人ナレッジ・認証設定を保全してから切り替える。復元やセットアップに失敗したら旧版へ戻す。

2. 下の「ファイル定義」にある **8 ファイル** を、指定された相対パス（`~/Downloads/AI顧問スキル/blog-builder_配布パッケージ/` からの相対）に作成する。
   - 各ファイルの内容は `========== FILE: パス ==========` 行の次の行から `========== END FILE ==========` 行の直前の行までを、
     **一字一句変更せずそのまま** 書き込む。ファイルの末尾は改行1つで終わらせる。
   - 要約・整形・体裁変更・翻訳・改行の増減・全角半角の変換・Markdown記法の「修正」は一切禁止。
     マーカー行（`========== ... ==========`）自体はファイルに含めない。
   - ファイル数が多い場合は数ファイルずつに分けて作成してよい。**途中で省略せず、必ず全ファイルを作りきる。**

3. 全ファイル作成後、次を検証して結果を報告する:
   - `~/Downloads/AI顧問スキル/blog-builder_配布パッケージ/` 配下に 8 ファイルが存在すること
   - 各ファイルの行数（`wc -l`）が下の「行数チェック表」と一致すること。
     一致しないファイルがあれば、そのファイルだけ作り直す。

4. **セットアップまで実行する。** 作成したフォルダの中にある説明書
   （`README.md` / `README_使い方.md` / `INSTALL.md` / `INSTALL_FOR_AI.md` / `はじめにお読みください.md` のうち存在するもの）を読み、
   そこに書かれた手順どおりに、このPCで `/blog-builder` が使える状態まで導入を完了させる。
   - 説明書に Claude Code 用・Codex 用の両方が書かれている場合は、現在のアプリを確認して該当手順を使う。判別できない場合だけ利用者に聞く。
   - 追加で必要なもの（Python等）が足りなければ、OSを確認して1ステップずつ案内する。

5. 最後に利用者へ、次の3点を伝える:
   - 作成したフォルダの場所（フルパス）
   - **AIを完全に終了して再起動する**必要があること
   - 再起動後 `/blog-builder` で呼び出せること

## 行数チェック表（wc -l の値）

| ファイル | 行数 |
|---|---|
| INSTALL_FOR_AI.md | 135 |
| README.md | 226 |
| blog-builder/AGENTS.md | 3 |
| blog-builder/SKILL.md | 559 |
| blog-builder/scripts/post_to_wp.py | 144 |
| blog-builder/scripts/upload_image_to_wp.py | 167 |
| blog-builder/scripts/wp_test.py | 146 |
| はじめにお読みください.md | 226 |

---

## ファイル定義

========== FILE: INSTALL_FOR_AI.md ==========
# 🤖 AIへの自動セットアップ指示書

> このファイルは、Claude Code または Codex に向けて書かれた **自動セットアップ指示書** です。
> ユーザーは「このZIP内の `INSTALL_FOR_AI.md` に従って設置して」とAIに頼むだけでOK。

---

## あなた（AI）がやること

このZIPには `blog-builder/` というスキルフォルダが入っています。
これを **Claude Code または Codex** で使えるように、ユーザーのPCに設置してください。

### 設置先の判定

ユーザーの環境に応じて、以下の場所に設置してください：

| AIツール | OS | 設置先 |
|---|---|---|
| Claude Code | macOS / Linux | `~/.claude/skills/blog-builder/` |
| Claude Code | Windows | `%USERPROFILE%\.claude\skills\blog-builder\` |
| Codex | macOS / Linux | `~/.codex/skills/blog-builder/` |
| Codex | Windows | `%USERPROFILE%\.codex\skills\blog-builder\` |

両方使う可能性がある場合は両方に設置してOKです（容量は数十KBなので問題なし）。

### 手順

#### macOS / Linux（Claude Codeの場合）

```bash
mkdir -p ~/.claude/skills
rm -rf ~/.claude/skills/blog-builder
cp -R "<コピー元パス>/blog-builder" ~/.claude/skills/
```

#### macOS / Linux（Codexの場合）

```bash
mkdir -p ~/.codex/skills
rm -rf ~/.codex/skills/blog-builder
cp -R "<コピー元パス>/blog-builder" ~/.codex/skills/
```

#### Windows（Claude Codeの場合・PowerShell）

```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\skills"
Remove-Item -Recurse -Force "$env:USERPROFILE\.claude\skills\blog-builder" -ErrorAction SilentlyContinue
Copy-Item -Recurse "<コピー元パス>\blog-builder" "$env:USERPROFILE\.claude\skills\"
```

#### Windows（Codexの場合・PowerShell）

```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\skills"
Remove-Item -Recurse -Force "$env:USERPROFILE\.codex\skills\blog-builder" -ErrorAction SilentlyContinue
Copy-Item -Recurse "<コピー元パス>\blog-builder" "$env:USERPROFILE\.codex\skills\"
```

### 設置確認

**macOS / Linux**:
```bash
ls -la ~/.claude/skills/blog-builder/SKILL.md   # Claude Codeの場合
ls -la ~/.codex/skills/blog-builder/AGENTS.md   # Codexの場合
```

**Windows**:
```powershell
Get-Item "$env:USERPROFILE\.claude\skills\blog-builder\SKILL.md"   # Claude Codeの場合
Get-Item "$env:USERPROFILE\.codex\skills\blog-builder\AGENTS.md"   # Codexの場合
```

ファイルが存在すればOK。

### ユーザーへの完了報告

以下のような文面でユーザーに報告してください（日本語で）：

```
✅ blog-builder スキルを設置しました！

【設置先】
（実際に設置した場所を表示）

【次にやること】
新しいスレッドを開いて、以下のように依頼してください：

  Claude Codeをお使いの方:
    「/blog-builder」または「ブログビルダー起動して」

  Codexをお使いの方:
    「ブログビルダーを起動して」または「ブログスキルを構築して」

スキルが起動して、以下の流れで「あなた専用のブログスキル」を構築します：

  Step 1: WordPress API連携の設定
  Step 2: あなたの既存ブログ記事を分析
  Step 3: あなた専用ナレッジファイルの自動生成
  Step 4: 投稿・画像アップロードスクリプトの設置
  Step 5: 最初の記事を書いてみる
  Step 6: フィードバックで精度を上げていく

完成すると、あなたの口調・構成・デザインで記事が書けるようになります。
```

---

## エラー対応

### よくあるエラーと対処

- **「~/.claude/ がない」** → ユーザーがClaude Codeをまだインストールしていない可能性。先にClaude Codeのインストールを案内してください。
- **「~/.codex/ がない」** → ユーザーがCodexをまだインストールしていない可能性。先にCodexのインストールを案内してください。
- **「Permission denied」** → コピー先フォルダの権限不足。`sudo` は使わず、ユーザーホーム配下に置けば通常は不要。
- **Windowsで「実行ポリシー」エラー** → PowerShellで `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` を提案。

---

## ⚠️ 守ってほしいこと

- ユーザーのホームディレクトリの **他のスキル** には絶対に触らないでください
- `~/.claude/CLAUDE.md` や `~/.claude/settings.json` などの設定ファイルは編集しない
- 既存の `blog-builder` フォルダがあった場合は、上書き（古いバージョンを最新版で置き換え）してOK
- **絶対にWordPressのログインIDやパスワードをチャットに貼らせないでください**（このスキルの最重要ルール）

---

## あなた（AI）への補足

このスキルは「ブログ記事を書く」スキルではなく、**「あなた専用のブログ記事作成スキルを組み上げるビルダー」** です。

セットアップ完了後、ユーザーが起動指示を出したら、`SKILL.md`（Claude Code）または `AGENTS.md`（Codex）の Step 1 から順番にガイドしてください。

特に **Step 1（WordPress API連携）では絶対にパスワードを直接やり取りしない** こと。`.env` ファイル経由で受け渡しする仕様を厳守してください。
========== END FILE ==========

========== FILE: README.md ==========
# はじめにお読みください — blog-builder

**あなた専用のWordPressブログ記事作成スキル** を組み上げる、ビルダー型のスキルです。

このスキルを使うと、以下が自動で完成します：

1. **WordPress API連携**（あなたのブログに記事を自動投稿できるようになる）
2. **あなたの既存記事の全文解析**（口調・構成・テンプレートを学習）
3. **あなた専用のナレッジファイル群**（ブログ作成の指針）
4. **投稿・画像アップロードスクリプト**
5. **`/blog` コマンド**（以後、これだけで記事が書ける）

セットアップ完了後は、**「ブログ書いて」「ブログ作って」と頼むだけで、あなたの口調・構成・デザインで下書きが完成** します。

---

## 🌐 対応環境

| AIツール | OS | 対応 |
|---|---|---|
| **Claude Code** | macOS | ✅ |
| **Claude Code** | Windows | ✅ |
| **Codex**（OpenAI Codex CLI） | macOS | ✅ |
| **Codex**（OpenAI Codex CLI） | Windows | ✅ |

各環境向けに `SKILL.md`（Claude Code用）と `AGENTS.md`（Codex用）を同梱しています。

---

## 前提条件

1. **WordPress（SWELLテーマ）** で運営している自分のブログがあること
2. **Claude Code または Codex** がインストール済みで、ログイン済みであること
3. **Python 3** がインストールされていること（追加パッケージ不要・標準ライブラリのみ使用）

---

## セットアップ手順（AIに丸投げ・推奨）

このZIPを Claude Code または Codex のチャットに添付して、以下のように指示するだけでOKです：

```
添付したZIPファイルを確認し、ZIP内の「INSTALL_FOR_AI.md」に従って、
スキルをセットアップしてください。
セットアップ後、ブログビルダーを起動できる状態にしてください。
```

AIがあなたの環境（OS・AIツール）を判定して、適切な場所に自動で設置してくれます。

---

## 手動セットアップ（自分でやりたい方）

### 設置先の早見表

| AIツール | OS | 設置先 |
|---|---|---|
| Claude Code | macOS | `~/.claude/skills/blog-builder/` |
| Claude Code | Windows | `%USERPROFILE%\.claude\skills\blog-builder\` |
| Codex | macOS | `~/.codex/skills/blog-builder/` |
| Codex | Windows | `%USERPROFILE%\.codex\skills\blog-builder\` |

### macOS（ターミナル）

**Claude Code を使う方**:
```bash
mkdir -p ~/.claude/skills
cp -R blog-builder ~/.claude/skills/
```

**Codex を使う方**:
```bash
mkdir -p ~/.codex/skills
cp -R blog-builder ~/.codex/skills/
```

### Windows（PowerShell）

**Claude Code を使う方**:
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\skills"
Copy-Item -Recurse blog-builder "$env:USERPROFILE\.claude\skills\"
```

**Codex を使う方**:
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\skills"
Copy-Item -Recurse blog-builder "$env:USERPROFILE\.codex\skills\"
```

### 設置確認

**macOS**：
```bash
ls ~/.claude/skills/blog-builder/   # Claude Codeの場合
ls ~/.codex/skills/blog-builder/    # Codexの場合
```

**Windows**：
```powershell
Get-ChildItem "$env:USERPROFILE\.claude\skills\blog-builder"   # Claude Codeの場合
Get-ChildItem "$env:USERPROFILE\.codex\skills\blog-builder"    # Codexの場合
```

`SKILL.md`（または `AGENTS.md`）と `scripts/` フォルダが見えればOKです。

---

## 起動方法

Claude Code または Codex を再起動してから、以下のように依頼してください：

### Claude Code をお使いの方

```
/blog-builder
```

または：

```
ブログビルダー起動して
ブログスキル構築して
```

### Codex をお使いの方

```
ブログビルダーを起動して
ブログスキル構築して
```

---

## 全体の流れ（6ステップ）

スキル起動後、AIが以下の順番で進めてくれます。

```
Step 1: WordPress API連携の設定（5〜10分）
   ↓
Step 2: 既存記事を分析（3〜5分）
   ↓
Step 3: あなた専用のナレッジファイル自動生成（自動）
   ↓
Step 4: 投稿・画像アップロードスクリプト設置（自動）
   ↓
Step 5: 最初の記事を書いてみる（10〜15分）
   ↓
Step 6: フィードバックで精度を上げていく（継続）
```

完成すると、毎回 **「ブログ書いて」だけで、あなた仕様の記事が書ける** ようになります。

---

## ⚠️ 超重要なお約束

WordPressのログインIDやパスワードを **このチャットには絶対に貼らないでください**。

スキルが `.env` ファイルを自動作成して、エディタで開いてくれます。
**そこにだけ書いて、保存してください**。

`.env` ファイルはあなたのPCの中にだけ保存され、AIには内容が見えないようになっています。

---

## このスキルでできること（完成後のイメージ）

1. 「ブログ書いて」と頼むだけで、あなたの口調で記事が書ける
2. 過去記事から学んだテンプレート構成で、毎回安定したクオリティ
3. アイキャッチ画像・本文画像も自動で調達
4. SWELLテーマのデザイン（吹き出し・カード・FAQ・CTA）を自動適用
5. 投稿は下書き保存（あなたが確認してから公開）
6. フィードバックを蓄積するたびにAIが賢くなる

---

## 困ったとき

### スキルが認識されない

スキル設置場所に `SKILL.md`（または `AGENTS.md`）と `scripts/` が両方あるか確認。
AIツール（Claude Code / Codex）を一度終了して、再起動するのが確実です。

### WordPress API連携でエラーが出る

スクショを撮って、AIに「これどこを押せばいい?」と聞いてください。
パスワードが映ったスクショは送らないように注意してください。

### Pythonが動かない

`python3 --version`（macOS）または `python --version`（Windows）で確認してください。
バージョン 3.8 以上が必要です。

### その他、困ったとき

AI（Claude Code / Codex）に直接質問するのが一番早いです。スキルの中身を理解した上で答えてくれます。

---

## ファイル構成

```
blog-builder_配布パッケージ/
├── はじめにお読みください.md（このファイル）
├── INSTALL_FOR_AI.md（AI自動セットアップ用指示書）
└── blog-builder/
    ├── SKILL.md（Claude Code用エントリポイント）
    ├── AGENTS.md（Codex用エントリポイント・同内容）
    └── scripts/
        ├── post_to_wp.py（記事投稿スクリプト）
        ├── upload_image_to_wp.py（画像アップロードスクリプト）
        └── wp_test.py（接続テストスクリプト）
```

---

## ライセンス・使用範囲

- このスキルは AI顧問の顧問生さん専用配布物です。第三者への再配布はご遠慮ください
- スキル内のロジック・ナレッジは、まさきの蓄積をもとに作られています

---

楽しんでブログを書いてください！
========== END FILE ==========

========== FILE: blog-builder/AGENTS.md ==========
# この配布スキルの実行入口

このフォルダのSKILL.mdが手順の正本です。依頼されたスキルを実行するときに読み、必要な参照ファイルだけを追加で読み込んでください。利用者の作業フォルダのルールと今回の依頼を優先します。
========== END FILE ==========

========== FILE: blog-builder/SKILL.md ==========
---
name: blog-builder
description: あなた専用のWordPressブログ記事作成スキルを組み上げるビルダー。「/blog-builder」で起動。WordPress（SWELLテーマ）のAPI連携設定 → 既存記事の全文解析 → あなた専用の口調・構成・テンプレートを自動生成 → 以後は「/blog」であなた仕様の記事が書ける。
---

## 既存環境と原稿を守る実行条件

- 初期設定／文体分析／既存ブログスキル更新を区別する。接続済みなら.envや専用ナレッジを作り直さない。雛形作成は新規ファイルに限り、既存キーは本人がエディタで管理する。
- WordPressの本人サイトURL、アプリケーションパスワードを使う利用者、記事の名義を確定する。資格情報を付けるリクエストは確認済みのHTTPSサイトだけへ送る。
- 過去記事の「文体」「事実」「時点依存の料金」を分ける。文体サンプルの古い制度や売上を新しい記事へ引き継がない。
- テンプレートの数字、成功事例、リンクは見本。本人の資料または確認した一次情報に差し替え、出典メモを残す。外部記事の本文を言い換えるだけの転載はしない。
- 生成する /blog にも、出典確認・本人の事実を創作しない・保存先の尊重・既存下書きの重複確認を引き継ぐ。
- 投稿結果には記事IDとstatusを確認する。タイムアウト等で成否不明なら、再投稿前に同タイトルと直近の記事を検索する。成功レスポンスだけで画像・改行・リンクの表示確認済みとしない。
- SWELL装飾は実テーマを確認して適用する。別テーマで使う依頼なら標準ブロックにし、テーマ変更を勝手に行わない。

# ブログスキル・ビルダー（WordPress + SWELL 専用）

## これは何？

あなた専用の「ブログ記事自動作成スキル」を、ゼロから組み上げるためのビルダーです。

完成すると `/blog` コマンドで、**あなたの口調・構成・デザインで記事が書ける**ようになります。

---

## 全体の流れ

```
Step 1: WordPress API連携の設定（.envファイル作成）
Step 2: あなたのブログ記事を分析する（口調・構成・パーツを数値化）
Step 3: あなた専用のナレッジファイルを自動生成
Step 4: 投稿・画像アップロードのスクリプトを設置
Step 5: /blog で最初の記事を書いてみる
Step 6: フィードバックで精度を上げていく（ここからが本番）
```

---

## Step 1：WordPress API連携の設定

Claude Code / Codex があなたのWordPressに記事を投稿できるように、API連携を設定します。

> ⚠️ **超重要：ログインIDやパスワードは、このチャットには絶対に貼らないでください。**
> Claude Code / Codex が `.env` ファイルを作成するので、**そこにだけ書いてください**。
> チャットに貼ると履歴に残ってしまいます。`.env` ファイルはあなたのPC内にだけ保存されます。

### 1-1. WordPressのログインIDを確認する

1. あなたのWordPress管理画面にログインする（`https://あなたのドメイン/wp-admin/`）
2. 左メニューの「**ユーザー**」→「**プロフィール**」を開く
3. 一番上に表示されている「**ユーザー名**」がログインIDです
4. これをメモしておいてください（まだチャットには貼らないで！）

> 💡 わからないところがあったら、画面のスクリーンショットを撮ってこのチャットに送ってください。スクショを見ながら一緒に進めます！（ただしパスワードが映っているスクショは送らないでね）

### 1-2. アプリケーションパスワードを発行する

1. 同じ「プロフィール」ページを**下にスクロール**してください
2. 「**アプリケーションパスワード**」というセクションを見つけます
   - 見つからない場合は、ページの一番下あたりにあります
   - それでも見つからない場合は、スクショを送ってください！一緒に探します
3. 「新しいアプリケーションパスワード名」という入力欄に `Claude` と入力
4. 「**新しいアプリケーションパスワードを追加**」ボタンをクリック
5. **スペース区切りの英数字**が表示されます。これがアプリケーションパスワードです
6. **この場でコピー**してください

> ⚠️ **このパスワードは一度しか表示されません！** 画面を閉じたら二度と見られません。
> コピーし忘れても大丈夫。もう一度「新しいアプリケーションパスワードを追加」で発行し直せます。
>
> 💡 「アプリケーションパスワード」のセクション自体が見当たらない場合は、WordPressのバージョンが古いか、プラグインで無効化されている可能性があります。スクショを送ってくれたら原因を一緒に調べます！

### 1-3. .envファイルに保存する

ここまで準備できたら、以下の手順で `.env` ファイルを作ります。

> 🔐 WordPress API連携を設定します！
>
> 以下の手順で進めてください：
>
> 1. まず、あなたの **WordPressサイトのURL** を教えてください（例：`https://example.com`）
>    - ログインIDやパスワードは**まだ言わないで**！
>
> 2. URLを教えてもらったら、`.env` ファイルを作成して**自動で開きます**
>
> 3. 開いた `.env` ファイルに、以下の形式で **ログインID** と **アプリケーションパスワード** を直接書き込んでください：
>    ```
>    WP_SITE_URL=https://あなたのドメイン
>    WP_USERNAME=ここにログインIDを書く
>    WP_APP_PASSWORD=ここにアプリケーションパスワードを書く
>    ```
>
> 4. 書き込んだら保存して、「**書けたよ**」と教えてください
>
> ⚠️ 繰り返しますが、ログインIDやパスワードは**このチャットには絶対に貼らないでください**。
> `.env` ファイルに直接書き込むだけでOKです。

#### AIによる実装（.envファイル作成 → 自動で開く）★ macOS / Windows 両対応 ★

ユーザーからサイトURLを受け取ったら、**OSを判定して** `.env` を作成・自動オープンします。

**macOS / Linux の場合**:
```bash
# .envファイルを作成（スキルの親ディレクトリに配置）
cat > "$(pwd)/.env" << 'ENVEOF'
# WordPress API連携設定
# ⚠️ このファイルの内容はチャットに貼らないでください
# ⚠️ このファイルはあなたのPC内にだけ保存されます

WP_SITE_URL=ユーザーから受け取ったURL
WP_USERNAME=ここにログインIDを書いてください
WP_APP_PASSWORD=ここにアプリケーションパスワードを書いてください
ENVEOF

# .envファイルを自動で開く（macOS）
open "$(pwd)/.env"

# Linuxの場合
# xdg-open "$(pwd)/.env"
```

**Windows の場合**（PowerShell）:
```powershell
# .envファイルを作成
@"
# WordPress API連携設定
# ⚠️ このファイルの内容はチャットに貼らないでください
# ⚠️ このファイルはあなたのPC内にだけ保存されます

WP_SITE_URL=ユーザーから受け取ったURL
WP_USERNAME=ここにログインIDを書いてください
WP_APP_PASSWORD=ここにアプリケーションパスワードを書いてください
"@ | Out-File -FilePath ".env" -Encoding UTF8

# .envファイルを自動で開く（Windows）
notepad .env
# または: Start-Process notepad .env
```

**Pythonでクロスプラットフォーム実装する場合**:
```python
import os
import platform
import subprocess
from pathlib import Path

env_content = """# WordPress API連携設定
# ⚠️ このファイルの内容はチャットに貼らないでください
# ⚠️ このファイルはあなたのPC内にだけ保存されます

WP_SITE_URL=ユーザーから受け取ったURL
WP_USERNAME=ここにログインIDを書いてください
WP_APP_PASSWORD=ここにアプリケーションパスワードを書いてください
"""

env_path = Path.cwd() / ".env"
env_path.write_text(env_content, encoding="utf-8")

# OS判定して自動オープン
system = platform.system()
if system == "Darwin":      # macOS
    subprocess.run(["open", str(env_path)])
elif system == "Windows":
    os.startfile(str(env_path))
elif system == "Linux":
    subprocess.run(["xdg-open", str(env_path)])
```

ユーザーが「書けたよ」と言ったら、接続テストを実行：

```bash
python3 scripts/wp_test.py
```

接続テストが成功したら次のステップへ。失敗したら原因を調べて案内する。

> 💡 「401エラー」が出た場合 → パスワードのコピーミスの可能性が高いです。もう一度アプリケーションパスワードを発行し直してみてください。
> 「404エラー」が出た場合 → サイトURLが間違っている可能性があります。URLを確認してください。
> それでもうまくいかない場合は、エラーメッセージのスクショを送ってください！

---

## Step 2：あなたのブログ記事を分析する

> 📝 あなたのブログを分析して「あなた専用のブログスキル」を作ります！
>
> **あなたの公開済みブログ記事のURL** を教えてください。
>
> - 最低3本あれば分析できます
> - **多ければ多いほど、あなたの理想の文体・構成に近づきます**（5〜10本がベスト）
> - まだ1本も書いていない場合は、「この人のブログを参考にしたい」という記事のURLを数本貼ってください
>   - 参考にしたいブログの文体や構成を分析して、それをベースにあなたのスキルを作ります
>   - あとからフィードバックで自分好みに調整していけるので、まずは「こんな感じがいい」で大丈夫です
>
> ```
> 例：
> https://example.com/post1/
> https://example.com/post2/
> https://example.com/post3/
> https://example.com/post4/
> https://example.com/post5/
> ```

### 分析の実行手順

URLを受け取ったら、以下の順で分析する。

#### 2-1. 記事HTMLの取得

```bash
# 各URLの記事HTMLを取得
curl -sL -A "Mozilla/5.0" "URL1" -o /tmp/article_1.html
curl -sL -A "Mozilla/5.0" "URL2" -o /tmp/article_2.html
# ... 以下同様
```

#### 2-2. 自動分析する項目

以下のPythonスクリプトを**その場で生成・実行**して、全記事を横断分析する。

**分析項目一覧：**

| 分析カテゴリ | 具体的に何を見るか |
|---|---|
| **文末パターン** | 「〜だよ」「〜です」「〜してね」「〜だね」等の出現回数と割合 |
| **一人称** | 僕/私/俺/わたし のどれを使っているか |
| **読者の呼び方** | フォロワーさん/読者/みなさん/あなた 等 |
| **絵文字** | よく使う絵文字TOP20、使っていない絵文字 |
| **吹き出し** | SWELLの balloonID一覧、アイコン画像URL、位置（左/右）、色、名前 |
| **見出し構成** | H2/H3の数、画像の配置パターン（H2直後か、本文中か） |
| **使用SWELLブロック** | capbox/button/table/accordion/tab/columns 等の種類と頻度 |
| **CTA** | ボタンの色・スタイル、キャッチ文の有無、配置位置 |
| **テーブル** | 使用頻度、列数の傾向、tfoot注釈の有無 |
| **画像** | H2直後の画像URL一覧、本文中の画像の有無 |
| **記事の構成パターン** | 冒頭→本文→FAQ→まとめ の流れ |
| **特徴的な語彙** | よく使う言い回し（「ぶっちゃけ」「正直」「マジで」等） |

#### 2-3. 分析結果をユーザーに提示

分析結果を以下の形式で提示し、確認してもらう：

> 📊 あなたのブログを分析しました！
>
> **口調：**
> - 基本文体：「〜だよ / 〜だね」調（フレンドリー系）
> - 一人称：「僕」
> - 読者の呼び方：「フォロワーさん」
> - です・ます調の割合：全体の5%未満
>
> **よく使う文末パターン（上位5つ）：**
> 1. 〜だよ（25%）
> 2. 〜してね（18%）
> 3. 〜だね（12%）
> 4. 〜よね（10%）
> 5. 〜だから（8%）
>
> **絵文字：**
> - よく使う：😊🔥👍☺️😆❤️‍🔥
> - 使っていない：🥰（NG候補）
>
> **吹き出し：**
> - あなた用アイコン：6種類（感情別に使い分け）
> - 読者用アイコン：4種類
>
> **記事構成：**
> - 冒頭：吹き出しで悩み列挙 → 共感 → 結論
> - 本文：H2見出し → 画像 → 本文 → 吹き出し補足
> - CTA：キャッチ文＋光沢ボタン
> - まとめ：POINTボックス → CTA → 応援吹き出し
>
> これで合ってますか？「ここは違う」「ここを変えたい」があれば教えてください！

ユーザーが「合ってる」と言ったら Step 3 へ。修正があれば反映してから Step 3 へ。

---

## Step 3：あなた専用のナレッジファイルを自動生成

分析結果をもとに、以下のファイルを自動生成する。

### 生成するファイル一覧

| ファイル | 内容 |
|---|---|
| `patterns/口調・文体ガイド.md` | 文末分布の実測値テーブル、口調モード、語彙リスト、絵文字ルール |
| `patterns/吹き出しアイコン使い分けガイド.md` | SWELL吹き出しセットのballoonID×アイコン×感情マッピング |
| `patterns/使用可能画像リスト.md` | H2直後用の画像ファイルURL一覧 |
| `patterns/記事タイプ別構成.md` | 記事パターンの分類と構成テンプレート |
| `patterns/完成記事パターン分析.md` | 構造の黄金パターン、テーブルの型、CTA配置ルール |
| `patterns/画像選定・アップロードガイド.md` | コンテンツ画像の調達・アップロード・挿入ルール |
| `templates/` | SWELLブロックのHTMLパーツ集（吹き出し・ボタン・テーブル・見出し等） |
| `patterns/フィードバック蓄積.md` | 今後のフィードバックを貯めるファイル（初期状態は空テンプレート） |

### 生成のポイント

- **口調・文体ガイド**：Step 2の文末カウント結果をそのまま数値テーブルにする
- **吹き出しアイコン**：記事HTMLから抽出したballoonID・アイコンURL・使用文脈を感情別にマッピング
- **画像リスト**：H2直後に使われている画像URLを全て抽出してリスト化
- **templates/**：記事HTMLから正規表現でSWELLブロック（吹き出し・capbox・ボタン・テーブル等）を切り出して保存
- **フィードバック蓄積.md**：以下のテンプレートで初期化

```markdown
# ブログ記事作成フィードバック蓄積

**このファイルはブログ記事を作る前に必ず目を通すこと。**
過去に指摘されたミスを二度と繰り返さないためのチェックリスト。

新しいフィードバックが来るたびにここに追記すること（日付順・新しいものが下）。

---

（まだフィードバックはありません。記事を作成してプレビューを確認し、
気になるところがあればフィードバックしてください。ここに自動で蓄積されます。）

---

## 新しいフィードバックを受けたら

### FB○○：簡潔なタイトル
**指摘**: ユーザーの実際の発言
**原因**: なぜそのミスをしたか
**ルール**: 今後どうすべきか（具体的に）
**How to apply**: 実作業でどう適用するか
```

---

## Step 4：投稿・画像アップロードのスクリプトを設置

Step 1で設定した `.env` を使って、以下のスクリプトを `scripts/` に自動生成・設置する。

### 4-1. `scripts/post_to_wp.py`（記事投稿スクリプト）

HTMLファイルを受け取って、WordPress REST API で下書き投稿するスクリプト。
`.env` から認証情報を自動読み込み。

### 4-2. `scripts/upload_image_to_wp.py`（画像アップロードスクリプト）

画像URL or ローカルファイルを受け取って、WordPressメディアライブラリにアップロードするスクリプト。
multipart/form-data 形式（SiteGuard WAF 対策済み）。

### 4-3. `scripts/wp_test.py`（接続テストスクリプト）

`.env` の認証情報でWordPress REST APIに接続できるかテストするスクリプト。

### 4-4. テスト投稿

スクリプト設置後、テスト投稿を実行して接続を確認：

```bash
# テスト投稿（タイトルだけの空記事を下書きで投稿）
echo "<p>テスト投稿です。このまま削除してOKです。</p>" > /tmp/test_post.html
python3 scripts/post_to_wp.py /tmp/test_post.html "【テスト】API接続確認 - 削除OK"
```

成功したら：
> ✅ WordPress API連携が正常に動作しています！
> テスト記事が下書きで投稿されました。WordPress管理画面で削除してOKです。

---

## Step 5：`/blog` スキルを自動生成して、最初の記事を書く

ここまでのStep 1〜4で集めた情報をもとに、あなた専用の `/blog` スキル（SKILL.md）を自動生成します。

生成される `/blog` スキルには、以下が最初から組み込まれています：

### 記事作成フロー
1. 参考リンクを受け取る（2本推奨・1本でも可）
2. 参考記事を取得・解析
3. 記事タイプを判定
4. 裏取り・追加リサーチ（WebSearch / WebFetch）
5. あなたに質問（価値観・体験に関わる部分のみ）
6. あなたの口調・構成でHTML記事を組み立て
7. **コンテンツ画像の自動検索・アップロード・挿入**（公式サイトから情報補足型画像を調達）
8. WordPress に下書き投稿
9. プレビューURLを提示

### 画像の自動調達機能（最初から組み込み済み）
- 記事で紹介しているサービス・制度・商品の**公式サイト**から、図解・バナー・還元率図・券面画像などを自動で検索
- 見つけた画像をダウンロード → WordPressメディアにアップロード → 記事HTMLに引用元付きで挿入
- 1記事あたり3〜5枚以上を目安に、情報補足型の画像を積極的に入れる
- イラストやフリー素材は入れない（情報量ゼロの装飾画像はNG）
- 見つからなかった場合は「こんな画像があるといい」とあなたに提案（スクショ元のURLも添える）

### 最初の記事を書いてみる

> 📝 ブログ記事を作成します！
>
> 以下を教えてください：
> 1. **参考ブログ記事のURL（2本推奨・1本でも可）** — 内容や構成を参考にします
> 2. **書きたいテーマ / 商品名 / キーワード** — 記事の軸
> 3. **CTAリンク**（あれば） — ボタンで誘導したい先のURL

---

## Step 6：フィードバックで精度を上げていく

**ここからが本番です。** 最初から完璧な記事は出ません。

プレビューを確認して、「ここが違う」「ここはこうしてほしい」をどんどんフィードバックしてください。フィードバックは `patterns/フィードバック蓄積.md` に自動で構造化して保存されるので、**同じミスは二度と起きなくなります**。

フィードバック具体例はプレビューを渡すたびに表示されるので（上記テンプレート参照）、それを参考に指摘してもらえればOKです。

**フィードバックは10〜15回出すと一気に精度が上がります。** 最初の5本くらいの記事が「スキルの育成期間」だと思ってください。

### フィードバックの蓄積の仕組み

フィードバックを受けたら、AIが自動で以下を行います：

1. `patterns/フィードバック蓄積.md` に構造化して追記（指摘→原因→ルール→適用方法）
2. `/blog` スキル（SKILL.md）の該当ルール・テンプレート・チェックリストを更新
3. 次の記事作成時に、更新済みルールを自動適用

**フィードバックを重ねるほど、スキルが賢くなります。最初の5〜10本の記事が「育成期間」だと思ってください。**

---

## `/blog` スキルの起動フロー（Step 5以降で使う）

### 起動コマンド

ユーザーが `/blog` と入力したら、以下の対話を開始：

> 📝 ブログ記事を作成します！
>
> 以下を教えてください：
>
> 1. **参考ブログ記事のURL（2本推奨・1本でも可）** — 内容や構成を参考にします
> 2. **書きたいテーマ / 商品名 / キーワード** — 記事の軸
> 3. **CTAリンク**（あれば） — ボタンで誘導したい先のURL

### 記事作成フロー

1. **参考記事を取得・解析**：curl でHTML取得 → 見出し構成・要点・テーブル・CTA文言を抽出
2. **記事タイプを判定**：`patterns/記事タイプ別構成.md` を参照
3. **裏取り・追加リサーチ**：WebSearch / WebFetch で最新情報を確認
4. **ユーザーに質問**（必要時のみ）：価値観・体験に関わる部分だけ聞く
5. **HTML記事を組み立て**：
   - 口調は `patterns/口調・文体ガイド.md` に従う
   - 吹き出しは `patterns/吹き出しアイコン使い分けガイド.md` に従う
   - 画像は `patterns/使用可能画像リスト.md` から選ぶ（H2直後のみ）
   - HTMLパーツは `templates/` のテンプレートを使う
   - 全ての禁止ルールを `patterns/フィードバック蓄積.md` でチェック
6. **コンテンツ画像の自動検索・アップロード・挿入**：
   - 記事で紹介しているサービス・制度・商品の公式サイトから情報補足型画像を検索
   - WebSearch + curl で公式サイトのキャンペーンページやLPから図解・バナー画像を取得
   - `/tmp/` にダウンロード → `scripts/upload_image_to_wp.py` でWPにアップロード
   - 引用元付き（`<figcaption>引用：〇〇公式サイト</figcaption>`）で記事HTMLに挿入
   - 1記事あたり3〜5枚以上が目安
   - 見つからなかった場合はユーザーに「こんな画像があるといい」と提案（スクショ元のURLも添える）
   - イラスト・フリー素材・装飾画像は入れない
7. **下書き投稿**：HTMLファイルに保存 → `scripts/post_to_wp.py` で投稿
8. **プレビューURLを提示**（フィードバック具体例と一緒に渡す → 下記テンプレート参照）
9. **フィードバック対応**：修正指示があれば対応 → フィードバック蓄積.md に記録

### プレビューを渡すときのメッセージ（必ずこの形式で）

プレビューURLと一緒に、フィードバックの出し方＋まさきの実例を毎回セットで提示する。
顧問生さんが「何を言えばいいかわからない」状態にならないようにするのが目的。

> 📝 記事が完成しました！プレビューを確認してみてください：
>
> 🔗 編集用URL: https://〇〇.com/wp-admin/post.php?post=XXX&action=edit
> （右上の「プレビュー」で実際の表示を確認できます）
>
> ---
>
> 確認するときのポイントを紹介するね。
> 以下は、このスキルの開発者（まさき）が実際に出したフィードバックの例です。
> **同じように「ここが違う」を指摘するだけで、あなたのスキルがどんどん育ちます。**
>
> **💬 口調・文体：**
> - 「ですます調じゃないよ。〜だよ/〜だね調にして」→ 口調ルールが即修正された
> - 「この語尾は女性っぽいから使わないで」→ 以後その語尾が全記事からなくなった
> - 「〜だよ、が多すぎる。もっと語尾を散らして」→ 語尾分散ルール（連続回数制限）が追加された
>
> **💬 構成・デザイン：**
> - 「CTAボタンの上にキャッチを入れて。行間は詰めて」→ 完璧な行間テンプレートが確定し全記事に適用
> - 「チェックリストは囲い枠で囲って。タイトルも付けて」→ 囲い枠必須ルールが追加された
> - 「FAQはQ&A形式じゃなくて、見出し＋吹き出し＋本文で」→ テンプレートが差し替わった
>
> **💬 吹き出し：**
> - 「吹き出しのキャラクターをWP管理画面から変えられなくなった」→ 記法がGutenbergブロック形式に全面修正された
> - 「セリフに合ったアイコンを選んで」→ アイコン×感情マッピング表が作られた
>
> **💬 画像：**
> - 「もっと画像入れられるでしょ。公式サイトから探して」→ 1記事3〜5枚以上のルールに変わった
> - 「見出し画像が全部同じ。別々にして」→ 画像重複禁止ルールが追加された
>
> **💬 情報の扱い：**
> - 「参考記事からの一文コピペは絶対禁止」→ 20文字以上の一致チェックルールが追加された
> - 「ここは価値観の部分だから、勝手に書かないで聞いて」→ 価値観パートは必ず質問するルールに
>
> ---
>
> 「なんか違う」だけでもOK！どこが違うか聞き返すよ。
> スクリーンショットで見せてくれるのが一番早いです。
> 「ここは完璧」「ここはいいね」も言ってくれると、次も同じ品質を再現できます！

### 記事作成前チェックリスト

記事を書くたびに以下を確認（フィードバック蓄積に応じて項目が増えていく）：

**初期チェック項目：**
- [ ] 口調ガイドに従った文体か？
- [ ] 吹き出しはGutenbergブロック形式で書いたか？
- [ ] H2直後に画像を入れたか？
- [ ] 画像は全H2で別々か？
- [ ] CTAボタンの直上にキャッチ文を入れたか？
- [ ] 元記事の表は移植したか？
- [ ] 一文コピペがないか？
- [ ] 下書き（draft）で投稿するか？（公開しない）

---

## スクリプト仕様

### scripts/post_to_wp.py

```
使い方:
  python3 scripts/post_to_wp.py <HTMLファイルパス> <タイトル> [--status draft|publish] [--id 記事ID]

デフォルトはdraft（下書き）。publishを指定しない限り公開されない。
--id を付けると既存記事の更新。
```

### scripts/upload_image_to_wp.py

```
使い方:
  python3 scripts/upload_image_to_wp.py <画像URLまたはローカルパス> [--alt "代替テキスト"] [--skip-safety-check]

出力:
  WPのメディアURL（記事の img src に使える）

multipart/form-data形式でアップロード（SiteGuard WAF対策済み）。
```

### scripts/wp_test.py

```
使い方:
  python3 scripts/wp_test.py

.envの認証情報でWordPress REST APIに接続できるかテスト。
```

---

## トラブルシューティング

- **認証エラー（401）** → `.env` のパスワードが間違っている可能性。アプリケーションパスワードを再発行して `.env` を書き直してください
- **投稿API 403** → アプリパスワードの権限不足。管理者ユーザーで発行し直してください
- **REST APIが無効** → WordPress側で REST API を有効化する必要があります（通常は有効）
- **画像アップロードで403（SiteGuard）** → `upload_image_to_wp.py` が multipart/form-data 形式になっていることを確認
- **吹き出しのアイコンが変更できない** → 生HTMLではなく `<!-- wp:loos/balloon {"balloonID":"X"} -->` 形式で書いているか確認

> 💡 どのエラーでも、**エラーメッセージのスクショを送ってくれれば一緒に解決します！**
========== END FILE ==========

========== FILE: blog-builder/scripts/post_to_wp.py ==========
"""WordPress REST API で記事を下書き投稿する汎用スクリプト

使い方:
  python3 post_to_wp.py <HTMLファイルパス> <タイトル> [--status draft|publish] [--id 記事ID]

デフォルトはdraft（下書き）。publishを指定しない限り公開されない。
--id を付けると既存記事の更新。

.env に以下の3つが必要：
  WP_SITE_URL=https://あなたのドメイン
  WP_USERNAME=ログインID
  WP_APP_PASSWORD=アプリケーションパスワード
"""
import os
import sys
import base64
import json
import argparse
import urllib.request
import urllib.error
from pathlib import Path


def load_env(path):
    env = {}
    if not Path(path).exists():
        return env
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if "=" in line:
            k, v = line.split("=", 1)
            env[k.strip()] = v.strip().strip('"').strip("'")
    return env


def find_env():
    cur = Path(__file__).resolve().parent
    for _ in range(6):
        env_path = cur / ".env"
        if env_path.exists():
            return env_path
        cur = cur.parent
    raise FileNotFoundError(
        ".envファイルが見つかりません。scripts/ の親ディレクトリに .env を配置してください"
    )


def post_article(title, html, status="draft", categories=None, tags=None, post_id=None, password=None):
    env_path = find_env()
    env = load_env(env_path)
    site = env.get("WP_SITE_URL", "").rstrip("/")
    user = env.get("WP_USERNAME", "")
    pw = env.get("WP_APP_PASSWORD", "").replace(" ", "")

    if not all([site, user, pw]):
        print("❌ .env に WP_SITE_URL / WP_USERNAME / WP_APP_PASSWORD が揃っていません")
        sys.exit(1)

    token = base64.b64encode(f"{user}:{pw}".encode()).decode()
    payload = {
        "title": title,
        "content": html,
        "status": status,
    }
    if categories:
        payload["categories"] = categories
    if tags:
        payload["tags"] = tags
    if password:
        payload["password"] = password

    endpoint = f"{site}/wp-json/wp/v2/posts"
    if post_id:
        endpoint = f"{endpoint}/{post_id}"
        action = "更新"
    else:
        action = "新規投稿"
    print(f"🔄 {action}中: {endpoint}")

    data = json.dumps(payload).encode("utf-8")
    req = urllib.request.Request(
        endpoint,
        data=data,
        headers={
            "Authorization": f"Basic {token}",
            "Content-Type": "application/json; charset=utf-8",
        },
        method="POST",
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read())
            print("✅ 投稿成功")
            print(f"  記事ID : {result['id']}")
            print(f"  ステータス: {result['status']}")
            print(f"  タイトル : {result['title']['rendered']}")
            print(f"  URL    : {result['link']}")
            print(f"  編集用URL: {site}/wp-admin/post.php?post={result['id']}&action=edit")
            if result["status"] == "draft":
                preview = f"{result['link']}?preview=true&p={result['id']}"
                print(f"  プレビュー: {preview}")
            return result
    except urllib.error.HTTPError as e:
        body = e.read().decode(errors="replace")
        print(f"❌ HTTP {e.code}: {e.reason}")
        print(f"  レスポンス: {body[:1000]}")
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="WordPress下書き投稿")
    parser.add_argument("html_file", help="投稿するHTMLファイルのパス")
    parser.add_argument("title", help="記事タイトル")
    parser.add_argument(
        "--status",
        default="draft",
        choices=["draft", "publish", "pending", "private"],
        help="投稿ステータス (default: draft)",
    )
    parser.add_argument("--id", type=int, default=None, help="既存記事IDを指定すると更新")
    parser.add_argument("--password", default=None, help="記事のパスワード保護")
    args = parser.parse_args()

    html_path = Path(args.html_file)
    if not html_path.exists():
        print(f"❌ ファイルが見つかりません: {html_path}")
        sys.exit(1)

    html = html_path.read_text(encoding="utf-8")
    print(f"📄 ファイル: {html_path}")
    print(f"📝 タイトル: {args.title}")
    print(f"🏷️  ステータス: {args.status}")
    if args.password:
        print(f"🔒 パスワード保護: {args.password}")
    print(f"📦 本文サイズ: {len(html):,} chars\n")

    post_article(args.title, html, status=args.status, post_id=args.id, password=args.password)


if __name__ == "__main__":
    main()
========== END FILE ==========

========== FILE: blog-builder/scripts/upload_image_to_wp.py ==========
"""画像をダウンロード → WordPressメディアライブラリにアップロードするスクリプト

使い方:
  python3 upload_image_to_wp.py <画像URL> [--alt "代替テキスト"]
  python3 upload_image_to_wp.py <ローカルパス> [--alt "代替テキスト"]

出力:
  WPのメディアURL（記事の img src に使える）

multipart/form-data 形式でアップロード（SiteGuard WAF 対策済み）。

.env に以下の3つが必要：
  WP_SITE_URL=https://あなたのドメイン
  WP_USERNAME=ログインID
  WP_APP_PASSWORD=アプリケーションパスワード
"""
import os
import sys
import base64
import json
import argparse
import urllib.request
import urllib.parse
import urllib.error
import mimetypes
import tempfile
import uuid
from pathlib import Path


def load_env(path):
    env = {}
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if "=" in line:
            k, v = line.split("=", 1)
            env[k.strip()] = v.strip().strip('"').strip("'")
    return env


def find_env():
    cur = Path(__file__).resolve().parent
    for _ in range(6):
        env_path = cur / ".env"
        if env_path.exists():
            return env_path
        cur = cur.parent
    raise FileNotFoundError(
        ".envファイルが見つかりません。scripts/ の親ディレクトリに .env を配置してください"
    )


def download_image(url, dest):
    req = urllib.request.Request(
        url,
        headers={"User-Agent": "Mozilla/5.0"},
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        content_type = resp.headers.get("Content-Type", "")
        data = resp.read()
    if not content_type.startswith("image/"):
        raise ValueError(f"画像ではありません: {content_type}")
    dest.write_bytes(data)
    return content_type, len(data)


def upload_to_wp(file_path, alt_text=""):
    env = load_env(find_env())
    site = env["WP_SITE_URL"].rstrip("/")
    user = env["WP_USERNAME"]
    pw = env["WP_APP_PASSWORD"].replace(" ", "")
    token = base64.b64encode(f"{user}:{pw}".encode()).decode()

    filename = file_path.name
    if not filename.lower().endswith((".jpg", ".jpeg", ".png", ".gif", ".webp")):
        filename += ".jpg"
    mime, _ = mimetypes.guess_type(filename)
    if not mime:
        mime = "image/jpeg"

    file_data = file_path.read_bytes()

    boundary = uuid.uuid4().hex
    body = b""
    body += f"--{boundary}\r\n".encode()
    body += f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'.encode()
    body += f"Content-Type: {mime}\r\n\r\n".encode()
    body += file_data
    body += f"\r\n--{boundary}--\r\n".encode()

    req = urllib.request.Request(
        f"{site}/wp-json/wp/v2/media",
        data=body,
        headers={
            "Authorization": f"Basic {token}",
            "Content-Type": f"multipart/form-data; boundary={boundary}",
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
        },
        method="POST",
    )

    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            result = json.loads(resp.read())
            media_id = result["id"]
            media_url = result["source_url"]

            if alt_text:
                update_req = urllib.request.Request(
                    f"{site}/wp-json/wp/v2/media/{media_id}",
                    data=json.dumps({"alt_text": alt_text}).encode(),
                    headers={
                        "Authorization": f"Basic {token}",
                        "Content-Type": "application/json",
                        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
                    },
                    method="POST",
                )
                urllib.request.urlopen(update_req, timeout=30).read()
            return {
                "id": media_id,
                "url": media_url,
                "width": result.get("media_details", {}).get("width"),
                "height": result.get("media_details", {}).get("height"),
            }
    except urllib.error.HTTPError as e:
        body_resp = e.read().decode(errors="replace")
        print(f"❌ HTTP {e.code}: {body_resp[:500]}")
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="画像をWPにアップロード")
    parser.add_argument("source", help="画像URLまたはローカルパス")
    parser.add_argument("--alt", default="", help="代替テキスト")
    parser.add_argument("--skip-safety-check", action="store_true", help="安全ドメインチェックをスキップ")
    args = parser.parse_args()

    if args.source.startswith("http"):
        print(f"📥 ダウンロード中: {args.source}")
        with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
            tmp_path = Path(tmp.name)
        content_type, size = download_image(args.source, tmp_path)
        print(f"  ✓ {size:,} bytes ({content_type})")
    else:
        tmp_path = Path(args.source)
        if not tmp_path.exists():
            print(f"❌ ファイルが見つかりません: {tmp_path}")
            sys.exit(1)
        print(f"📁 ローカルファイル: {tmp_path}")

    print(f"📤 WPにアップロード中...")
    result = upload_to_wp(tmp_path, alt_text=args.alt)

    print(f"\n✅ アップロード成功")
    print(f"  メディアID: {result['id']}")
    print(f"  URL: {result['url']}")
    if result["width"]:
        print(f"  サイズ: {result['width']}×{result['height']}px")
    print(f"\n📋 記事用HTML:")
    print(f'<figure class="wp-block-image size-large"><img src="{result["url"]}" alt="{args.alt}" /></figure>')


if __name__ == "__main__":
    main()
========== END FILE ==========

========== FILE: blog-builder/scripts/wp_test.py ==========
"""WordPress REST API 接続テストスクリプト

使い方:
  python3 wp_test.py

.env の認証情報でWordPress REST APIに接続できるかテストします。
テスト内容:
  1. サイトURLへの接続確認
  2. REST API エンドポイントの確認
  3. 認証情報の確認（投稿一覧の取得）
  4. メディアアップロード権限の確認
"""
import sys
import base64
import json
import urllib.request
import urllib.error
from pathlib import Path


def load_env(path):
    env = {}
    for line in Path(path).read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if "=" in line:
            k, v = line.split("=", 1)
            env[k.strip()] = v.strip().strip('"').strip("'")
    return env


def find_env():
    cur = Path(__file__).resolve().parent
    for _ in range(6):
        env_path = cur / ".env"
        if env_path.exists():
            return env_path
        cur = cur.parent
    raise FileNotFoundError(
        ".envファイルが見つかりません。scripts/ の親ディレクトリに .env を配置してください"
    )


def main():
    print("🔍 WordPress API接続テストを開始します...\n")

    # .env読み込み
    try:
        env_path = find_env()
        env = load_env(env_path)
        print(f"✅ .env ファイル発見: {env_path}")
    except FileNotFoundError as e:
        print(f"❌ {e}")
        sys.exit(1)

    site = env.get("WP_SITE_URL", "").rstrip("/")
    user = env.get("WP_USERNAME", "")
    pw = env.get("WP_APP_PASSWORD", "").replace(" ", "")

    # 必須項目チェック
    missing = []
    if not site:
        missing.append("WP_SITE_URL")
    if not user:
        missing.append("WP_USERNAME")
    if not pw:
        missing.append("WP_APP_PASSWORD")
    if missing:
        print(f"❌ .env に以下が設定されていません: {', '.join(missing)}")
        sys.exit(1)

    print(f"  サイトURL: {site}")
    print(f"  ユーザー名: {user}")
    print(f"  パスワード: {'*' * min(len(pw), 8)}... ({len(pw)}文字)")

    token = base64.b64encode(f"{user}:{pw}".encode()).decode()

    # テスト1: サイト情報取得
    print(f"\n🔗 テスト1: サイト情報を取得中...")
    try:
        req = urllib.request.Request(
            f"{site}/wp-json/",
            headers={"User-Agent": "Mozilla/5.0"},
        )
        with urllib.request.urlopen(req, timeout=15) as resp:
            data = json.loads(resp.read())
            print(f"  ✅ サイト名: {data.get('name', '不明')}")
            print(f"  ✅ REST API: 有効")
    except urllib.error.HTTPError as e:
        print(f"  ❌ HTTP {e.code}: REST APIにアクセスできません")
        if e.code == 404:
            print(f"    → サイトURL（{site}）が間違っているか、REST APIが無効です")
        sys.exit(1)
    except Exception as e:
        print(f"  ❌ 接続エラー: {e}")
        print(f"    → サイトURL（{site}）にアクセスできません。URLを確認してください")
        sys.exit(1)

    # テスト2: 認証テスト（投稿一覧取得）
    print(f"\n🔑 テスト2: 認証テスト中...")
    try:
        req = urllib.request.Request(
            f"{site}/wp-json/wp/v2/posts?per_page=1&context=edit&_fields=id,title",
            headers={
                "Authorization": f"Basic {token}",
                "User-Agent": "Mozilla/5.0",
            },
        )
        with urllib.request.urlopen(req, timeout=15) as resp:
            posts = json.loads(resp.read())
            print(f"  ✅ 認証成功！（投稿数: {resp.headers.get('X-WP-Total', '不明')}件）")
    except urllib.error.HTTPError as e:
        print(f"  ❌ HTTP {e.code}: 認証に失敗しました")
        if e.code == 401:
            print(f"    → ユーザー名またはアプリケーションパスワードが間違っています")
            print(f"    → パスワードはスペースなしで入力していますか？")
        elif e.code == 403:
            print(f"    → このユーザーに投稿の権限がありません")
            print(f"    → 管理者ユーザーのアプリケーションパスワードを使ってください")
        sys.exit(1)

    # テスト3: メディアアップロード権限確認
    print(f"\n📷 テスト3: メディアアップロード権限を確認中...")
    try:
        req = urllib.request.Request(
            f"{site}/wp-json/wp/v2/media?per_page=1&_fields=id",
            headers={
                "Authorization": f"Basic {token}",
                "User-Agent": "Mozilla/5.0",
            },
        )
        with urllib.request.urlopen(req, timeout=15) as resp:
            print(f"  ✅ メディアライブラリへのアクセスOK")
    except urllib.error.HTTPError as e:
        print(f"  ⚠️ HTTP {e.code}: メディアライブラリにアクセスできません")
        print(f"    → 画像アップロードが動作しない可能性があります")

    # 完了
    print(f"\n{'='*50}")
    print(f"🎉 全テスト完了！ WordPress API連携は正常に動作しています。")
    print(f"{'='*50}")


if __name__ == "__main__":
    main()
========== END FILE ==========

========== FILE: はじめにお読みください.md ==========
# はじめにお読みください — blog-builder

**あなた専用のWordPressブログ記事作成スキル** を組み上げる、ビルダー型のスキルです。

このスキルを使うと、以下が自動で完成します：

1. **WordPress API連携**（あなたのブログに記事を自動投稿できるようになる）
2. **あなたの既存記事の全文解析**（口調・構成・テンプレートを学習）
3. **あなた専用のナレッジファイル群**（ブログ作成の指針）
4. **投稿・画像アップロードスクリプト**
5. **`/blog` コマンド**（以後、これだけで記事が書ける）

セットアップ完了後は、**「ブログ書いて」「ブログ作って」と頼むだけで、あなたの口調・構成・デザインで下書きが完成** します。

---

## 🌐 対応環境

| AIツール | OS | 対応 |
|---|---|---|
| **Claude Code** | macOS | ✅ |
| **Claude Code** | Windows | ✅ |
| **Codex**（OpenAI Codex CLI） | macOS | ✅ |
| **Codex**（OpenAI Codex CLI） | Windows | ✅ |

各環境向けに `SKILL.md`（Claude Code用）と `AGENTS.md`（Codex用）を同梱しています。

---

## 前提条件

1. **WordPress（SWELLテーマ）** で運営している自分のブログがあること
2. **Claude Code または Codex** がインストール済みで、ログイン済みであること
3. **Python 3** がインストールされていること（追加パッケージ不要・標準ライブラリのみ使用）

---

## セットアップ手順（AIに丸投げ・推奨）

このZIPを Claude Code または Codex のチャットに添付して、以下のように指示するだけでOKです：

```
添付したZIPファイルを確認し、ZIP内の「INSTALL_FOR_AI.md」に従って、
スキルをセットアップしてください。
セットアップ後、ブログビルダーを起動できる状態にしてください。
```

AIがあなたの環境（OS・AIツール）を判定して、適切な場所に自動で設置してくれます。

---

## 手動セットアップ（自分でやりたい方）

### 設置先の早見表

| AIツール | OS | 設置先 |
|---|---|---|
| Claude Code | macOS | `~/.claude/skills/blog-builder/` |
| Claude Code | Windows | `%USERPROFILE%\.claude\skills\blog-builder\` |
| Codex | macOS | `~/.codex/skills/blog-builder/` |
| Codex | Windows | `%USERPROFILE%\.codex\skills\blog-builder\` |

### macOS（ターミナル）

**Claude Code を使う方**:
```bash
mkdir -p ~/.claude/skills
cp -R blog-builder ~/.claude/skills/
```

**Codex を使う方**:
```bash
mkdir -p ~/.codex/skills
cp -R blog-builder ~/.codex/skills/
```

### Windows（PowerShell）

**Claude Code を使う方**:
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\skills"
Copy-Item -Recurse blog-builder "$env:USERPROFILE\.claude\skills\"
```

**Codex を使う方**:
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\skills"
Copy-Item -Recurse blog-builder "$env:USERPROFILE\.codex\skills\"
```

### 設置確認

**macOS**：
```bash
ls ~/.claude/skills/blog-builder/   # Claude Codeの場合
ls ~/.codex/skills/blog-builder/    # Codexの場合
```

**Windows**：
```powershell
Get-ChildItem "$env:USERPROFILE\.claude\skills\blog-builder"   # Claude Codeの場合
Get-ChildItem "$env:USERPROFILE\.codex\skills\blog-builder"    # Codexの場合
```

`SKILL.md`（または `AGENTS.md`）と `scripts/` フォルダが見えればOKです。

---

## 起動方法

Claude Code または Codex を再起動してから、以下のように依頼してください：

### Claude Code をお使いの方

```
/blog-builder
```

または：

```
ブログビルダー起動して
ブログスキル構築して
```

### Codex をお使いの方

```
ブログビルダーを起動して
ブログスキル構築して
```

---

## 全体の流れ（6ステップ）

スキル起動後、AIが以下の順番で進めてくれます。

```
Step 1: WordPress API連携の設定（5〜10分）
   ↓
Step 2: 既存記事を分析（3〜5分）
   ↓
Step 3: あなた専用のナレッジファイル自動生成（自動）
   ↓
Step 4: 投稿・画像アップロードスクリプト設置（自動）
   ↓
Step 5: 最初の記事を書いてみる（10〜15分）
   ↓
Step 6: フィードバックで精度を上げていく（継続）
```

完成すると、毎回 **「ブログ書いて」だけで、あなた仕様の記事が書ける** ようになります。

---

## ⚠️ 超重要なお約束

WordPressのログインIDやパスワードを **このチャットには絶対に貼らないでください**。

スキルが `.env` ファイルを自動作成して、エディタで開いてくれます。
**そこにだけ書いて、保存してください**。

`.env` ファイルはあなたのPCの中にだけ保存され、AIには内容が見えないようになっています。

---

## このスキルでできること（完成後のイメージ）

1. 「ブログ書いて」と頼むだけで、あなたの口調で記事が書ける
2. 過去記事から学んだテンプレート構成で、毎回安定したクオリティ
3. アイキャッチ画像・本文画像も自動で調達
4. SWELLテーマのデザイン（吹き出し・カード・FAQ・CTA）を自動適用
5. 投稿は下書き保存（あなたが確認してから公開）
6. フィードバックを蓄積するたびにAIが賢くなる

---

## 困ったとき

### スキルが認識されない

スキル設置場所に `SKILL.md`（または `AGENTS.md`）と `scripts/` が両方あるか確認。
AIツール（Claude Code / Codex）を一度終了して、再起動するのが確実です。

### WordPress API連携でエラーが出る

スクショを撮って、AIに「これどこを押せばいい?」と聞いてください。
パスワードが映ったスクショは送らないように注意してください。

### Pythonが動かない

`python3 --version`（macOS）または `python --version`（Windows）で確認してください。
バージョン 3.8 以上が必要です。

### その他、困ったとき

AI（Claude Code / Codex）に直接質問するのが一番早いです。スキルの中身を理解した上で答えてくれます。

---

## ファイル構成

```
blog-builder_配布パッケージ/
├── はじめにお読みください.md（このファイル）
├── INSTALL_FOR_AI.md（AI自動セットアップ用指示書）
└── blog-builder/
    ├── SKILL.md（Claude Code用エントリポイント）
    ├── AGENTS.md（Codex用エントリポイント・同内容）
    └── scripts/
        ├── post_to_wp.py（記事投稿スクリプト）
        ├── upload_image_to_wp.py（画像アップロードスクリプト）
        └── wp_test.py（接続テストスクリプト）
```

---

## ライセンス・使用範囲

- このスキルは AI顧問の顧問生さん専用配布物です。第三者への再配布はご遠慮ください
- スキル内のロジック・ナレッジは、まさきの蓄積をもとに作られています

---

楽しんでブログを書いてください！
========== END FILE ==========
