# 【コピペ用】LINE→Obsidian 音声日記 おまかせ構築プロンプト

このファイルの使い方はかんたんです。

1. 下の **「━━━ ここからコピー ━━━」から「━━━ ここまでコピー ━━━」まで** をすべて選択してコピーする
2. Claude Code（クロードコード）の入力欄に貼り付ける
3. 最後に **「この手順通りに進めてほしい」** と送る

あとは Claude Code が1ステップずつ案内してくれます。専門知識は不要です。途中で「ブラウザでこのボタンを押してください」「この値を貼ってください」と聞かれるので、その通りに答えるだけで完成します。

> ⚠️ トークンなどの「秘密の値」は、Claude Code に貼っても大丈夫ですが、**SNSや他人に見える場所には貼らないでください。** 作業が終わったら再発行しておくと安心です。

---

━━━ ここからコピー ━━━

あなたは、私が「**LINEに話しかけるだけで、Macのobsidianに日記が自動でたまる仕組み**」をゼロから作るのを、最後まで伴走して手伝うアシスタントです。

## 前提

- 私は**コードが分かりません**。専門用語はできるだけ使わず、使うときは一言で説明してください。
- 私のパソコンは **Mac** です。
- ゴールは「スマホのLINEに送った文章（音声入力でもOK）が、5分以内にObsidianの今日のノートに自動で追記される」状態です。
- **記事保存やNotion連携などの応用機能は作りません。** 音声メモをObsidianに貯めるところまでで完成とします。

## 進め方のルール（重要）

1. **1ステップずつ**進めてください。まとめて指示せず、1つ終わって私が「できた」と言ってから次に進む。
2. **私がやるブラウザ操作**は、「どのサイトの・どの画面の・どのボタンを押すか」を具体的に説明してください。
3. **コードのファイル作成や実行は、あなたがやってOK**です。私が中身を理解する必要はありません。「このファイルを作りますね」と言ってから進めてください。
4. **秘密の値（トークン・シークレット等）はコードに直接書かない**でください。Vercelの環境変数として設定します。私が値を貼ったら、それを使って設定を進めてください。
5. 各ステップの最後に必ず**「確認方法」**を示し、うまくいったか一緒に確かめてください。
6. エラーが出たら、**原因と対処を私の言葉で**説明してください。同じエラーが2回続けて直らなければ、一度立ち止まって状況を整理してください。
7. まず最初に、これから何をやるかの**全体像（9ステップ）を1回だけ**簡単に見せてから、Step 0 に入ってください。

## 完成させる仕組みの全体像

```
スマホの LINE でメッセージ送信（音声入力でもOK）
    ↓
LINE Bot が受信（自動）
    ↓
Vercel のプログラムがメッセージを保存（Upstash Redis）
    ↓
Mac の常駐スクリプトが5分おきに取得
    ↓
Obsidian の今日のノート（YYYY-MM-DD.md）に自動追記
```

使うサービスは**すべて無料**です（LINE Messaging API / Vercel / Upstash Redis / Obsidian）。

---

## Step 0: 事前チェック（まずOSを確認）

**最初に、私のパソコンが Mac か Windows かを確認してください。** このプロンプトはどちらでも作れますが、**最後の「自動実行」の作り方だけがOSで変わる**ため、ここで確定させておいてください。

- 分からなければ「画面の左上にリンゴのマークがありますか？（あればMac）」のように聞いて判定してください。
- 以降、Macなら「ターミナル」、Windowsなら「PowerShell」または「コマンドプロンプト」を使います。どちらを開けばいいか私に案内してください。

次に、環境を確認してください（足りないものは入れ方を案内）。

- **Node.js v18以上**: `node -v`（Mac / Windows 共通）。入っていなければ https://nodejs.org からLTS版を入れるよう案内
- **Vercel CLI**: Macは `which vercel`、Windowsは `where vercel`。なければ `npm i -g vercel` を案内
- **Obsidian アプリ**: 次のStep 1で確認

