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

---

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

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

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

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

---

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

## 手順

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

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

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

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

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

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

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

| ファイル | 行数 |
|---|---|
| .gitignore | 2 |
| README.md | 134 |
| SKILL.md | 148 |
| assets/sample.md | 21 |
| references/image_insertion.md | 59 |
| references/note_voice_and_design.md | 53 |
| references/troubleshooting.md | 61 |
| scripts/login.mjs | 43 |
| scripts/patch.mjs | 55 |
| scripts/save_draft.mjs | 82 |
| scripts/setup.mjs | 73 |

---

## ファイル定義

========== FILE: .gitignore ==========
runtime/
*.log
========== END FILE ==========

========== FILE: README.md ==========
# note自動下書きスキル｜導入手順（はじめにお読みください）

AIに「このブログをnote化して」とお願いすると、**note記事の下書きを自動で作ってくれる**スキルです。
文章のリライト・note装飾（見出し・引用・区切り線）・画像の挿入まで自動。
**公開と予約だけは自分で確認して押す**、安全設計になっています。

対応：**Mac / Windows** ・ **Claude Code / Codex** の全組み合わせ。

---

## ⚠️ 最初に必ず読んでください（大事）

- noteには公式のAPIがありません。このスキルは**非公式ツール**を使って動きます。
- そのため note の規約上は**グレーゾーン**で、アカウント停止のリスクがゼロではありません。
- **必ず「実験用のサブ垢」で試してください。** メインの大事なアカウントでは使わないでください。
- **下書きまで自動／公開・予約は自分の手で**、を守れば安全度がぐっと上がります。
- 投稿は**低頻度（週数本まで）**にし、連投はしないでください。

---

## 1. 必要なもの（先に準備）

| 必要なもの | 入手先・補足 |
|---|---|
| Node.js 18以上 | https://nodejs.org/ →「LTS」版をインストール |
| Google Chrome | https://www.google.com/chrome/ （無くても動きますが推奨） |
| Claude Code または Codex | どちらかが使える状態 |
| note の**サブアカウント** | 実験用に1つ作っておく |

インストールできたか確認（ターミナル／WindowsはPowerShellで）：
```
node -v
```
`v18` 以上の数字が出ればOK。

---

## 2. フォルダを置く

このフォルダ（`note-auto-draft`）を、下記の場所に置きます。

