addashboard-cli 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,48 +1,479 @@
1
- # addashboard-cli
1
+ # webgram CLI
2
2
 
3
- 広告ダッシュボード操作用の CLI。詳細な使い方・運用フローは社内マニュアル参照。
3
+ ad-dashboard を Claude Code / Codex CLI / ターミナルから操作するための CLI。
4
+ 「install → login → 広告入稿 dry-run → 実入稿」までを 1 本のマニュアルで完走できる構成にしてある。
4
5
 
5
- ## インストール
6
+ > 🔐 認証方式: Google SSO (loopback OAuth / 非対話環境は device flow) を主軸、`--password` (ROPC) は deprecated フォールバック
7
+ > 📦 配布: **npm public registry** (`addashboard-cli` unscoped) — `npx -y addashboard-cli@latest` で追加インストール不要
6
8
 
7
- Node.js 18+ が必要。
9
+ ---
10
+
11
+ ## 前提
12
+
13
+ - **Node.js 18+** (`node --version` で確認。無ければ [nodejs.org](https://nodejs.org) から LTS を入れる)
14
+ - **macOS / Linux** (Windows は動作未確認)
15
+ - **ネットワーク到達性**: `registry.npmjs.org` (npm パッケージ DL) と本番エンドポイント (API) の両方に届くこと
16
+ - **ad-dashboard アカウント**: `@webgram.jp` の Google アカウント (推奨)。フォールバックとしてメール + パスワードも可
17
+
18
+ ## クイックスタート (人間向け, 5 分)
19
+
20
+ ### 1. 疎通確認 (npm public registry から取得)
8
21
 
9
22
  ```bash
10
- # 都度実行 (推奨)
11
- npx -y addashboard-cli@latest --help
23
+ npx -y addashboard-cli@latest --version
24
+ # → 0.2.3
25
+ ```
12
26
 
13
- # あるいはグローバルインストール
14
- npm install -g addashboard-cli
15
- webgram --help
27
+ 初回のみ npm パッケージ DL で数秒。以降は npm キャッシュから即時起動。
28
+
29
+ > 💡 毎回タイプするのが面倒ならグローバルインストール:
30
+ > ```bash
31
+ > npm install -g addashboard-cli
32
+ > webgram --version
33
+ > ```
34
+ > アンインストールは `npm uninstall -g addashboard-cli`。
35
+
36
+ ### 2. ログイン (ターミナルから対話実行)
37
+
38
+ デフォルトは **Google アカウント (@webgram.jp) でのブラウザログイン** (loopback OAuth)。パスワードは不要。
39
+
40
+ ```bash
41
+ webgram auth login
42
+ # ブラウザで Google ログインを開きます…
43
+ # (ブラウザで @webgram.jp アカウントを選択)
44
+ # ✓ Logged in as you@example.com
45
+ # Saved to /Users/.../.config/webgram/credentials.json (chmod 0600)
16
46
  ```
17
47
 
18
- ## ログイン
48
+ ブラウザが自動で開かない環境では、表示された URL を手動で開けば同じフローが完了する。
49
+
50
+ #### 非対話環境 (Claude Code / CI 等) — device flow
51
+
52
+ `stdout` が TTY でない**非対話環境では自動で Google device flow に切り替わる** (loopback ブラウザは使えないため)。TTY でも `--device` を付ければ強制できる。
19
53
 
20
54
  ```bash
21
- webgram auth login # ブラウザで認証
22
- webgram auth whoami # 状態確認
23
- webgram auth logout
55
+ webgram auth login # 非対話環境では自動で device flow
56
+ webgram auth login --device # TTY でも device flow を強制
57
+
58
+ # ────────────────────────────────────────────
59
+ # Google でログインしてください (ブラウザ操作が必要です)
60
+ # 1. ブラウザで次の URL を開く: https://www.google.com/device
61
+ # 2. 次のコードを入力して許可: ABCD-EFGH
62
+ # 許可が完了すると自動でログインが続行されます…
63
+ # ────────────────────────────────────────────
64
+ # ✓ Logged in as you@example.com
65
+ ```
66
+
67
+ CLI が出力する **URL と user_code** を (別端末やスマホの) ブラウザで開いて @webgram.jp アカウントで許可すると、CLI が自動でトークンを取得して保存する。**client_secret はサーバー側で保持し、CLI には持たせない**。クライアント ID / シークレットの設定は不要 (メンバーは `webgram auth login` を実行するだけ)。
68
+
69
+ #### パスワード方式 (ROPC・deprecated フォールバック)
70
+
71
+ device flow もブラウザも使えない場合の**最終フォールバック**:
72
+
73
+ ```bash
74
+ webgram auth login --password # email/password を prompt
75
+ webgram auth login --email you@example.com --password 'secret' # 非推奨: shell history に残る
76
+ ```
77
+
78
+ > ⚠️ パスワード方式は deprecated。対話環境ではブラウザ loopback、非対話環境では device flow が自動で選ばれるため、通常は `--password` 不要。
79
+
80
+ ### 3. ログイン確認
81
+
82
+ ```bash
83
+ webgram auth whoami
84
+ # {"id":"...","email":"you@example.com","name":"...","role":"admin",...}
85
+ ```
86
+
87
+ 未ログインなら `✗ not_logged_in` + exit 1。
88
+
89
+ ## YDA 入稿クイックスタート (人間向け, 10 分)
90
+
91
+ 「YDA (Yahoo Display Ads) にキャンペーンを 1 本 PAUSED 状態で入れる」までの最短ルート。他媒体 (Meta / Google / SmartNews / ByteDance) も手順はほぼ同じ (JSON テンプレートを差し替えるだけ)。
92
+
93
+ ### 3-1. アカウント一覧を取得
94
+
95
+ ```bash
96
+ webgram list --platform yda --resource accounts
97
+ # [
98
+ # { "name": "伸長ぐんぐん習慣", "id": "1002778399" },
99
+ # { "name": "桑の葉&茶カテキン/株式会社WEBGRAM", "id": "1002792978" },
100
+ # ...
101
+ # ]
102
+ ```
103
+
104
+ > ⚠️ 一覧に出るのは **ad-dashboard の連携設定 (`ApiConnection.selectedAccounts`) に登録済みのアカウントだけ**。CLI 側でページングして全件取れるコマンドは現状無い。目的のアカウントが出ないときは、ad-dashboard の Web UI (データシンク → YDA) から `selectedAccounts` に追加する。
105
+
106
+ ### 3-2. 入稿ボディ雛形をコピー
107
+
108
+ 同梱の fixtures からコピーして書き換える:
109
+
110
+ ```bash
111
+ # npm install -g addashboard-cli した場合
112
+ cp $(npm root -g)/addashboard-cli/fixtures/yda_poc.json ./my_yda.json
113
+
114
+ # あるいは GitHub の Web からダウンロード:
115
+ # https://github.com/WEBGRAM-WG/ad-dashboard/tree/main/cli/fixtures
116
+ ```
117
+
118
+ `my_yda.json` を開いて 最低限 以下を書き換える:
119
+
120
+ - `accountId` — 3-1 で確認した対象アカウント ID
121
+ - `campaigns[0].name` — 任意のユニークな名前 (例: `商品名_20260714_PoC`)
122
+ - `campaigns[0].startDate` — 明日以降 (`YYYY-MM-DD`)
123
+
124
+ 他フィールドの意味は [`cli/fixtures/README.md`](./fixtures/README.md) 参照。
125
+
126
+ ### 3-3. dry-run (実媒体は触らない)
127
+
128
+ ```bash
129
+ webgram submit --platform yda --json-file ./my_yda.json
130
+ # → dry-run が既定。実媒体には一切触らない。zod 検証と would_create のみ返る
131
+ ```
132
+
133
+ `400` が返ったら応答の `error` フィールドを確認。必須項目が抜けているケースがほとんど。
134
+
135
+ ### 3-4. 実入稿
136
+
137
+ dry-run が警告なしで通過したら、**同じ JSON** に対して:
138
+
139
+ ```bash
140
+ webgram submit --platform yda --json-file ./my_yda.json --no-dry-run --yes
141
+ # ✓ Campaign created: campaignId=32523583
142
+ # ✓ AdGroup created: adGroupId=451748065
143
+ ```
144
+
145
+ `--no-dry-run` と `--yes` の **両方** が必須 (`--yes` なしは exit 2 で停止)。二段階ガードで事故を防いでいる。
146
+
147
+ ### 他媒体の入稿
148
+
149
+ Meta / Google / SmartNews / ByteDance も手順は同じ。JSON テンプレは `fixtures/` 配下:
150
+
151
+ | 媒体 | 必須 top-level | fixture |
152
+ |---|---|---|
153
+ | YDA | `accountId` | `yda_poc.json` / `yda_video_poc.json` |
154
+ | Meta | `accountId` (`act_...`) | `meta_poc.json` |
155
+ | Google | `customerId` | `google_poc.json` |
156
+ | SmartNews | `accountId` | `smartnews_poc.json` |
157
+ | ByteDance (TikTok) | `advertiserId` | `tiktok_poc.json` |
158
+
159
+ 各媒体の必須フィールド・制約は [`cli/fixtures/README.md`](./fixtures/README.md) にまとめている。
160
+
161
+ ---
162
+
163
+ ## 初期設定: Skill として配置する (推奨、AI エージェント経由で使う場合)
164
+
165
+ Claude Code / Codex CLI から「広告運用」「YDA 入稿」等の自然言語で発火させたい場合、**`ad-ops` skill をエージェントの skills ディレクトリに配置する**のが最短。ターミナル直叩きで CLI を使う人はこの章をスキップして OK。
166
+
167
+ Skill 本体 (`SKILL.md` / `config.json` / `README.md`) は npm パッケージに同梱されているため、`npm root -g` 経由か tarball 展開でコピーする。
168
+
169
+ ### Claude Code に配置
170
+
171
+ Claude Code のチャットに以下を貼り付けて実行を依頼:
172
+
173
+ ```
174
+ addashboard-cli の ad-ops skill を ~/.claude/skills/ に配置して
175
+ ```
176
+
177
+ Claude が裏で `npm pack addashboard-cli` → 展開 → `cp` を実行する。手動で入れる場合:
178
+
179
+ ```bash
180
+ mkdir -p ~/.claude/skills/ad-ops /tmp/ad-ops-extract
181
+ cd /tmp/ad-ops-extract && npm pack addashboard-cli@latest
182
+ tar xzf addashboard-cli-*.tgz --strip-components=1
183
+ cp -r skills/ad-ops/. ~/.claude/skills/ad-ops/
184
+ ```
185
+
186
+ ### Codex CLI に配置
187
+
188
+ Codex CLI は Claude Code のような skills 自動発火機能を持たないため、以下いずれかで SKILL.md を context に読み込ませる。
189
+
190
+ **方式 A: プロジェクトルートの `AGENTS.md` に参照を書く (推奨)**
191
+
192
+ 作業ディレクトリの `AGENTS.md` に以下を追記:
193
+
194
+ ```markdown
195
+ ## 広告運用 (ad-ops skill)
196
+
197
+ ad-dashboard の広告操作は `~/.codex/skills/ad-ops/SKILL.md` に従って `webgram` CLI (`npx -y addashboard-cli@latest`) 経由で実行する。設定は `~/.codex/skills/ad-ops/config.json` を参照。
198
+ ```
199
+
200
+ SKILL.md 本体を配置:
201
+
202
+ ```bash
203
+ mkdir -p ~/.codex/skills/ad-ops /tmp/ad-ops-extract
204
+ cd /tmp/ad-ops-extract && npm pack addashboard-cli@latest
205
+ tar xzf addashboard-cli-*.tgz --strip-components=1
206
+ cp -r skills/ad-ops/. ~/.codex/skills/ad-ops/
207
+ ```
208
+
209
+ **方式 B: 都度 `--instructions` で明示読み込み**
210
+
211
+ ```bash
212
+ codex --instructions ~/.codex/skills/ad-ops/SKILL.md "YDA に PAUSED で入稿の dry-run 走らせて"
24
213
  ```
25
214
 
26
- ## 主なコマンド
215
+ **方式 C: `~/.codex/config.toml` の `instructions` に恒久追加** (Codex CLI のバージョンによる)
216
+
217
+ ### 発火方法
218
+
219
+ 配置後、以下のいずれかのキーワードでエージェントに投げると自動発火 (Codex は AGENTS.md 経由で読み込まれる):
220
+
221
+ | カテゴリ | 発火キーワード例 |
222
+ |---|---|
223
+ | 参照系 | 「YDA のアカウント見せて」「Meta のキャンペーン一覧」「広告アカウント一覧」 |
224
+ | 入稿系 | 「YDA に入稿して」「PAUSED で dry-run」「Meta に入稿の dry-run」 |
225
+ | 認証系 | 「ad-dashboard のログイン状態は?」「webgram でログアウトして」 |
226
+ | 直接指定 | 「/ad-ops」「ad-ops skill 使って」「広告運用スキルで」 |
227
+
228
+ skill 側の詳細な発火条件・実行フロー・トラブルシュートは [`skills/ad-ops/README.md`](./skills/ad-ops/README.md) 参照。
229
+
230
+ ---
231
+
232
+ ## AI エージェント向け決定表
233
+
234
+ Claude Code / Codex CLI などの AI エージェントが「YDA 入稿して」のような曖昧な指示を受けたときに、試行錯誤せず最短経路で完走するための決定表。
235
+
236
+ ### コマンド早見表
237
+
238
+ | ユーザーがやりたいこと | 実行コマンド |
239
+ |---|---|
240
+ | 疎通確認 | `npx -y addashboard-cli@latest --help` |
241
+ | ログイン状態確認 | `webgram auth whoami` (成功=exit 0 / `not_logged_in`=exit 1) |
242
+ | ログイン (代行禁止 — 後述) | `webgram auth login` (Google SSO / device flow) |
243
+ | ログアウト | `webgram auth logout` |
244
+ | アカウント一覧 | `webgram list --platform <yda\|meta\|google\|smartnews\|bytedance> --resource accounts` |
245
+ | キャンペーン一覧 | `webgram list --platform <媒体> --resource campaigns --account-id <id>` |
246
+ | リソース一覧 (YDA/Meta/Google/ByteDance) | `webgram list --platform <媒体> --resource resources --account-id <id>` |
247
+ | 入稿 dry-run | `webgram submit --platform <媒体> --json-file <path>` |
248
+ | 実入稿 | `webgram submit --platform <媒体> --json-file <path> --no-dry-run --yes` |
249
+
250
+ ### 媒体別 top-level 必須フィールド
251
+
252
+ エージェントが JSON を組む前に必ず参照する。詳細フィールドは fixtures を参照。
253
+
254
+ | 媒体 | top-level | 子ノード必須 |
255
+ |---|---|---|
256
+ | yda | `accountId` / `campaigns[]` | `name` / `goal` / `status` / `startDate` / `budget≥1` / `biddingStrategy` / `cpc≥1` / `adGroups[]` |
257
+ | meta | `accountId` (`act_` 付) / `campaigns[]` | `objective` / `status` / `buyingType` / `adSets[]` (`optimizationGoal`,`billingEvent`,`bidStrategy`,`dailyBudget≥1`,`startTime`) |
258
+ | google | `customerId` / `campaigns[]` | `advertisingChannelType` / `status` / `budgetAmountYen≥1` / `adGroups[]` (`cpcBidYen≥1`, `ads[]`) |
259
+ | smartnews | `accountId` / `campaigns[]` | `objective` / `status` / `startDateTime` / `adGroups[]` (`ads[].adHeadline`, `adDescription`, `adLandingPageUrl`, `mediaFileId`) |
260
+ | bytedance | `advertiserId` / `campaigns[]` | `objectiveType` / `adGroups[]` (`optimizationGoal`, `billingEvent`, `budgetMode`, `budget≥20`, `landingPageUrl`, `locationIds`, `scheduleType`, `placementType`, `ads[]`) |
261
+
262
+ ### 制約チェックリスト (共通・媒体別)
263
+
264
+ エージェントは JSON 生成時に以下を **必ず** 確認する:
265
+
266
+ - **status は開始時点で `PAUSED` (bytedance は `DISABLE`)** — 動作確認できてから ad-dashboard UI で ACTIVE に切り替える運用
267
+ - **予算 0 円は不可** — YDA/Meta/Google/SmartNews は 1 以上、ByteDance は 20 以上
268
+ - **YDA 動画広告** — `videoPath` 必須、`thumbnailPath` を省略するとサムネ自動生成なし (Yahoo は自動生成しない)
269
+ - **Google Ads** — `RESPONSIVE_SEARCH_AD` は `headlines` 3 本以上・`descriptions` 2 本以上
270
+ - **SmartNews** — `mediaFileId` は事前に SmartNews 側にアップロード済みの画像/動画 ID が必要 (CLI からのアップロード機能なし)
271
+ - **ByteDance** — `budget` は 20 以上、状態は `PAUSED` ではなく `DISABLE`
272
+ - **dry-run 応答の見方** — `{ dry_run: true, would_create: ..., warnings: [] }` が成功。`400` は `error` フィールドを見る。生 JSON が欲しいときは `--verbose`
273
+
274
+ ### ログイン未完時の対応 (最重要)
275
+
276
+ **AI エージェントは `webgram auth login` を代行実行しない**。Google SSO / device flow のユーザーブラウザ操作は本人が行う (認証 URL とコードは CLI が出力するのでそれをユーザーに提示するだけ)。
277
+
278
+ `webgram auth whoami` が `not_logged_in` を返したら、エージェントは以下のテキストをユーザーに提示して**停止**する:
279
+
280
+ > ログインが必要です。ご自身のターミナルで以下を実行してください:
281
+ > ```bash
282
+ > webgram auth login
283
+ > ```
284
+ > ブラウザで Google (@webgram.jp) アカウントを選択してください。完了後「ログインしました」とお伝えください。
285
+ >
286
+ > (非対話環境で自動で device flow になった場合は、CLI が出力する URL と user_code をブラウザで開いて許可)
287
+
288
+ ユーザーから完了報告を受けたら `webgram auth whoami` で確認してから本題を続行する。
289
+
290
+ ## 接続先の切替 (ローカル開発時のみ)
291
+
292
+ 通常は指定不要 (デフォルトで本番エンドポイントに接続)。ローカル開発時のみ環境変数で切り替える:
27
293
 
28
294
  ```bash
29
- webgram list --platform <p> --resource <accounts|campaigns|resources> [--account-id <id>]
30
- webgram submit --platform <p> --json-file <path> # dry-run 既定
31
- webgram submit --platform <p> --json-file <path> --no-dry-run --yes # 実入稿
295
+ export WEBGRAM_ENDPOINT=http://localhost:3001
296
+ webgram auth login
32
297
  ```
33
298
 
34
- `<p>` = 対応媒体 (`yda` / `meta` / `google` / `smartnews` / `bytedance`)。
299
+ ログイン時の endpoint は credentials.json に保存され、以降の `whoami` / `logout` / `list` / `submit` は同じ endpoint に向く。
300
+
301
+ ## コマンドリファレンス
302
+
303
+ ### `webgram auth login [--device] [--password] [--email <mail>] [--endpoint <url>]`
304
+
305
+ - 既定は Google SSO (loopback OAuth)。非対話環境では自動で device flow に切り替わる
306
+ - `--device` — TTY でも device flow を強制
307
+ - `--password` — deprecated な ROPC フォールバック。パスワードは prompt or stdin パイプで渡す (argv 直渡しは shell history に残るので避ける)
308
+
309
+ ### `webgram auth whoami`
310
+
311
+ 現在の `access_token` に紐づくユーザー情報を `/api/auth/me` から取得。未ログインで exit 1。
312
+
313
+ ### `webgram auth logout`
314
+
315
+ サーバー側で `refresh_token` を revoke してから credentials.json を削除。idempotent。
35
316
 
36
- 入稿ボディ JSON の雛形と必須フィールドは [`fixtures/README.md`](./fixtures/README.md)。
317
+ ### `webgram list --platform <p> --resource <r> [--account-id <id> --campaign-id <id>]`
37
318
 
38
- ## Skill として使う
319
+ - `--platform`: `yda` / `meta` / `google` / `smartnews` / `bytedance`
320
+ - `--resource`: `accounts` / `campaigns` / `resources` (媒体により対応差あり)
321
+
322
+ ### `webgram submit --platform <p> --json-file <path> [--no-dry-run --yes] [--verbose]`
323
+
324
+ - 既定は dry-run。実入稿は `--no-dry-run --yes` の 2 フラグ必須
325
+ - 動画広告付きの YDA/Meta は本実行時のみ multipart upload (timeout 180s)
326
+ - `--verbose` でサーバー応答の raw JSON を表示
327
+
328
+ ### `webgram freee login/templates/issue`
329
+
330
+ freee 請求書発行用サブコマンド。詳細は `skills/invoice-issue-freee/SKILL.md` 参照。allowlist で利用者制限あり。
331
+
332
+ ### `webgram --help` / `webgram <subcommand> --help`
333
+
334
+ ## 認証フローと保存先
335
+
336
+ ```
337
+ webgram auth login
338
+ ↓ (Google SSO: loopback OAuth or device flow)
339
+ ↓ サーバー経由で認可コード → access_token 交換 (client_secret はサーバー側で保持)
340
+ ↓ 200 { access_token, refresh_token, expires_in: 3600 }
341
+ ↓
342
+ ~/.config/webgram/credentials.json (chmod 0600)
343
+ {
344
+ "endpoint": "<本番エンドポイント>",
345
+ "accessToken": "eyJ...", # JWT (1h)
346
+ "refreshToken": "Xy9...", # 256bit base64url (90d)
347
+ "expiresAt": "2026-06-29T05:00:00.000Z"
348
+ }
349
+
350
+ API 呼び出し
351
+ ↓ Authorization: Bearer <access_token>
352
+ ├─ 200 → 結果
353
+ └─ 401 → 自動 refresh + retry 1 回 → まだ失敗すればエラー
354
+ ```
39
355
 
40
- Claude Code / Codex CLI 用の `ad-ops` skill (広告運用スキル) を同梱。配置手順は [`skills/ad-ops/README.md`](./skills/ad-ops/README.md)。
356
+ | 項目 | 仕様 |
357
+ |---|---|
358
+ | パスワード保存 | しない (Google SSO ではそもそも扱わない) |
359
+ | credentials.json | `chmod 0600` (本人のみ読み書き) |
360
+ | `access_token` | 1 時間 (JWT exp claim) |
361
+ | `refresh_token` | 90 日 |
362
+ | Rate limit | 同一 IP から 15min / 5 回失敗で 429 (`--password` フォールバック時のみ) |
363
+ | 不正再利用検知 | 同じ `refresh_token` を 2 回使うと全 CLI トークン失効 |
364
+ | 通信 | HTTPS (本番) / HTTP (ローカル) |
365
+
366
+ ## トラブルシューティング
367
+
368
+ ### `webgram: command not found`
369
+
370
+ グローバルインストールしていない場合は `npx -y addashboard-cli@latest <cmd>` で実行するか、以下でグローバル導入:
371
+
372
+ ```bash
373
+ npm install -g addashboard-cli
374
+ which webgram
375
+ ```
376
+
377
+ ### `✗ Login failed: invalid_grant`
378
+
379
+ Google SSO 時は認可コードが期限切れ / 無効。再度 `webgram auth login` を実行。`--password` フォールバック時はメール/パスワードが違うので Web UI で確認。
380
+
381
+ ### `✗ Login failed: network_error`
382
+
383
+ エンドポイントに繋がっていない。ネットワークを確認、ローカル開発時は backend の起動を確認。
384
+
385
+ ### `✗ not_logged_in`
386
+
387
+ `webgram auth login` を先に実行。または `ls -la ~/.config/webgram/credentials.json` で残っているか確認。
388
+
389
+ ### Rate limit (HTTP 429)
390
+
391
+ `--password` フォールバックで 15 分間に 5 回連続でログイン失敗するとブロック。**15 分待ってから** 再試行、または Google SSO に切り替え (rate limit 対象外)。
392
+
393
+ ### アカウント一覧が少ない
394
+
395
+ `webgram list --platform <媒体> --resource accounts` は `ApiConnection.selectedAccounts` に登録済みのアカウントのみ返す。全件必要なら Web UI (データシンク → 対象媒体) から `selectedAccounts` を追加する。
396
+
397
+ ### dry-run で意味不明なエラー ([object Object] など)
398
+
399
+ CLI 側 (`src/commands/submission.ts`) で `data.error ?? err.message` に整形済みなので、通常は raw の `[object Object]` は出ない。それでも出るときは `--verbose` を付けて再実行し、サーバー応答の raw JSON を確認。
41
400
 
42
401
  ## 開発
43
402
 
403
+ ### ローカルインストール (ソース clone 派)
404
+
44
405
  ```bash
406
+ git clone git@github.com:WEBGRAM-WG/ad-dashboard.git
407
+ cd ad-dashboard/cli
45
408
  npm install
46
409
  npm run build
47
- npm test
410
+ npm link # webgram コマンドがグローバルに登録される
48
411
  ```
412
+
413
+ ### テスト実行
414
+
415
+ ```bash
416
+ npm test # vitest + nock、一時 dir で credentialStore/apiClient/コマンドをユニットテスト
417
+ npm run test:watch
418
+ ```
419
+
420
+ ### ローカル backend に対する動作確認
421
+
422
+ ```bash
423
+ # 別ターミナルで backend 起動
424
+ cd ../backend && npm run dev # :3001
425
+
426
+ # CLI で叩く
427
+ export WEBGRAM_ENDPOINT=http://localhost:3001
428
+ webgram auth login
429
+ webgram auth whoami
430
+ webgram auth logout
431
+ ```
432
+
433
+ ### ディレクトリ構成
434
+
435
+ ```
436
+ cli/
437
+ ├── src/
438
+ │ ├── index.ts # commander エントリ + prompt/promptHidden
439
+ │ ├── commands/
440
+ │ │ ├── auth.ts # runLogin / runWhoami / runLogout
441
+ │ │ ├── authGoogle.ts # Google SSO (loopback OAuth)
442
+ │ │ ├── authDevice.ts # Google device flow
443
+ │ │ ├── ads.ts # list (accounts/campaigns/resources)
444
+ │ │ ├── submission.ts # submit (dry-run/実入稿、動画 upload)
445
+ │ │ └── freee.ts # freee 請求書発行
446
+ │ └── lib/
447
+ │ ├── credentialStore.ts # ~/.config/webgram/credentials.json (chmod 0600)
448
+ │ └── apiClient.ts # axios factory (Bearer 付与 + 401 auto-refresh)
449
+ ├── fixtures/ # 入稿ボディ JSON 雛形 (媒体別)
450
+ ├── skills/ # skills/{ad-ops, invoice-issue-freee}
451
+ ├── test/unit/ # vitest + nock
452
+ ├── package.json # "bin": { "webgram": "./dist/index.js" }
453
+ └── tsconfig.json
454
+ ```
455
+
456
+ ## 参照
457
+
458
+ - [`fixtures/README.md`](./fixtures/README.md) — 全 5 媒体の入稿 JSON 雛形と必須フィールド一覧
459
+ - [`skills/ad-ops/SKILL.md`](./skills/ad-ops/SKILL.md) — Claude Code / Codex CLI から自然言語で実行するときのマッピング (広告運用スキル)
460
+ - [`skills/ad-ops/README.md`](./skills/ad-ops/README.md) — Skill 配置手順と発火方法 (Claude Code + Codex CLI 両対応)
461
+ - [`skills/invoice-issue-freee/SKILL.md`](./skills/invoice-issue-freee/SKILL.md) — freee 請求書発行 E2E マニュアル (allowlist 制)
462
+ - [../CLAUDE.md](../CLAUDE.md) — ad-dashboard 全体の知識ベース (媒体別認証・DB スキーマ・デプロイ手順)
463
+
464
+ ## ロードマップ
465
+
466
+ - [x] `auth login` / `whoami` / `logout` + 401 自動 refresh
467
+ - [x] Google SSO (loopback OAuth / 非対話環境は device flow)
468
+ - [x] `list` (accounts/campaigns/resources) 全 5 媒体
469
+ - [x] `submit` (dry-run + 実入稿) 全 5 媒体
470
+ - [x] `freee login/templates/issue` (allowlist 制)
471
+ - [x] npm public registry 配布 (`addashboard-cli`)
472
+ - [ ] `webgram raw <METHOD> <PATH>` (任意の REST を叩く脱出ハッチ)
473
+ - [ ] `webgram accounts --all` (selectedAccounts に載っていないアカウントもページングで全件取得)
474
+
475
+ ---
476
+
477
+ ## ライセンス
478
+
479
+ 社内限定。
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "addashboard-cli",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "webgram CLI — ad-dashboard (https://macchiato.site) を Claude Code / Codex CLI から操作するための CLI",
5
5
  "bin": {
6
6
  "webgram": "./dist/index.js"
@@ -9,7 +9,8 @@
9
9
  "dist",
10
10
  "README.md",
11
11
  "skills/ad-ops/**",
12
- "skills/invoice-issue-freee/**"
12
+ "skills/invoice-issue-freee/**",
13
+ "!skills/ad-ops/入稿計画/**"
13
14
  ],
14
15
  "keywords": [
15
16
  "webgram",
@@ -38,13 +39,17 @@
38
39
  "start": "node dist/index.js",
39
40
  "test": "vitest run",
40
41
  "test:watch": "vitest",
41
- "prepublishOnly": "npm run build"
42
+ "test:e2e": "playwright test",
43
+ "prepublishOnly": "npm run build",
44
+ "prepack": "node scripts/materialize-skills.js",
45
+ "postpack": "node scripts/materialize-skills.js --restore"
42
46
  },
43
47
  "dependencies": {
44
48
  "axios": "^1.7.7",
45
49
  "commander": "^12.1.0"
46
50
  },
47
51
  "devDependencies": {
52
+ "@playwright/test": "1.61.1",
48
53
  "@types/node": "^22.9.0",
49
54
  "nock": "14.0.16",
50
55
  "tsx": "^4.19.2",
@@ -7,7 +7,7 @@ description: ad-dashboard (https://macchiato.site) の webgram CLI 経由で広
7
7
 
8
8
  Google Drive から手動 DL 済みの動画を各媒体に半自動入稿するためのスキル。**現状 YDA のみ対応**、Meta / TikTok は将来対応予定。
9
9
 
10
- 配置・発火方法は同ディレクトリの [README.md](./README.md) 参照。
10
+ 配置・発火方法・ログイン手順は [cli/README.md](../../README.md) の「初期設定: Skill として配置する」章を参照。
11
11
 
12
12
  ## 動画入稿フロー (メイン用途)
13
13
 
@@ -144,3 +144,69 @@ open "https://ads-display.yahoo.co.jp/campaign/detail?accountId=<accountId>&camp
144
144
  | 汎用入稿 (JSON) 実入稿 | `npx -y addashboard-cli@latest submit --platform <媒体> --json-file <path> --no-dry-run --yes` |
145
145
 
146
146
  汎用入稿 (JSON ボディ直渡し) は yda / meta / google / smartnews / bytedance の 5 媒体対応。fixtures の雛形は tarball 同梱の `fixtures/*_poc.json`、各媒体の必須フィールドは `fixtures/README.md`。
147
+
148
+ ***
149
+
150
+ ## YDA入稿プランナー(HTML DOCS / JSON入稿・レスポンシブ画像固定型)
151
+
152
+ 動画の API 入稿とは別に、**レスポンシブ(画像)・固定型の一括入稿** を計画・確認するためのシングルHTMLツール。2026-07-16 / 07-21 定例フィードバックを反映。**2026-07-23 に CSV 書き出しを廃止し、保存・入稿受け渡しを JSON に統一**。
153
+
154
+ - **ファイル**: 本スキル同梱の [`yda-planner.html`](./yda-planner.html)(ローカルで開くだけ・依存なし。実データ同梱: タイトル999 / 画像633 / グループ96)
155
+ - **役割**: 動画=`addashboard-cli submit`(API入稿)、**画像=このプランナーで計画 → 「入稿JSON書き出し」→ 同じ `submit --platform yda` に流す**(Yahoo管理画面CSVインポートは廃止)。
156
+ - **基本思想(定例)**: AIで生成できる部分は **AIに生成させ(JSON読込)**、絶対に人が確定する部分(クリエイティブ選定・確認)を **スプシ的コピペ・一括入力・複製** で楽にする。プランナーで確認・修正して **OK なら 入稿JSON書き出し(=GO)→ `submit` dry-run → 本実行**。
157
+ - **ビュー**: `媒体要件`(YDA/Meta タブの仕様・使い方ページ)/ `プラン`(戦略メモ → 案件設定 → シート/ツリー切替。シートは1広告=1行の表+広告/広告グループ/キャンペーンのネストタブ、ツリーは開閉・複製・量産)/ `参照データ`(タイトル&説明一覧・登録画像一覧の閲覧+新規登録)/ `履歴`(保存バージョン一覧)。同一 state を投影し切替。
158
+
159
+ ### 保存とバージョン履歴(2026-07-23〜)
160
+
161
+ - **バージョン保存**: 保存のたびに **常に新バージョン**(v1, v2…)。JSON は `schemaVersion:2` で `meta`(バージョンID・作成/更新日時・作成者・対象媒体・名称・メモ)を持つ。旧 v1 JSON も読込時に自動マイグレーション。**履歴本体はブラウザ内(localStorage)に自動保存**されるため、フォルダ設定なしで一覧・再読込・削除が完結する。
162
+ - **保存フォルダ連携(入稿計画/)**: 履歴ビューの「📁 保存フォルダに接続」で本スキル同梱の `入稿計画/` フォルダを**初回に1回だけ**選ぶと、以後は開くだけで自動接続され、保存のたびにファイルにも書き出される(File System Access API / Chrome系のみ。非対応環境・未接続時はダウンロード動作)。
163
+ - **履歴ビュー**: バージョン・日時・媒体・名称・メモ・作成者の一覧。`読込`(過去バージョン復元)/ `編集`(名称・メモ)/ `削除`。
164
+ - **入稿JSON書き出し**: 設定ダイアログなしの**ワンクリック**。アカウントID・目的(goal)・開始日は案件設定チップ、入札はキャンペーン行(tCPA→`MAXIMIZE_CONVERSIONS`+targetCpa)、ターゲティングは広告グループ行の列(日本語ラベル→API enum 自動変換)から `*_submit-body_*.json` を生成。手入稿バナー・参照未解決の広告は自動除外。accountId 未入力・0件なら書き出し中止(空入稿防止)。
165
+
166
+ ### 量産構造(媒体要件の核)
167
+
168
+ - 階層 **キャンペーン > 広告グループ > 広告**。`1:1:4`(基本)/ 初期 `1:1:10`(撒いて選ぶ)。
169
+ - **変数=キャンペーン**(検証したい1点だけ変えてキャンペーンを分ける)、**クリエイティブ束=広告グループ内の広告**。
170
+ - 北さんのやり方 = **テンプレ複製 → 中身クリア → 変数だけ差し替え** の量産。プランナーのツリー複製ダイアログ / 「N本まとめて」/ キャンペーン量産で再現。
171
+ - **広告グループ = 1つの `【paramCode】`**。これでキャンペーンID/広告グループID/メディアID/タイトル/説明文/最終URL を解決(VLOOKUP代替)。派生値は純関数で毎回算出。
172
+
173
+ ### 入稿モードと手入稿
174
+
175
+ - モード: **新規**(12,000円/日・1CP=1AG=1広告を量産)/ **既存ASC**(5万〜10万円/日・まとめ入稿)/ 既存-広告グループ追加 / 既存-広告追加。
176
+ - **バナー(画像のみ)は API 未対応 → 手入稿**。プランナーでは `手入稿` フラグで区別し、入稿JSONから自動除外。
177
+
178
+ ### 発火時の案内
179
+
180
+ 「YDA入稿プランナー」「入稿シート」「タイトル/画像一覧」「まとめ入稿の確認用シート」等を求められたら、このHTMLを案内・オープンする(`open <path>`)。入稿JSONは書き出し後 `webgram submit --platform yda --json-file <submit-body>` で **dry-run → 本実行** にかける。
181
+
182
+ ## ログイン情報の取り扱い
183
+
184
+ - **通常は device flow を使う**: パスワードは扱わない。CLI が出力する `verification_url` と `user_code` をユーザーに伝え、ブラウザ許可を待つだけ。Google 資格情報は Google 側でのみ入力される
185
+ - device_code / user_code は Google のワンタイム値。不要に貼らない
186
+ - 認証成功後は `~/.config/webgram/credentials.json` (`chmod 0600`) に保存される (再認証不要)
187
+ - **`--password` (ROPC) は deprecated なフォールバック**: どうしても device flow もブラウザも使えない場合のみ。使う場合は AskUserQuestion で1回だけ聞き、`printf '%s\n' '<pw>' | npx -y addashboard-cli@latest auth login --password --email <email>` の形で **stdin パイプ** 経由で渡す (argv は `ps` / シェル履歴に露出するため)。パスワードは応答メッセージに絶対書かない
188
+
189
+ ## トラブルシュート
190
+
191
+ | 症状 | 対処 |
192
+ |---|---|
193
+ | `command not found: npx` | Node.js が入っていない。`https://nodejs.org` から LTS 版インストールを案内 |
194
+ | `Login failed: invalid_grant` | Web UI (`https://macchiato.site`) でログインできるか確認を案内 |
195
+ | `Login failed: network_error` | `curl -v https://macchiato.site/api/health` で疎通確認 |
196
+ | `not_logged_in` (whoami 時) | `auth login` から再度実行 |
197
+ | Rate limit (429) | 15分間ログイン失敗5回でブロック。15分待ってから再試行 |
198
+ | 入稿失敗 (媒体API側) | エラーメッセージを要約してユーザーに提示、残りの入稿を続けるか AskUserQuestion で確認 |
199
+
200
+ ## 制約 / 今後の拡張
201
+
202
+ - **将来的な体験改善**: Google Drive 拡張機能から複数動画を選択 → プロンプト自動生成 → 貼り付け実行までワンストップ化
203
+ - CLI バージョンは `npmPackage: "addashboard-cli@latest"` で常に最新。特定バージョンに固定したい場合は `config.json` を `addashboard-cli@0.2.3` の形に変更
204
+
205
+ ### 入稿プランナー関連ロードマップ(2026-07-16 定例 / 2026-07-23 更新)
206
+
207
+ - ~~CSVを介さない直接入稿~~ → **完了(2026-07-23)**: プランナーの「入稿JSON書き出し」が submit-body.json を生成し、そのまま `submit --platform yda` に流せる。CSV書き出しは廃止。
208
+ - **キャンペーン/広告グループID の自動取得**: 管理画面からの手コピペ(`【paramCode】`↔ID の突合)を、API/MCP で自動取得して置き換える。新規CPは払出し後にID解決。
209
+ - **新規画像のメディア登録自動化**: ドライブ格納画像を YDA メディアに登録し、プランナーの参照データ(画像番号→mediaID)へ反映。
210
+ - **命名規則の統一**: `【】内の数字`のみ共通で、キャンペーン名/広告名は担当者差がある → システム命名に寄せられるようにする。
211
+ - **Meta広告対応**: backend/CLI は実装済み・GUI未対応。検証範囲と要件一覧のドラフトはプランナー媒体要件ビューの「Meta広告」タブを参照。
212
+ - **未確定(要実機確認)**: CTA既定(画像=もっとみる / 動画=詳細を見る)と `buttonText` enum、画像レスポンシブAPI入稿(PR #82)の実疎通、新規時に CP/AG ID 未払出でどう入稿するか、画像サムネURLの入手経路。