> Windowsの場合、Node.jsのインストールでつまずきやすいです。入っていなければ、あわてず一緒に入れてから先へ進めてください。

確認できたら Step 1 へ。

---

## Step 1: Obsidian の準備（設定方法）

**目的**: 日記を保存する「保管庫（Vault）」を用意し、その保存場所（フルパス）を確定させる。

私に次を順番に案内してください。

### 1-1. Obsidian がインストールされているか確認

- 私に「Obsidianアプリは入っていますか？」と聞いてください。
- **入っていない場合**: 2通りのどちらかを案内してください。
  - かんたん: ブラウザで https://obsidian.md を開き、「Download」からMac版をダウンロードして、アプリケーションフォルダに入れる
  - ターミナル派: `brew install --cask obsidian`（Homebrewがある場合）
- インストールできたら Obsidian を起動してもらう。

### 1-2. 保管庫（Vault）を作る

Obsidianを初めて開くと「保管庫」を作る画面が出ます。私に次を案内してください。

- 「**新しい保管庫を作成**（Create new vault）」を選ぶ
- **保管庫の名前**を入力（例: `Obsidian Vault`）
- **保存場所（Location）**を選ぶ。おすすめは `書類（Documents）` フォルダの中。
  - つまり最終的な場所は `/Users/（あなたのユーザー名）/Documents/Obsidian Vault` のようになります。
- 「作成」を押す。すでに保管庫を持っている場合は、それをそのまま使ってOKです。

### 1-3. 保存場所（フルパス）を確認する

このパスは後のStepで必ず使うので、正確に控えます。私のOSに合わせて案内してください。

- **Mac**: Obsidianの左下の保管庫名を右クリック →「**Finderで表示**（Reveal in Finder）」→ 開いたフォルダを右クリック → Optionキーを押しながら「**"（フォルダ名)"のパス名をコピー**」
  - 例: `/Users/yumiokada/Documents/Obsidian Vault`