**Claude Codeの人：**
- Mac → `~/.claude/skills/` の中
- Windows → `C:\Users\あなたの名前\.claude\skills\` の中

**Codexの人：**
- どこでもOK（例：`~/note-auto-draft`）

---

## 3. セットアップを実行（自動インストール）

ターミナルでこのフォルダに移動して、次を実行：
```
node scripts/setup.mjs
```
必要なものが自動でインストールされ、最後に「登録スニペット」が表示されます。
**この表示をコピーして控えておいてください**（次で使います）。

---

## 4. Claude Code / Codex に登録

控えたスニペットを貼ります。

**Claude Codeの人：**
- プロジェクト直下の `.mcp.json` の `mcpServers` に、表示された `note-draft` を追加
- （または、表示された内容で `claude mcp add-json` を実行）

**Codexの人：**
- 設定ファイルの末尾に、表示された `[mcp_servers.note_draft]` ブロックを貼る
  - Mac → `~/.codex/config.toml`
  - Windows → `C:\Users\あなたの名前\.codex\config.toml`

貼ったら、**Claude Code / Codex を一度再起動**してください。

---

## 5. noteにログイン（最初の1回）

```
node scripts/login.mjs
```
- ブラウザが開きます → **サブ垢で note にログイン**
  - おすすめは「**メールアドレスでログイン**」（Googleログインは弾かれることがあります）
- ログインできたら、ターミナルに戻って **Enter**
- `✅ セッションを保存しました` と出たら完了！

※ このログインは1〜2週間で切れます。動かなくなったら、もう一度この手順を実行してください。

---

## 6. テスト（動作確認）

```
node scripts/save_draft.mjs assets/sample.md
```
note の「下書き」一覧にテスト記事が出れば**成功**です！（確認したら削除してOK）
※ 下書き作成中に**ブラウザの窓が一瞬開くのは正常**です。

---

## 7. 使い方

**Claude Codeの人：**
- 「`/note-auto-draft`」または「このブログをnote化して下書きして」
- 「この原稿をnoteの下書きにして」
- 「note記事に画像を入れて。内容を読んで最適な場所に入れて」

**Codexの人：**
- 再起動後、note の下書きツール（`save_draft`）が使えます。
- 「このURLをnote記事にして下書きを作って」などと指示。

できあがった下書きを note で確認し、問題なければ**自分で公開 or 予約投稿**してください。

---

## 困ったときは

`references/troubleshooting.md`（トラブル対処）を見てください。
よくあるもの：
- 「タイトル欄が見つからない」→ `node scripts/patch.mjs` を実行
- しばらく使うと失敗 → `node scripts/login.mjs` でログインし直す
- Googleログインが弾かれる →「メールアドレスでログイン」を使う

---

## 安全に使うために（もう一度）

- ✅ 実験用サブ垢で使う
- ✅ 下書きまで自動、公開・予約は自分の手で
- ✅ 低頻度（週数本まで）・連投しない

楽しいnoteライフを！
========== END FILE ==========

========== FILE: SKILL.md ==========
---
name: note-auto-draft
description: note.comの「自動下書き」を実現するセットアップ＋運用スキル。①導入セットアップ（MCP/Playwright導入・headfulパッチ・Claude Code/Codex登録・ログイン・疎通テスト）②MCP経由でnote下書きを自動作成（URL/原稿/テーマ→利用者本人の口調＆note装飾→下書き化）③画像を内容を読んで最適位置に自動挿入、の3役を担う。「/note-auto-draft」「noteの自動下書きをセットアップ」「noteをMCPで下書き」「noteに自動で下書き作って」「noteの下書き自動化を導入」「note自動投稿の設定」「このブログをnote化して下書きして」「note記事に画像を自動挿入」と言われたら使う。公開・予約は手動（設計A）。非公式ツール利用のため実験用サブ垢・低頻度を推奨。
---

## 下書きの正確性と再実行

元資料の事実、本人の見解、表現の変更を区別する。別名義の口調や体験を持ち込まない。
URLが読めなければ取得できた範囲を伝え、本文を依頼する。タイトルや検索抜粋から全文を再現しない。
本文・画像・CTAを用意してから下書きを1回作る。応答が不明ならnoteの下書き一覧で作成の有無を確認し、同じ記事を連続作成しない。
保存後はタイトル・本文末尾・画像位置・下書き状態を確認する。確認できない項目は未確認とする。
既存の認証状態をセットアップで消さない。認証状態ファイルは認証情報として扱い、値やスクリーンショットを共有しない。
MCPや依存パッケージは実際のツール定義とインストール版を確認する。想定したsave_draftがなければ停止し、publish系ツールへ置き換えない。

# note-auto-draft — note自動下書きのセットアップ＆運用スキル

note公式APIは存在しないため、非公式の `@gonuts555/note-post-mcp`（Playwrightでブラウザ操作）を使い、
**文章→note装飾→下書き作成**までを自動化する。**公開・予約は人間が手動**（＝設計A／規約グレー対策）。

> ⚠️ 必ず最初に `references/troubleshooting.md` の「大前提：設計A運用」を踏まえること。
> 推奨：実験用サブ垢・週数本まで・連投しない。本番アカウントでも公開は手動厳守。

このスキルのベースディレクトリを `SKILL_DIR` と呼ぶ（このファイルのある場所）。

## 対応環境
- **OS**: macOS / Windows 両対応（パスは `os.homedir()`／スラッシュ統一で自動処理。コマンドは共通）。
- **AIツール**: Claude Code / Codex 両対応（setup.mjsが両方の登録スニペットを出力）。
- **ブラウザ**: Google Chrome 推奨。無ければ同梱Chromiumに自動フォールバック（headful維持）。
- 設定ファイル: Claude Code=`.mcp.json`、Codex=`~/.codex/config.toml`（Win: `%USERPROFILE%\.codex\config.toml`）。

---

## ステップ0：意図を判定して分岐

ユーザーの依頼から、どれかに振り分ける（複数にまたがる場合は SETUP→DRAFT→IMAGE の順で連結）：

- **SETUP**（導入したい／初めて／「セットアップ」「設定」「導入」） → セクションA
- **DRAFT**（note記事を下書きにしたい／URLや原稿をnote化） → セクションB
- **IMAGE**（画像も入れたい／画像挿入） → セクションC（DRAFTの一部として実行）

判定に迷う＆セットアップ状況が不明なら、まず `~/.note-state.json` と `SKILL_DIR/runtime/node_modules/@gonuts555/note-post-mcp/build/index.js` の存在を確認し、無ければ SETUP から案内する。

---

## セクションA：SETUP（導入セットアップ）

目的：このスキル単体で note自動下書きが動く状態にする。

### A-1. 依存導入＋パッチ
`SKILL_DIR` で実行：
```bash
node scripts/setup.mjs
```
これで runtime/ に note-post-mcp + playwright を導入、Chromium導入、headfulパッチ適用まで自動。
出力末尾の `SETUP_RESULT`（SERVER_PATH / STATE_PATH と登録スニペット）を控える。

### A-2. Claude Code / Codex に登録
setup.mjs が出力したスニペットを、既存設定を壊さずに追記する（エージェントが Edit で安全にマージ）：
- **Claude Code**：プロジェクト直下 `.mcp.json` の `mcpServers` に `note-draft` を追加（無ければ `claude mcp add-json` でも可）。
- **Codex**：`~/.codex/config.toml` の末尾に `[mcp_servers.note_draft]` ブロックを追加。
- どちらも反映には**各ツールの再起動**が必要だと伝える。

### A-3. ログイン
ユーザーにターミナルで実行してもらう（ブラウザログインはユーザー本人しかできない）：
```bash
node scripts/login.mjs
```
Chromeが開く → **「メールアドレスでログイン」推奨**（Googleログインは弾かれることがある→troubleshooting.md）→ Enter → `~/.note-state.json` 生成。

### A-4. 疎通テスト
`assets/sample.md`（無ければ簡単なテストMarkdownを作る）で下書きを1本作る：
```bash
node scripts/save_draft.mjs <テストmd>
```
`success: true` と下書きURLが返れば完了。テスト下書きは削除を案内。

---

## セクションB：DRAFT（note下書きを自動作成）＝ /note(MCP版)

`references/note_voice_and_design.md` を読んでから実行。

### B-1. 素材を受け取る
- URL（ブログ/ニュースレター等） → **WebFetchで全文を構造化抽出**（見出し・数字・固有名詞・手順を漏らさず）
- 原稿/台本テキスト → そのまま読む
- テーマだけ → 構成案を作って確認

### B-2. ユーザーの口調を適用
- あなた専用の文体プロファイル（口調・構成をまとめたメモ）があれば読んで適用する。
- 無ければ、あなたの過去note/発信サンプルを1〜数本もらって口調（一人称・敬体/常体・口癖・絵文字頻度）を学習してから書く。事実は保持しつつリライト。

### B-3. note装飾でMarkdown化
- front matter（title / tags）を付ける。
- 見出し`##`／引用`>`（感情ピーク・核心のみ）／区切り線`---`／箇条書き`-`／番号`1.` を使う。
- **表は箇条書き/番号に変換**。**太字`**`は使わない**（note_voice_and_design.md）。

