addashboard-cli 0.3.0 → 0.3.1

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,479 +1,52 @@
1
- # webgram CLI
1
+ # addashboard-cli
2
2
 
3
- ad-dashboard を Claude Code / Codex CLI / ターミナルから操作するための CLI。
4
- 「install → login → 広告入稿 dry-run → 実入稿」までを 1 本のマニュアルで完走できる構成にしてある。
3
+ 広告ダッシュボード操作用の CLI。詳細な使い方・運用フローは社内マニュアル参照。
5
4
 
6
- > 🔐 認証方式: Google SSO (loopback OAuth / 非対話環境は device flow) を主軸、`--password` (ROPC) は deprecated フォールバック
7
- > 📦 配布: **npm public registry** (`addashboard-cli` unscoped) — `npx -y addashboard-cli@latest` で追加インストール不要
5
+ ## インストール
8
6
 
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 から取得)
21
-
22
- ```bash
23
- npx -y addashboard-cli@latest --version
24
- # → 0.2.3
25
- ```
26
-
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)
46
- ```
47
-
48
- ブラウザが自動で開かない環境では、表示された URL を手動で開けば同じフローが完了する。
49
-
50
- #### 非対話環境 (Claude Code / CI 等) — device flow
51
-
52
- `stdout` が TTY でない**非対話環境では自動で Google device flow に切り替わる** (loopback ブラウザは使えないため)。TTY でも `--device` を付ければ強制できる。
53
-
54
- ```bash
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 本体を配置:
7
+ Node.js 18+ が必要。
201
8
 
202
9
  ```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
- ```
10
+ # 都度実行 (推奨)
11
+ npx -y addashboard-cli@latest --help
208
12
 
209
- **方式 B: 都度 `--instructions` で明示読み込み**
210
-
211
- ```bash
212
- codex --instructions ~/.codex/skills/ad-ops/SKILL.md "YDA に PAUSED で入稿の dry-run 走らせて"
13
+ # あるいはグローバルインストール
14
+ npm install -g addashboard-cli
15
+ webgram --help
213
16
  ```
214
17
 
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
- 通常は指定不要 (デフォルトで本番エンドポイントに接続)。ローカル開発時のみ環境変数で切り替える:
18
+ ## ログイン
293
19
 
294
20
  ```bash
295
- export WEBGRAM_ENDPOINT=http://localhost:3001
296
- webgram auth login
297
- ```
298
-
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。
316
-
317
- ### `webgram list --platform <p> --resource <r> [--account-id <id> --campaign-id <id>]`
318
-
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 回 → まだ失敗すればエラー
21
+ webgram auth login # ブラウザで認証
22
+ webgram auth whoami # 状態確認
23
+ webgram auth logout
354
24
  ```
355
25
 
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>` で実行するか、以下でグローバル導入:
26
+ ## 主なコマンド
371
27
 
372
28
  ```bash
373
- npm install -g addashboard-cli
374
- which webgram
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 # 実入稿
32
+ webgram submit-plan --plan-file <入稿計画.json> # 入稿計画の一括検証 (dry-run 既定)
33
+ webgram submit-plan --plan-file <入稿計画.json> --no-dry-run --yes # 1キャンペーンずつ実入稿 (再開可能)
34
+ webgram freee <login|templates|issue> # freee 請求書発行 (allowlist 制)
375
35
  ```
376
36
 
377
- ### `✗ Login failed: invalid_grant`
37
+ `<p>` = 対応媒体 (`yda` / `meta` / `google` / `smartnews` / `bytedance`)。`submit-plan` は現状 `yda` のみ。
378
38
 
379
- Google SSO 時は認可コードが期限切れ / 無効。再度 `webgram auth login` を実行。`--password` フォールバック時はメール/パスワードが違うので Web UI で確認。
39
+ 入稿ボディ JSON の雛形と必須フィールドは [`fixtures/README.md`](./fixtures/README.md)。
40
+ 入稿計画 JSON は同梱の YDA 入稿プランナー ([`skills/ad-ops/yda-planner.html`](./skills/ad-ops/yda-planner.html)) が書き出す。
380
41
 
381
- ### `✗ Login failed: network_error`
42
+ ## Skill として使う
382
43
 
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 を確認。
44
+ Claude Code / Codex CLI 用の `ad-ops` skill (広告運用スキル・YDA入稿プランナー同梱) と `invoice-issue-freee` skill を同梱。配置手順は [`skills/ad-ops/README.md`](./skills/ad-ops/README.md)。
400
45
 
401
46
  ## 開発
402
47
 
403
- ### ローカルインストール (ソース clone 派)
404
-
405
48
  ```bash
406
- git clone git@github.com:WEBGRAM-WG/ad-dashboard.git
407
- cd ad-dashboard/cli
408
49
  npm install
409
50
  npm run build
410
- npm link # webgram コマンドがグローバルに登録される
51
+ npm test
411
52
  ```
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
- 社内限定。
@@ -5,7 +5,7 @@ exports.resolvePath = resolvePath;
5
5
  exports.runList = runList;