- **Windows**: 保管庫名を右クリック →「**Show in system explorer**（エクスプローラーで表示）」→ エクスプローラーのアドレスバーをクリックしてパスをコピー
  - 例: `C:\Users\yumi\Documents\Obsidian Vault`
  - ⚠️ **後でコードに書くときは、`\`（円マーク/バックスラッシュ）を `/` に置き換えて** `C:/Users/yumi/Documents/Obsidian Vault` の形にしてください（プログラム上のトラブルを防ぐため）。この変換はあなた（アシスタント）がやってください。

確認できたパスを私に聞いて、メモしておいてください。

### 1-4. デイリーノートについての補足

- この仕組みでは、スクリプトが**今日の日付のノート（例: `2026-07-03.md`）を自動で作成・追記**します。特別なプラグインは不要です。
- もし私が普段からObsidianの「デイリーノート」プラグインを使っている場合は、その保存先フォルダが保管庫の直下（ルート）になっているか確認してください。違うフォルダにしている場合は、あとでスクリプトの保存先パスをそこに合わせます。

**確認方法**: 保管庫のフルパスが1つに確定していればStep 1は完了です。次へ。

---

## Step 2: 公式LINE（LINE Bot）の登録

**目的**: 自分専用のLINE Botを作り、あとで使う2つの値（**Channel Secret** と **Channel Access Token**）を取得する。

> LINEの管理画面は「LINE Developers」と「LINE Official Account Manager」の**2つのサイト**にまたがります。ここが分かりにくいので、私にどちらのサイトの操作なのかを毎回はっきり伝えてください。

### 2-1. LINE Developers にログイン

- ブラウザで https://developers.line.biz/ja/ を開く
- 右上の「**ログイン**」→ 普段使っているLINEアカウントでログイン（メール＋パスワード、またはQRコード）

### 2-2. プロバイダーを用意

- ログインするとコンソールが開きます。「プロバイダー」（開発者名のようなもの）が一覧に出ます。
- あれば既存のものでOK。**なければ**「作成」で新規作成（名前は何でもOK、例: `my-tools`）。

### 2-3. Messaging API チャネルを作る

- プロバイダーを選んで中に入り、「**Messaging API**」を選ぶ。
- 現在はここから直接は作れないため、画面に出る緑色の「**LINE公式アカウントを作成する**」ボタンを押す。
- **LINE Official Account Manager** という別サイトに移動します。次を入力して作成:
  - **アカウント名**: 好きな名前（例: `音声日記Bot` や `yumi_デイリーログ`）
  - **業種**: 「個人」でOK
  - プライバシーポリシー・利用規約: 空欄のままでOK

### 2-4. Messaging API を有効化

- LINE Official Account Manager の左メニュー「**設定**（歯車）」→「**Messaging API**」
- 「**Messaging APIを利用する**」を押す
- プロバイダーを選ぶ画面が出たら、さっきのプロバイダーを選ぶ → 有効化完了

### 2-5. 自動応答メッセージをオフにする

- 同じく「**設定**」→「**応答設定**」
- 「**応答メッセージ**」を**オフ**にする（デフォルトの自動返信が邪魔になるため）

### 2-6. 2つの値を取得する（ここから LINE Developers に戻る）

- https://developers.line.biz/console/ を開き、プロバイダー → 作ったチャネルを選ぶ

**① Channel Secret**
- 「**チャネル基本設定**」タブ → 「Channel secret」の「コピー」ボタン → 私に控えるよう伝える

**② Channel Access Token（長期）**
- 「**Messaging API設定**」タブ → 一番下の「**チャネルアクセストークン（長期）**」→「**発行**」→ 表示された長い文字列を「コピー」→ 私に控えるよう伝える

**確認方法**: `Channel Secret` と `Channel Access Token` の2つが手元にそろえばStep 2は完了です。（Webhookの設定はStep 7でやります）

---

## Step 3: Upstash Redis（メッセージの一時保存先）を作る

**目的**: LINEから届いたメッセージを一時的にためるデータベースを無料で用意し、2つの値を取得する。

私に次を案内してください。

- ブラウザで https://console.upstash.com/ を開く
- **Googleアカウントでログイン**（無料・クレジットカード不要）
- 「**Create Database**」を押す
  - **Name**: `voice-diary`
  - **Region**: `ap-northeast-1`（Tokyo）
  - 「Monthly: $0」と出ていることを確認 → 「**Create**」
- 作成後の画面で、次の2つをコピーして私に控えさせてください:
  - **UPSTASH_REDIS_REST_URL**（`https://xxxx.upstash.io` の形）
  - **UPSTASH_REDIS_REST_TOKEN**（長い文字列）

**確認方法**: 上記2つの値がそろえばStep 3は完了です。

---

## Step 4: プロジェクトのファイルを作る（あなたが作成）

**目的**: 仕組みの本体となるファイルを一式そろえる。ここは**あなたがファイルを作成**してください（私は中身を理解しなくてOK）。

作業フォルダは `~/voice-diary-bot` にしてください。以下のファイルを作成します。

**`~/voice-diary-bot/package.json`**
```json
{
  "name": "voice-diary-bot",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "vercel dev",
    "sync": "npx tsx scripts/sync-to-obsidian.ts"
  },
  "dependencies": {
    "@line/bot-sdk": "^9.0.0",
    "@upstash/redis": "^1.37.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "tsx": "^4.21.0",
    "typescript": "^5.0.0",
    "vercel": "^39.0.0"
  }
}
```

**`~/voice-diary-bot/tsconfig.json`**
```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "rootDir": ".",
    "resolveJsonModule": true
  },
  "include": ["api/**/*", "scripts/**/*"]
}
```