### B-4.（任意）画像挿入 → セクションC

### B-5. 下書き作成
Markdownをファイル保存し、`SKILL_DIR` で：
```bash
node scripts/save_draft.mjs <作成したmd> [アイキャッチ画像]
```
（Chrome窓が一瞬開くのは正常）。

### B-6. 報告
- 下書きURLを伝える。
- **公開・予約はユーザーが手動**（noteの公開設定→予約投稿はnoteプレミアム）と必ず添える。
- 気になる点（CTA・数字・タイトル）の調整可を伝える。

---

## セクションC：IMAGE（画像を内容を読んで最適位置に挿入）

`references/image_insertion.md` を読んで実行。要点：

1. 画像を集める（ユーザー提供 or Codexで生成＝サブスク枠／API直叩き禁止）。
2. **各画像を Read ツールで開いて内容を把握**（何が写っているか・どのセクションと一致するか）。
3. 配置ルールで最適位置を決定（アイキャッチ=`thumbnail_path`、セクション画像=該当`##`直後、図解=説明本文の直後、感情写真=引用ブロック手前）。
4. 本文Markdownに `![説明](絶対パス)` を独立行・前後空行で差し込む。
5. `node scripts/save_draft.mjs <md> <アイキャッチ>` で作成（本文画像は自動アップ）。

機械的に並べず、**画像の中身に合った文脈の隣**に置くこと。

---

## ファイル構成
```
note-auto-draft/
├── SKILL.md
├── scripts/
│   ├── setup.mjs        # 導入＋パッチ＋登録スニペット出力
│   ├── login.mjs        # ブラウザログイン → ~/.note-state.json
│   ├── patch.mjs        # headful再パッチ（再インストール後に実行）
│   └── save_draft.mjs   # MCPクライアント（md→下書き作成）
├── references/
│   ├── note_voice_and_design.md  # 文体変換＆Markdown→note装飾
│   ├── image_insertion.md        # 画像を内容を読んで最適挿入
│   └── troubleshooting.md        # 設計A前提・不具合対処
└── runtime/             # setup.mjsが生成（node_modules等・gitignore対象）
```

