# task-693: ThreadAuto CLI post-carousel 커맨드 추가

## 배경
카드뉴스 6장을 생성했으나 커버 1장만 업로드되는 문제 발생.
근본 원인: `cli.py`에 `post-carousel` 커맨드가 없어서, 봇이 `post-image`로 단일 이미지만 업로드함.
`api/client.py:73`에 `post_carousel()` 메서드는 이미 구현되어 있으나, CLI 진입점이 없음.

## 현재 CLI 커맨드 현황
- `post-text` ✅ (cli.py:100)
- `post-image` ✅ (cli.py:135)
- `post-video` ✅ (cli.py:173)
- `post-carousel` ❌ **미구현** ← 이걸 추가

## 요구사항

### 1. `post-carousel` CLI 커맨드 추가

```python
@app.command(name="post-carousel")
def post_carousel(
    image_paths: list[str] = typer.Argument(..., help="로컬 이미지 경로들 (또는 공개 URL들)"),
    caption: str = typer.Option("", "--caption", "-c", help="캐러셀 캡션"),
):
    """캐러셀(멀티이미지) 게시물 발행"""
```

기능:
1. 토큰 유효성 확인 (`get_valid_token()`)
2. 이미지 경로가 로컬 파일인 경우 → 이미지 서버(`publisher/image_server.py`)를 통해 공개 URL로 변환
3. `ThreadsClient.post_carousel(image_urls, caption)` 호출
4. 결과 출력 (Post ID)

### 2. 로컬 파일 → 공개 URL 변환 처리

현재 `post-image`는 공개 URL만 받는데, 카드뉴스는 로컬 파일(`output/cardnews_*.png`)로 생성됨.
`publisher/image_server.py`의 Tailscale Funnel 방식이나, 기존에 task-691.1에서 사용한 방법을 활용.

로컬 파일 감지: 경로가 `http://` 또는 `https://`로 시작하지 않으면 로컬 파일로 판단.

### 3. 기존 커맨드 스타일 일치

현재 `post-text`, `post-image`, `post-video`의 패턴을 동일하게 따를 것:
- `get_valid_token()` 확인
- `asyncio.run()` 패턴
- Rich Panel로 성공/실패 출력
- 실패 시 `typer.Exit(code=1)`

## 파일 위치
- 수정 대상: `/home/jay/projects/ThreadAuto/cli.py`
- 참조: `/home/jay/projects/ThreadAuto/api/client.py` (post_carousel 메서드)
- 참조: `/home/jay/projects/ThreadAuto/publisher/image_server.py` (이미지 서빙)

## 테스트
- `post-carousel` 커맨드가 `--help`에 노출되는지 확인
- 로컬 파일 경로 → URL 변환 동작 확인
- 실제 업로드는 별도 (토큰 필요)

## 산출물
- cli.py 수정본 (post-carousel 커맨드 추가)
- `memory/reports/task-693.md` 보고서