**`~/voice-diary-bot/vercel.json`**
```json
{
  "version": 2,
  "routes": [
    { "src": "/api/webhook", "methods": ["POST"], "dest": "/api/webhook.ts" },
    { "src": "/api/messages", "methods": ["GET"], "dest": "/api/messages.ts" }
  ]
}
```

**`~/voice-diary-bot/api/webhook.ts`**（LINEからメッセージを受け取って保存する）
```typescript
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { Redis } from "@upstash/redis";
import crypto from "crypto";

const CHANNEL_SECRET = process.env.LINE_CHANNEL_SECRET!;
const CHANNEL_ACCESS_TOKEN = process.env.LINE_CHANNEL_ACCESS_TOKEN!;

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

interface LineEvent {
  type: string;
  message?: { type: string; id: string; text?: string };
  timestamp: number;
  replyToken?: string;
}

function verifySignature(body: string, signature: string): boolean {
  const hash = crypto.createHmac("SHA256", CHANNEL_SECRET).update(body).digest("base64");
  return hash === signature;
}

async function replyMessage(replyToken: string, text: string) {
  await fetch("https://api.line.me/v2/bot/message/reply", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${CHANNEL_ACCESS_TOKEN}`,
    },
    body: JSON.stringify({ replyToken, messages: [{ type: "text", text }] }),
  });
}

export default async function handler(req: VercelRequest, res: VercelResponse) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" });

  const signature = req.headers["x-line-signature"] as string;
  const body = JSON.stringify(req.body);
  if (!verifySignature(body, signature)) return res.status(401).json({ error: "Invalid signature" });

  const events: LineEvent[] = req.body.events;
  for (const event of events) {
    if (event.type === "message" && event.message?.type === "text") {
      const text = event.message.text!;
      const jst = new Date(event.timestamp + 9 * 60 * 60 * 1000);
      const timestamp = jst.toISOString().replace("Z", "+09:00");
      await redis.rpush("diary:messages", JSON.stringify({ timestamp, text }));
      if (event.replyToken) await replyMessage(event.replyToken, "📝 記録しました");
    }
  }
  return res.status(200).json({ ok: true });
}
```

**`~/voice-diary-bot/api/messages.ts`**（Macが溜まったメッセージを取りに来る）
```typescript
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { Redis } from "@upstash/redis";

const API_SECRET = process.env.API_SECRET!;
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

export default async function handler(req: VercelRequest, res: VercelResponse) {
  if (req.method !== "GET") return res.status(405).json({ error: "Method not allowed" });

  const auth = req.headers["x-api-secret"] as string;
  if (auth !== API_SECRET) return res.status(401).json({ error: "Unauthorized" });

  const raw: string[] = await redis.lrange("diary:messages", 0, -1);
  const messages = raw.map((item) => (typeof item === "string" ? JSON.parse(item) : item));
  if (messages.length > 0) await redis.del("diary:messages");

  return res.status(200).json({ messages });
}
```

作成できたら、ターミナルで `cd ~/voice-diary-bot && npm install` を実行してください（あなたが実行してOK）。`added xxx packages` と出れば成功です。

**確認方法**: `api/webhook.ts` / `api/messages.ts` / `package.json` / `tsconfig.json` / `vercel.json` の5ファイルがあり、`npm install` が成功していればStep 4は完了です。

---

## Step 5: Vercel に公開（デプロイ）する

- ターミナルで `cd ~/voice-diary-bot && vercel --yes` を実行。
- 初回はブラウザが開いてVercelログインを求められます。私にログインするよう案内してください（GitHub/GoogleアカウントでOK）。
- デプロイ成功で URL が表示されます（例: `https://voice-diary-bot.vercel.app`）。この URL を私に控えさせてください。

**確認方法**: デプロイURLが発行されればStep 5は完了です。

---

## Step 6: 環境変数（秘密の値）を登録する