## 禁止事項
- 公開・予約まで完全自動にする（必ず下書き止まりで、公開は人間）。
- 表(Markdown table)や `**太字**`、HTMLタグを本文に入れる。
- メール/パスワードでの自動ログインを実装する（reCAPTCHAで不安定＋規約リスク）。
- 認証情報(~/.note-state.json)をコミット・共有する。
- 「刺さった」「刺さる」を使う。
========== END FILE ==========

========== FILE: assets/sample.md ==========
---
title: 【テスト】note-auto-draft 疎通確認
tags: [テスト]
---

これは note-auto-draft スキルの疎通確認用の下書きです。

## 見出しのテスト

引用ブロックのテスト。

> セットアップが成功すれば、この囲みが引用ブロックになる。

区切り線のテスト。

---

- 箇条書き1
- 箇条書き2

この下書きが表示されていれば成功です。確認後は削除してください。
========== END FILE ==========

========== FILE: references/image_insertion.md ==========
# 画像の自動挿入（内容を読んで最適位置に入れる）

note-post-mcp は、Markdown本文中の `![説明](ローカル画像パス)` を見つけると、その画像を**自動でnoteにアップロード**して該当位置に差し込む。アイキャッチは `save_draft` の `thumbnail_path` 引数（または scripts/save_draft.mjs の第2引数）で指定する。

対応形式: png / jpg / jpeg / gif。パスは**絶対パス推奨**。

---

## 方針：画像内容を読んで、最適な場所に入れる

「ただ貼る」のではなく、**画像の中身をAIが読み取って、関連する文脈の隣に配置する**のが理想。手順は以下。

### ステップ1：画像を集める
- ユーザーが用意した画像 → パスを受け取る
- 無ければ生成を提案（Codexの画像生成＝サブスク枠を使う。例: アイキャッチ、図解、説明バナー）

### ステップ2：各画像の内容をAIが読む
- **Readツールで画像を1枚ずつ開く**（画像はビジュアルとして認識できる）
- 何が写っているか・どのセクションの内容と一致するかをメモする
  - 例: 料金表の画像 → 「料金」セクション / 家族写真 → 体験談セクション / グラフ → データ提示箇所

### ステップ3：最適位置を決める（配置ルール）
| 画像の種類 | 入れる場所 |
|---|---|
| アイキャッチ（タイトル画像） | `thumbnail_path` で指定（本文先頭ではなくサムネ枠） |
| セクションを象徴する画像 | 対応する `## 見出し` の直後 |
| 図解・グラフ・スクショ | それが説明している本文の直後 |
| 感情を補強する写真 | クライマックス（引用ブロック）の手前 |
| 商品・サービスのバナー | CTAの近く |

### ステップ4：Markdownに差し込む
画像は**独立した行**に、前後を空行で囲んで置く：

```markdown
## 料金はこの3段階だけ

![楽天モバイルの料金プラン表](/Users/you/images/price.png)

ご覧の通り、使った分だけの従量制で…
```

### ステップ5：作成
```bash
# アイキャッチあり + 本文画像は ![](...) で自動アップ
node scripts/save_draft.mjs article.md /Users/you/images/eyecatch.png
```

---

## チェックリスト
- [ ] 画像パスは絶対パスか
- [ ] 本文画像は `![説明](パス)` で独立行・前後空行
- [ ] アイキャッチは `thumbnail_path`（第2引数）で渡したか
- [ ] 各画像は「内容を読んで」関連箇所に置いたか（無関係な位置に機械的に並べない）
- [ ] 形式は png/jpg/jpeg/gif か

## 補足：画像生成を絡める場合
- Codexの画像生成（サブスク枠内）でアイキャッチや図解を作る。OpenAI APIキー直叩き等の従量課金は避ける。
- 生成 → 保存パスを受け取る → ステップ2以降と同じ流れで内容を読んで配置。
========== END FILE ==========

========== FILE: references/note_voice_and_design.md ==========
# note転用：文体変換 & 装飾ルール

note-post-mcp は **Markdownをnoteエディタに流し込む**。対応している装飾と、変換時の注意をまとめる。

## 1. Markdown → note装飾の対応表（これだけ使う）