6
6
  const apiClient_1 = require("../lib/apiClient");
7
7
  exports.ALLOWED_PLATFORMS = ['meta', 'yda', 'google', 'smartnews', 'bytedance'];
8
- exports.ALLOWED_RESOURCES = ['accounts', 'campaigns', 'resources'];
8
+ exports.ALLOWED_RESOURCES = ['accounts', 'campaigns', 'resources', 'media'];
9
9
  /**
10
10
  * v5 §5.2: platform × resource → backend エンドポイント解決テーブル。
11
11
  *
@@ -16,6 +16,9 @@ exports.ALLOWED_RESOURCES = ['accounts', 'campaigns', 'resources'];
16
16
  * SmartNews は creative リソースが ad に埋込まれる仕様のため、resources は未対応。
17
17
  * bytedance は T-05 で accounts / campaigns / resources GET を追加 (accounts は
18
18
  * ApiConnection.selectedAccounts 由来、campaigns / resources は TikTok Marketing API v1.3 実叩き)。
19
+ *
20
+ * media は W6 (新規アカウントインポート) 用の登録画像一覧リソース。yda のみ対応
21
+ * (/yda/media)。他媒体は未対応 (画像一覧 API 未実装)。
19
22
  */
20
23
  function resolvePath(input) {
21
24
  const { platform, resource, accountId, campaignId } = input;
@@ -25,6 +28,10 @@ function resolvePath(input) {
25
28
  if (!exports.ALLOWED_RESOURCES.includes(resource)) {
26
29
  throw new Error(`unknown resource: ${resource} (allowed: ${exports.ALLOWED_RESOURCES.join(', ')})`);
27
30
  }
31
+ // media (登録画像一覧) は yda のみ対応。他媒体は画像一覧 API 未実装のため未対応。
32
+ if (resource === 'media' && platform !== 'yda') {
33
+ throw new Error(`${platform} + media は未対応です (画像一覧は yda のみ対応)`);
34
+ }
28
35
  if (platform === 'meta') {
29
36
  if (resource === 'accounts')
30
37
  return { path: '/api/submission/meta/accounts', query: {} };
@@ -55,6 +62,11 @@ function resolvePath(input) {
55
62
  throw new Error('--account-id が必要です (yda + resources)');
56
63
  return { path: '/api/submission/yda/resources', query: { accountId } };
57
64
  }
65
+ if (resource === 'media') {
66
+ if (!accountId)
67
+ throw new Error('--account-id が必要です (yda + media)');
68
+ return { path: '/api/submission/yda/media', query: { accountId } };
69
+ }
58
70
  }
59
71
  if (platform === 'google') {
60
72
  if (resource === 'accounts')
@@ -1 +1 @@
1
- {"version":3,"file":"ads.js","sourceRoot":"","sources":["../../src/commands/ads.ts"],"names":[],"mappings":";;;AA0BA,kCAgFC;AAsBD,0BA+BC;AA9JD,gDAAwD;AAM3C,QAAA,iBAAiB,GAAe,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AACpF,QAAA,iBAAiB,GAAe,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAOpF;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CAAC,KAK3B;IACC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAE5D,IAAI,CAAC,yBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,cAAc,yBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3E,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,yBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,cAAc,yBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACzF,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACzE,OAAO,EAAE,IAAI,EAAE,gCAAgC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACzE,OAAO,EAAE,IAAI,EAAE,gCAAgC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,8BAA8B,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACxF,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACxE,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,EAAE,IAAI,EAAE,qCAAqC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,CAAC;YAC3F,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QACzE,CAAC;QACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACxE,OAAO,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QACzE,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,iCAAiC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC3F,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAC3E,OAAO,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC5E,CAAC;QACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAC3E,OAAO,EAAE,IAAI,EAAE,kCAAkC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,oCAAoC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC9F,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC9E,OAAO,EAAE,IAAI,EAAE,qCAAqC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC/E,CAAC;QACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,oCAAoC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC9F,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC9E,OAAO,EAAE,IAAI,EAAE,qCAAqC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC/E,CAAC;QACD,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC9E,OAAO,EAAE,IAAI,EAAE,qCAAqC,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,MAAM,QAAQ,EAAE,CAAC,CAAC;AAC5D,CAAC;AAkBD;;;GAGG;AACI,KAAK,UAAU,OAAO,CAAC,KAAgB;IAC5C,IAAI,QAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,QAAQ,GAAG,WAAW,CAAC;YACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC;IACpD,CAAC;IAED,IAAI,MAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,gCAAoB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC;IACpD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QACxE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAI,GAA0C,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7E,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAChE,MAAM,GAAG,GAAI,GAAoD,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK;eAClF,GAAa,CAAC,OAAO;eACtB,eAAe,CAAC;QACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACnC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ads.js","sourceRoot":"","sources":["../../src/commands/ads.ts"],"names":[],"mappings":"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"}