Step 2・3で控えた値と、新しく決める「合言葉」をVercelに安全に登録します。私に**API_SECRETという合言葉を1つ決めてもらい**（例: `my-diary-secret-2026`）、次を1つずつ実行してください（値の部分は私に貼ってもらう）。

```bash
cd ~/voice-diary-bot
vercel env add UPSTASH_REDIS_REST_URL production --value "（Step3のURL）"
vercel env add UPSTASH_REDIS_REST_TOKEN production --value "（Step3のトークン）"
vercel env add LINE_CHANNEL_SECRET production --value "（Step2のChannel Secret）"
vercel env add LINE_CHANNEL_ACCESS_TOKEN production --value "（Step2のAccess Token）"
vercel env add API_SECRET production --value "（自分で決めた合言葉）"
```

登録後、反映のため再デプロイ: `vercel --prod --yes`

**確認方法**: `vercel env ls` で5つ登録されていて、再デプロイが「ready」になればStep 6は完了です。API_SECRETの合言葉はStep 8でも使うので覚えておいてください。

---

## Step 7: LINE と Vercel をつなぐ（Webhook 接続）

**目的**: LINEに送ったメッセージがVercelに届くようにする。**ここが一番ハマるポイント**なので丁寧に案内してください。

### 7-1. Webhook URL を設定

- **LINE Official Account Manager**（https://manager.line.biz/）→ 作ったアカウント →「設定」→「Messaging API」
- 「**Webhook URL**」に次を入力: `（Step5のデプロイURL）/api/webhook`（例: `https://voice-diary-bot.vercel.app/api/webhook`）→「保存」

### 7-2. 「Webhookの利用」をオンにする（最重要）

- **LINE Developers コンソール** → チャネル →「**Messaging API設定**」タブ
- 「**Webhookの利用**」のトグルを**オン**にする（緑になればOK）
- ⚠️ URLを入れても、このトグルがオフだとメッセージは一切届きません。必ずオンを確認。

### 7-3. 検証 → 友だち追加 → テスト

- 同じ画面の「**検証**」ボタン →「成功」が出ればOK
- 同じタブにある**QRコード**をスマホのLINEで読み取り、Botを**友だち追加**
- LINEで「テスト」と送って、「**📝 記録しました**」と返ってくれば成功

返ってこない場合は、7-2のトグル・Webhook URLのスペル・Step6の環境変数・再デプロイを一緒に確認してください。

**確認方法**: LINEに送って「📝 記録しました」が返ればStep 7は完了です。

---

## Step 8: Mac の同期スクリプトを作る（あなたが作成）

**目的**: Vercelに溜まったメッセージを取得して、Obsidianの今日のノートに書き込む。

**`~/voice-diary-bot/scripts/sync-to-obsidian.ts`** を作成してください。**先頭の3つの値**を、私の環境に合わせて設定してください（Step5のURL、Step6の合言葉、Step1で確定した保管庫のフルパス）。