| Markdown | note装飾 | 備考 |
|---|---|---|
| `## 見出し` | 大見出し(h2) | メインの見出し |
| `### 見出し` | 中見出し(h3) | サブ。多用しない |
| `> 文章` | 引用ブロック（出典枠つき囲み） | **感情のピーク/核心**で使う |
| `---`（単独行） | 区切り線 | セクション区切り |
| `- 項目` | 箇条書き | |
| `1. 項目` | 番号リスト | 手順・条件に最適 |
| ` ```code``` ` | コードブロック | |
| `![説明](ローカルパス)` | 画像（自動アップロード） | → image_insertion.md |
| URL単独行 | リンクカード埋め込み | 行頭からURLだけ |

## 2. 使ってはいけない / 効かないもの

- **表（Markdown table）→ 非対応**。料金表・比較表は必ず「箇条書き」か「番号リスト」に変換する。
- **太字 `**文字**` → 不確実**。noteのインライン変換に依存し、効かないと `**` が残る。原則使わず、見出し・引用・リストで強弱をつける。
- `<img>` `<table>` `<div>` `style属性` などのHTMLタグは入れない（Markdownのみ）。

## 3. front matter（必須）

Markdownの先頭に必ず付ける：

```markdown
---
title: 記事タイトル
tags: [タグ1, タグ2, タグ3]
---

本文…
```

## 4. 文体変換（ユーザーの口調に合わせる）

- あなた専用の文体プロファイル（口調・構成をまとめたメモ）があれば**必ず読んで適用**する。
- 無い場合は、あなたの過去note/発信サンプルを1〜数本もらって口調（一人称・敬体/常体・口癖・絵文字頻度）を学習してから書く。
- 引用ブロックは「価値観の核」「感情のピーク」「結論の言い切り」に限定（単なる情報引用には使わない）。
- note記事は**画像が命**。長文だけにせず、アイキャッチ＋セクション画像を提案する（→ image_insertion.md）。

## 5. 元記事/原稿からの転用フロー

1. 元コンテンツ（URL/原稿/テーマ）を取得・読解（URLは WebFetch で全文を構造化抽出）
2. 事実（数字・固有名詞・手順）を保持しつつ、ユーザーの口調にリライト
3. 上表のMarkdownで装飾（表→箇条書き変換を忘れない）
4. front matter を付与
5. （任意）画像を最適位置に挿入 → image_insertion.md
6. `node scripts/save_draft.mjs <md>` で下書き作成
7. **公開・予約はユーザーが手動**で（設計A）
========== END FILE ==========

========== FILE: references/troubleshooting.md ==========
# トラブルシューティング & 重要な前提

## ⚠️ 大前提：これは非公式・設計A運用
- note は公式の投稿APIを提供していない。このスキルは**非公式ツール**(note-post-mcp / Playwright)を使う。
- note規約上は**グレーゾーン**。アカウント停止時は売上没収・データ返却なしのリスク。
- そのため **設計A** で運用する：**下書き作成までを自動／公開・予約は人間が手動**。
- 推奨：**実験用サブ垢・低頻度（週数本まで）・連投しない**。本番アカウントでも「公開は手動」を厳守。

---

## よくある不具合と対処

### 1.「タイトル欄が見つからない」でタイムアウトする
- 原因：headlessではnoteエディタが描画されない。
- 対処：`node scripts/patch.mjs` を実行（headful＋本物Chrome起動に変更）。
- npmで本体を再インストール/更新したら**毎回 patch.mjs を再実行**。
- 下書き作成時に**Chrome窓が一瞬開くのは正常**。

### 2. Googleログインが「安全でない可能性」で弾かれる
- 原因：Googleは自動操作ブラウザでのGoogleログインをブロックする。
- 対処：login.mjs では**「メールアドレスでログイン」**を使う（note自身のメール/パスワード）。
  - パスワード未設定なら、noteログイン画面の「パスワードをお忘れですか？」で設定してから。

### 3. しばらく使うと作成に失敗する
- 原因：セッション（~/.note-state.json）の失効（概ね1〜2週間）。
- 対処：`node scripts/login.mjs` を再実行してセッションを取り直す。

### 4. ログインAPIのreCAPTCHA / Cloudflare
- note は2026年にログインへreCAPTCHA必須化、サイト全体がCloudflare配下。
- だから「メール/パスを自動投入」ではなく「**人がブラウザでログイン→Cookie保存→再利用**」方式にしている（login.mjs）。

### 5. 表が崩れる / `**` が本文に残る
- 表(Markdown table)は非対応 → 箇条書き/番号リストに変換する。
- 太字 `**` は効かないことがある → 使わない。
- 詳細は note_voice_and_design.md。

### 6. Chrome が無い環境
- パッチは「本物Chrome優先 → 無ければ同梱Chromium」に自動フォールバックする（headful維持）。
- Chromeを入れると最も安定（Googleログインも通りやすい）。