```typescript
import fs from "fs";
import path from "path";

// ★ この3つを私の環境に合わせて設定する
const API_URL = "（Step5のデプロイURL）/api/messages";
const API_SECRET = "（Step6で決めた合言葉）";
const VAULT_PATH = "（Step1で確定した保管庫のフルパス）";

interface DiaryMessage { timestamp: string; text: string; }

function formatTime(timestamp: string): string {
  const date = new Date(timestamp);
  const h = String(date.getHours()).padStart(2, "0");
  const m = String(date.getMinutes()).padStart(2, "0");
  return `${h}:${m}`;
}

function getDateKey(timestamp: string): string {
  const date = new Date(timestamp);
  const jst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
  const y = jst.getUTCFullYear();
  const mo = String(jst.getUTCMonth() + 1).padStart(2, "0");
  const d = String(jst.getUTCDate()).padStart(2, "0");
  return `${y}-${mo}-${d}`;
}

function appendToDaily(messages: DiaryMessage[]) {
  const byDate = new Map<string, DiaryMessage[]>();
  for (const msg of messages) {
    const key = getDateKey(msg.timestamp);
    if (!byDate.has(key)) byDate.set(key, []);
    byDate.get(key)!.push(msg);
  }
  for (const [dateKey, msgs] of byDate) {
    const targetPath = path.join(VAULT_PATH, `${dateKey}.md`);
    let content = fs.existsSync(targetPath)
      ? fs.readFileSync(targetPath, "utf-8")
      : `## ${dateKey} デイリーログ\n`;

    if (!content.includes("### 🎙️ 音声メモ")) {
      const headerEnd = content.indexOf("\n", content.indexOf("デイリーログ"));
      content = headerEnd !== -1
        ? content.slice(0, headerEnd + 1) + "\n### 🎙️ 音声メモ\n" + content.slice(headerEnd + 1)
        : content + "\n### 🎙️ 音声メモ\n";
    }

    const sectionIndex = content.indexOf("### 🎙️ 音声メモ");
    const sectionEnd = content.indexOf("\n---", sectionIndex);
    const insertPos = sectionEnd !== -1
      ? sectionEnd
      : content.indexOf("\n###", sectionIndex + 1) !== -1
        ? content.indexOf("\n###", sectionIndex + 1)
        : content.length;

    const newEntries = msgs.map((m) => `- ${formatTime(m.timestamp)} — ${m.text}`).join("\n");
    content = content.slice(0, insertPos) + "\n" + newEntries + content.slice(insertPos);

    fs.writeFileSync(targetPath, content, "utf-8");
    console.log(`✅ ${msgs.length} 件を ${dateKey}.md に追記しました`);
  }
}

async function sync() {
  try {
    const res = await fetch(API_URL, { headers: { "x-api-secret": API_SECRET } });
    if (!res.ok) { console.error(`❌ API エラー: ${res.status}`); return; }
    const data = await res.json();
    const messages: DiaryMessage[] = data.messages;
    if (messages.length === 0) { console.log("📭 新しいメッセージはありません"); return; }
    console.log(`📬 ${messages.length} 件のメッセージを取得`);
    appendToDaily(messages);
  } catch (err) {
    console.error("❌ 同期エラー:", err);
  }
}

console.log("🚀 音声日記同期スクリプト開始");
sync();
setInterval(sync, 5 * 60 * 1000);
```

作成後、動作テストしてください。
1. 私にLINEで何かメッセージを送ってもらう →「📝 記録しました」を確認
2. ターミナルで `cd ~/voice-diary-bot && npm run sync`
3. `✅ 1 件を YYYY-MM-DD.md に追記しました` と出たら、Obsidianの今日のノートに `### 🎙️ 音声メモ` が追加されているか私に確認してもらう
4. `Ctrl + C` で停止

**確認方法**: LINEで送った内容がObsidianの今日のノートに表示されればStep 8は完了です。

---

## Step 9: パソコン起動時に自動で動かす（常駐化）

**目的**: 毎回手動で実行しなくても、5分おきに自動で同期される状態にする。

> ⚠️ **ここだけOSで手順が分かれます。** Step 0で確認したOSに合わせて、**片方だけ**を実行してください（あなたがOSを判定して、該当する方だけ案内する）。

### 【Macの場合】launchd で常駐化

- まず `mkdir -p ~/voice-diary-bot/logs`
- `which npx` を実行して結果を確認（`/opt/homebrew/bin/npx`＝Apple Silicon、`/usr/local/bin/npx`＝Intel）
- `whoami` でユーザー名を確認
- `~/Library/LaunchAgents/com.（ユーザー名）.voice-diary-sync.plist` を作成（下記。npxのパスとユーザー名を私の環境に合わせる）

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.（ユーザー名）.voice-diary-sync</string>
  <key>ProgramArguments</key>
  <array>
    <string>/opt/homebrew/bin/npx</string>
    <string>tsx</string>
    <string>/Users/（ユーザー名）/voice-diary-bot/scripts/sync-to-obsidian.ts</string>
  </array>
  <key>WorkingDirectory</key><string>/Users/（ユーザー名）/voice-diary-bot</string>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>/Users/（ユーザー名）/voice-diary-bot/logs/sync.log</string>
  <key>StandardErrorPath</key><string>/Users/（ユーザー名）/voice-diary-bot/logs/error.log</string>
  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
  </dict>