---

## Mac / Windows の違い（両対応）
コマンドは共通（`node scripts/setup.mjs` / `login.mjs` / `save_draft.mjs`）。差分は以下だけ：

| 項目 | macOS | Windows |
|---|---|---|
| セッション | `~/.note-state.json` | `%USERPROFILE%\.note-state.json` |
| Codex設定 | `~/.codex/config.toml` | `%USERPROFILE%\.codex\config.toml` |
| Claude Code設定 | プロジェクト直下 `.mcp.json` | 同左 |
| 設定内のパス | `/Users/...` | `C:/Users/...`（**スラッシュ表記でOK**。`\`はTOML/JSONで壊れるので使わない） |
| Chrome未導入時 | 同梱Chromiumにフォールバック | 同左 |

- Windowsでも note-post-mcp 内部のコピペは Ctrl+V を自動使用（ツールが `process.platform` を判定済み）。
- setup.mjs は実行OSを判定し、設定ファイルの場所をその場で案内する。

## 設定ファイルの場所（参考）
- セッション: `~/.note-state.json`（Win: `%USERPROFILE%\.note-state.json`）
- Claude Code: プロジェクト直下 `.mcp.json`（または `claude mcp add-json` ユーザースコープ）
- Codex: `~/.codex/config.toml`（Win: `%USERPROFILE%\.codex\config.toml`）
- サーバー本体: `<このスキル>/runtime/node_modules/@gonuts555/note-post-mcp/build/index.js`
========== END FILE ==========

========== FILE: scripts/login.mjs ==========
// note.com ログイン（Mac/Windows両対応）
// ブラウザを専用プロファイルで起動 → ユーザーがログイン → セッションを ~/.note-state.json に保存。
// セッションをローカル保存するだけで外部送信は一切なし。
// 実行: node scripts/login.mjs
import { createRequire } from 'node:module';
import { homedir } from 'node:os';
import { join, resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

// playwright はスキル内 runtime/node_modules から解決する
const scriptsDir = dirname(fileURLToPath(import.meta.url));
const runtimeDir = resolve(scriptsDir, '../runtime');
const require = createRequire(join(runtimeDir, 'package.json'));
const { chromium } = require('playwright');

const statePath = process.env.NOTE_POST_MCP_STATE_PATH || join(homedir(), '.note-state.json');
const userDataDir = join(homedir(), '.note-chrome-profile');
const baseOpts = { headless: false, viewport: null, args: ['--disable-blink-features=AutomationControlled'] };

console.log('\n=== note.com ログイン ===');
console.log('ブラウザを起動します。開いたウィンドウで note.com にログインしてください。');
console.log('・おすすめ:「メールアドレスでログイン」（Googleログインは自動操作だと弾かれる場合あり）');
console.log('ログイン完了後、このターミナルに戻って Enter を押してください。\n');

// 本物Chrome優先 → 無ければ同梱Chromium
let context;
try {
  context = await chromium.launchPersistentContext(userDataDir, { ...baseOpts, channel: 'chrome' });
} catch (e) {
  console.log('（Google Chrome が見つからないため、同梱Chromiumで起動します）');
  context = await chromium.launchPersistentContext(userDataDir, baseOpts);
}

const page = context.pages()[0] || (await context.newPage());
await page.goto('https://note.com/login');

process.stdout.write('▶ ログインが終わったら Enter を押してください... ');
await new Promise((r) => { process.stdin.resume(); process.stdin.once('data', () => r()); });

await context.storageState({ path: statePath });
console.log(`\n✅ セッションを保存しました: ${statePath}\n`);
await context.close();
process.exit(0);
========== END FILE ==========

========== FILE: scripts/patch.mjs ==========
// headfulパッチ（Mac/Windows両対応・冪等）
// noteエディタは headless では描画されないため、ブラウザ起動を
// 「本物Chrome優先 → 無ければ同梱Chromium」の headful 起動に書き換える。
// npm再インストール/更新後に: node scripts/patch.mjs
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const scriptsDir = path.dirname(fileURLToPath(import.meta.url));
const file = path.resolve(scriptsDir, '../runtime/node_modules/@gonuts555/note-post-mcp/build/index.js');

if (!fs.existsSync(file)) {
  console.error('❌ サーバー本体が見つかりません。先に node scripts/setup.mjs を実行してください。');
  process.exit(1);
}

// 置換後の起動コード（Chrome優先→同梱Chromiumフォールバック・headful）
const NEW = `    /* note-auto-draft patch: headful + Chrome fallback (note editor does not render headless) */
    const __naOpts = { headless: process.env.NOTE_HEADLESS === 'true', args: ['--lang=ja-JP', '--disable-blink-features=AutomationControlled'] };
    let browser;
    try {
        browser = await chromium.launch({ ...__naOpts, channel: 'chrome' });
    }
    catch (e) {
        browser = await chromium.launch(__naOpts);
    }`;

// 既知の3形態（オリジナル / 旧パッチ）からの移行に対応
const FORM_ORIG = `    const browser = await chromium.launch({
        headless: true,
        args: ['--lang=ja-JP'],
    });`;
const FORM_OLD = `    const browser = await chromium.launch({
        headless: process.env.NOTE_HEADLESS === 'true',
        channel: 'chrome',
        args: ['--lang=ja-JP', '--disable-blink-features=AutomationControlled'],
    });`;

let s = fs.readFileSync(file, 'utf8');

if (s.includes('note-auto-draft patch')) {
  console.log('✅ 既にパッチ済みです（最新形態）');
  process.exit(0);
}
if (s.includes(FORM_ORIG)) {
  s = s.replace(FORM_ORIG, NEW);
} else if (s.includes(FORM_OLD)) {
  s = s.replace(FORM_OLD, NEW);
} else {
  console.error('❌ パッチ対象が見つかりません（ツール側の更新で構造が変わった可能性）。troubleshooting.md 参照。');
  process.exit(1);
}

fs.writeFileSync(file, s);
console.log('✅ headfulパッチを適用しました（Chrome優先→同梱Chromiumフォールバック）');
========== END FILE ==========

========== FILE: scripts/save_draft.mjs ==========
// note 下書きを自動作成する MCPクライアント
// 実行: node scripts/save_draft.mjs <markdown_path> [thumbnail_path]
//   - markdown_path: 本文Markdown（front matterで title / tags 指定）
//   - thumbnail_path: アイキャッチ画像（任意）
//   - 本文中の ![](ローカル画像) は自動でアップロードされる
// 下書き専用。公開系ツールは呼ばない。
import { spawn } from 'node:child_process';
import os from 'node:os';
import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';

const scriptsDir = path.dirname(fileURLToPath(import.meta.url));
const serverPath = path.resolve(scriptsDir, '../runtime/node_modules/@gonuts555/note-post-mcp/build/index.js');

const md = process.argv[2];
const thumb = process.argv[3];
const tool = 'save_draft';
if (process.env.NOTE_TOOL && process.env.NOTE_TOOL !== tool) {
  console.error('下書き専用です。NOTE_TOOLによる公開指定は使えません。');
  process.exit(1);
}

if (!md || !fs.existsSync(md)) {
  console.error('usage: node scripts/save_draft.mjs <markdown_path> [thumbnail_path]');
  process.exit(1);
}
if (!fs.existsSync(serverPath)) {
  console.error('❌ サーバー未インストール。先に node scripts/setup.mjs を実行してください。');
  process.exit(1);
}

const statePath = process.env.NOTE_POST_MCP_STATE_PATH || path.join(os.homedir(), '.note-state.json');
if (!fs.existsSync(statePath)) {
  console.error('❌ ログイン未完了。先に node scripts/login.mjs を実行してください。');
  process.exit(1);
}

const args = { markdown_path: path.resolve(md) };
if (thumb) args.thumbnail_path = path.resolve(thumb);

const srv = spawn(process.execPath, [serverPath], {
  env: { ...process.env, NOTE_POST_MCP_STATE_PATH: statePath },
  stdio: ['pipe', 'pipe', 'inherit'],
});

srv.on('exit', () => { console.error('MCPが応答完了前に終了しました。下書き一覧を確認してください。'); process.exit(1); });
srv.on('error', () => { console.error('MCP起動に失敗しました。'); process.exit(1); });
let buf = '';
srv.stdout.on('data', (d) => {
  buf += d.toString();
  let i;
  while ((i = buf.indexOf('\n')) >= 0) {
    const line = buf.slice(0, i).trim();
    buf = buf.slice(i + 1);
    if (!line) continue;
    let msg;
    try { msg = JSON.parse(line); } catch { continue; }
    if (msg.error || msg.result?.isError) {
      console.error('MCPエラー。処理を止めます。下書き一覧で反映状況を確認してください。');
      srv.kill(); process.exit(1);
    }
    if (msg.id === 1) {
      send({ jsonrpc: '2.0', method: 'notifications/initialized' });
      send({ jsonrpc: '2.0', id: 2, method: 'tools/call', params: { name: tool, arguments: args } });
    } else if (msg.id === 2) {
      const r = msg.result?.content?.[0]?.text ?? JSON.stringify(msg.result ?? msg.error);
      console.log('\n=== RESULT ===');
      console.log(r);
      let result;
      try { result = JSON.parse(r); } catch { result = null; }
      srv.kill();
      const verified = result?.success === true || result?.ok === true;
      if (!verified) console.error('保存結果を確認できませんでした。再送せず下書き一覧を確認してください。');
      process.exit(verified ? 0 : 1);
    }
  }
});
const send = (o) => srv.stdin.write(JSON.stringify(o) + '\n');
send({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'note-auto-draft', version: '1.0' } } });

setTimeout(() => { console.error('timeout'); srv.kill(); process.exit(1); }, 230000);
========== END FILE ==========

========== FILE: scripts/setup.mjs ==========
// note-auto-draft セットアップ（Mac/Windows両対応・自己完結・冪等）
// note-post-mcp + playwright を runtime/ に導入 → Chromium導入 → headfulパッチ →
// Claude Code / Codex 用の登録スニペットを出力。
// 実行: node scripts/setup.mjs
import { execSync } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const scriptsDir = path.dirname(fileURLToPath(import.meta.url));
const skillRoot = path.resolve(scriptsDir, '..');
const runtimeDir = path.join(skillRoot, 'runtime');
const serverPath = path.join(runtimeDir, 'node_modules/@gonuts555/note-post-mcp/build/index.js');
const statePath = path.join(os.homedir(), '.note-state.json');
// 設定ファイル内ではスラッシュ統一（Windowsの \ でJSON/TOMLが壊れるのを防ぐ。nodeは / でも動く）
const slash = (p) => p.split(path.sep).join('/');

const sh = (cmd, cwd) => execSync(cmd, { cwd, stdio: 'inherit' });

// 0. Node 18+
const major = parseInt(process.versions.node.split('.')[0], 10);
if (major < 18) {
  console.error(`❌ Node.js 18 以上が必要です（現在 ${process.version}）。`);
  process.exit(1);
}

// 1. runtime ディレクトリ
fs.mkdirSync(runtimeDir, { recursive: true });
const pkg = path.join(runtimeDir, 'package.json');
if (!fs.existsSync(pkg)) {
  fs.writeFileSync(pkg, JSON.stringify({ name: 'note-auto-draft-runtime', private: true, type: 'module' }, null, 2));
}

// 2. 依存インストール
console.log('▶ 依存をインストール中（@gonuts555/note-post-mcp + playwright）...');
sh('npm install @gonuts555/note-post-mcp@latest playwright@latest --no-fund --no-audit', runtimeDir);

// 3. Chromium
console.log('▶ Chromium をインストール中...');
sh('npx playwright install chromium', runtimeDir);

// 4. headfulパッチ（patch.mjs に一本化）
console.log('▶ headfulパッチを適用中...');
sh(`node "${path.join(scriptsDir, 'patch.mjs')}"`, skillRoot);

// 5. 登録スニペット出力
const claudeSnippet = {
  'note-draft': { command: 'node', args: [slash(serverPath)], env: { NOTE_POST_MCP_STATE_PATH: slash(statePath) } },
};
const codexSnippet =
  `[mcp_servers.note_draft]\n` +
  `command = "node"\n` +
  `args = ["${slash(serverPath)}"]\n` +
  `startup_timeout_sec = 120\n\n` +
  `[mcp_servers.note_draft.env]\n` +
  `NOTE_POST_MCP_STATE_PATH = "${slash(statePath)}"`;

const isWin = process.platform === 'win32';
console.log('\n================ SETUP_RESULT ================');
console.log('PLATFORM=' + process.platform);
console.log('SERVER_PATH=' + slash(serverPath));
console.log('STATE_PATH=' + slash(statePath));
console.log('\n--- Claude Code: .mcp.json の "mcpServers" に追加 ---');
console.log(JSON.stringify(claudeSnippet, null, 2));
console.log('\n--- Codex: config.toml の末尾に追加 ---');
console.log(`( 場所: ${isWin ? '%USERPROFILE%\\.codex\\config.toml' : '~/.codex/config.toml'} )`);
console.log(codexSnippet);
console.log('==============================================');
console.log('\n次のステップ: node scripts/login.mjs でブラウザログイン → ~/.note-state.json 生成');
if (isWin) {
  console.log('※ Windows: Google Chrome 推奨（無くても同梱Chromiumにフォールバックします）。');
}
========== END FILE ==========