</dict>
</plist>
```

- 登録: `launchctl load ~/Library/LaunchAgents/com.（ユーザー名）.voice-diary-sync.plist`（無言で完了すれば成功）
- 確認: `cat ~/voice-diary-bot/logs/sync.log` に「🚀 音声日記同期スクリプト開始」が出ていればOK

### 【Windowsの場合】スタートアップに登録して常駐化

Windowsには launchd がないので、**「サインイン時に自動で立ち上がるフォルダ（スタートアップ）」に起動用ファイルを置く**方法を使います。初心者にやさしい順で案内してください。

1. **起動用のバッチファイルを作る**。あなた（アシスタント）が、プロジェクト内に `%USERPROFILE%\voice-diary-bot\start-sync.bat` を次の内容で作成してください（パスは私の環境に合わせる）。
   ```bat
   @echo off
   cd /d "%USERPROFILE%\voice-diary-bot"
   npx tsx scripts\sync-to-obsidian.ts
   ```
2. **スタートアップフォルダを開く**。私に案内してください:
   - キーボードの `Windows`＋`R` を押す →「ファイル名を指定して実行」が開く
   - `shell:startup` と入力して Enter → スタートアップフォルダが開く
3. **バッチファイルのショートカットを置く**。`start-sync.bat` を右クリック →「ショートカットの作成」→ できたショートカットを、2で開いたスタートアップフォルダに移動（またはコピー）する。
   - （黒い画面を出したくない場合は、Task Scheduler／タスクスケジューラで「ログオン時に実行・非表示」に設定する方法もあります。詳しくやりたいときは私に相談してください。）
4. **今すぐ動作確認**: `start-sync.bat` をダブルクリックすると黒い画面が開き、「🚀 音声日記同期スクリプト開始」と表示されればOK。この画面は開いたままにしておくと同期が続きます（サインインのたびに自動で開きます）。

**確認方法**（共通）: 「🚀 音声日記同期スクリプト開始」が表示され、LINEに送った内容が数分でObsidianに反映されれば、自動化まで完成です。

---

## 完成テスト（最後にいっしょに確認）

1. スマホのLINEで、Botに何か送る（音声入力でもテキストでもOK）
2. 「📝 記録しました」が返ってくる
3. 5分以内に、Obsidianの今日のノートの「🎙️ 音声メモ」に追記される

3つすべてOKなら完成です！ 最後に、私向けの「毎日の使い方」と「困ったときのコマンド一覧（同期停止/再開、ログ確認など）」を短くまとめて見せてください。

## うまくいかないときの切り分け（あなたが案内）

- **「記録しました」が返らない** → Step7の「Webhookの利用」オン／Webhook URL／Step6の環境変数／再デプロイを確認（OS共通）
- **Obsidianに書き込まれない** → `npm run sync` を手動実行してエラーを確認。スクリプト先頭の `VAULT_PATH` が保管庫のパスと一致しているか（Windowsは `C:/Users/...` の形＝スラッシュになっているか）を確認
- **再起動後に止まった** → Macは `launchctl load ~/Library/LaunchAgents/com.（ユーザー名）.voice-diary-sync.plist` を再実行／Windowsは `start-sync.bat` をダブルクリック（スタートアップ登録済みなら次回サインインから自動）
- **今すぐ同期したい（5分待てない）** → `cd ~/voice-diary-bot && npm run sync`（OS共通）

では、全体像（9ステップ）を簡単に見せてから、Step 0 から始めてください。

━━━ ここまでコピー ━━━
