@bluevs/ttcli 0.0.6 → 0.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluevs/ttcli",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "TikTok CLI - designed for AI Agent and developers",
5
5
  "bin": {
6
6
  "ttcli": "scripts/run.js"
@@ -9,12 +9,12 @@
9
9
  "postinstall": "node -e \"console.log('\\n📦 ttcli installed. To install the openclaw skill, run:\\n bash $(npm root -g)/@bluevs/ttcli/skills/ttcli/scripts/install-skill.sh\\n')\""
10
10
  },
11
11
  "optionalDependencies": {
12
- "@bluevs/ttcli-darwin-arm64": "0.0.6",
13
- "@bluevs/ttcli-darwin-x64": "0.0.6",
14
- "@bluevs/ttcli-linux-arm64": "0.0.6",
15
- "@bluevs/ttcli-linux-x64": "0.0.6",
16
- "@bluevs/ttcli-win32-arm64": "0.0.6",
17
- "@bluevs/ttcli-win32-x64": "0.0.6"
12
+ "@bluevs/ttcli-darwin-arm64": "0.0.7",
13
+ "@bluevs/ttcli-darwin-x64": "0.0.7",
14
+ "@bluevs/ttcli-linux-arm64": "0.0.7",
15
+ "@bluevs/ttcli-linux-x64": "0.0.7",
16
+ "@bluevs/ttcli-win32-arm64": "0.0.7",
17
+ "@bluevs/ttcli-win32-x64": "0.0.7"
18
18
  },
19
19
  "engines": {
20
20
  "node": ">=16"
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: ttcli
3
- version: 0.0.6
3
+ version: 0.0.7
4
4
  description: 直接调用 TikTok Marketing API(access token 鉴权,不经 VH 平台/项目层)。当用户提供原生 TikTok access_token + advertiser_id、要直连 TikTok 创建或查询 Smart+ campaign/adgroup/ad、或查 identity/app/region 等元数据时使用。注意:用户走 VH 项目流程(po_xxxx + account_id)的 TikTok 创编应改走 vhcli tiktok。
5
5
  ---
6
6
 
7
7
  # TikTok CLI (`ttcli`)
8
8
 
9
- > **Skill version**: `0.0.6`
9
+ > **Skill version**: `0.0.7`
10
10
  >
11
11
  > 当用户问"ttcli skill 版本是多少 / skill 装好了吗 / 升级生效了没" 时,**直接念出上面的版本号**。
12
12
  > 用户期望更高版本但没看到 → 让他们:(1) 重跑 `npm install -g @bluevs/ttcli && bash $(npm root -g)/@bluevs/ttcli/skills/ttcli/scripts/install-skill.sh` (2) 然后**新开一个会话**(skill 在会话启动时加载,老会话不刷新)。
@@ -33,6 +33,41 @@ This skill is intentionally short. Always treat `ttcli -h` and `ttcli <subcomman
33
33
 
34
34
  如果用户问「能不能直接调 X 接口」,先回「我们走 ttcli,让我看看包了没;没包的话我把这个接口加到 ttcli 里再用,会更稳」。
35
35
 
36
+ ## 🔍 如何发现 ttcli 能力(不要靠记忆)
37
+
38
+ SKILL.md **不**枚举所有 ttcli 子命令;项目还在长。新会话或不确定 ttcli 是否已支持某能力时,走两步发现:
39
+
40
+ **第 1 步 — `ttcli schema`(默认 JSON)一次拿全树**
41
+ - 输出含每条命令的 `path` / `short` / `long` / `flags`(含 `name`/`type`/`default`/`usage`/`required`)
42
+ - AI agent 视角的"能力清单 API":一条命令拉到全部,免去靠记忆
43
+ - 速看人类视图:`ttcli --human schema --depth=2`(root + namespace + 子命令短描述)
44
+
45
+ **第 2 步 — `ttcli <path> -h`(cobra 自带)看具体细节**
46
+ - 完整 long help(含示例段落、关键链路提示,如"返回的 X ID 喂入 adgroup body 的 Y 字段")
47
+ - 每个 flag 的默认值、required 标记、shorthand
48
+
49
+ **典型用法**(jq 配合 schema JSON):
50
+ ```bash
51
+ # 找名字含 hashtag 的所有命令
52
+ ttcli schema | jq '.. | objects | select(.short | test("hashtag"; "i")) | .path'
53
+
54
+ # 看 tool namespace 下所有子命令
55
+ ttcli schema | jq '.. | objects | select(.path == "ttcli tool") | .subcommands[].path'
56
+
57
+ # 看某命令的所有 required flag
58
+ ttcli schema | jq '.. | objects | select(.path == "ttcli identity video list") | .flags[] | select(.required) | .name'
59
+
60
+ # 找所有支持 --dry-run 的写命令
61
+ ttcli schema | jq '.. | objects | select(.flags // [] | map(.name) | index("dry-run")) | .path'
62
+ ```
63
+
64
+ **何时用**:
65
+ - 不确定 ttcli 能不能做某事 → 第 1 步(grep / jq 过滤)
66
+ - 选定命令、要写正确 flag 串 → 第 2 步
67
+ - 这两步替代"靠记忆猜命令" + "硬上 curl 直调"(hard rule #1 禁止)
68
+
69
+ **注意**:cobra 层 required 跟业务必填不一定一致——很多 create 类命令 cobra flag 不标 required,但 `Validate()` / TikTok 服务端会拒。`long` 文本里的 `REQUIRED:` 段落 + 实际报错才是终极真理;schema 的 `required` 字段是辅助信号。
70
+
36
71
  ## 🚨 与用户对话的硬性约定:错误信息要翻译
37
72
 
38
73
  ttcli 和 TikTok 返回的报错都是技术语言(`missing required fields: [adgroup_id]`、`Invalid optimization goal`、`code=40002 ...`)。**严禁原样把这些贴给用户**——非技术用户看到字段名、code 数字会懵。
@@ -120,7 +155,21 @@ Before creating a campaign or adgroup, gather the IDs you'll reference:
120
155
 
121
156
  ```
122
157
  ttcli auth show # confirm credentials loaded + their source
158
+ ttcli user info # → who am I? (TikTok for Business user behind the access token)
123
159
  ttcli bc list # → bc_id (Business Centers; needed for BC_AUTH_TT identities)
160
+ ttcli bc changelog list --bc-id=B # BC audit log (member/account/asset/settings changes)
161
+ ttcli bc balance --bc-id=B # BC's own wallet balance (requires finance role)
162
+ ttcli bc transaction list --bc-id=B # transaction history (BC / advertiser / portfolio level, 13 transaction_type)
163
+ ttcli bc transaction summary --bc-id=B # BC aggregated by date × funds_type × invoice + top-level totals
164
+ ttcli bc cost list --bc-id=B # actual ad spend per advertiser (NEGATIVE amounts; ~10h delay)
165
+ ttcli bc payment-portfolio list --bc-id=B # financial portfolios (whitelist feature; SHARED/NON_SHARED)
166
+ ttcli bc payment-portfolio create --name=X --advertiser-ids=A,B # create SHARED portfolio (max 20 advertisers)
167
+ ttcli bc payment-portfolio attach --portfolio-id=P --advertiser-ids=A,B # attach more advertisers to existing SHARED portfolio
168
+ ttcli bc payment-portfolio advertiser list --portfolio-id=P # advertisers currently attached to a portfolio
169
+ ttcli bc payment-portfolio credit-line update --portfolio-ids=P1,P2 --percentages=0.6,0.4 # allocate credit by % across SHARED portfolios
170
+ ttcli advertiser balance --bc-id=B # advertiser balances under a BC (requires finance role)
171
+ ttcli advertiser transaction list --bc-id=B # legacy advertiser transactions (CASH/GRANT split, 4 transfer_type)
172
+ ttcli advertiser budget changelog list --bc-id=B --advertiser-id=A # budget modification audit (who changed what budget when)
124
173
  ttcli app list # → app_id (Android/iOS apps)
125
174
  ttcli minis list # → minis_id (TikTok Minis: MINI_GAME / MINI_SERIES)
126
175
  ttcli identity list # → identity_id (Spark Ads publishing identity)
@@ -139,8 +188,53 @@ ttcli tool targeting info \
139
188
  --objective-type=APP_PROMOTION --promotion-type=APP_ANDROID \
140
189
  --placements=PLACEMENT_TIKTOK \
141
190
  --targeting-ids=6254925,6254928 # ← reverse: name + parent hierarchy from IDs (use --scene=ISP for isp_id lookup)
191
+ ttcli tool language # → language codes for targeting_spec.languages (audience targeting; not the same as --language=zh-CN on tool region which is *display* language)
192
+ ttcli tool interest-category list # → general interest tree (lighter than 'targeting search'; only needs --advertiser-id)
193
+ ttcli tool interest-keyword recommend # → other-interest keyword IDs from a seed (single OR multi keyword)
194
+ ttcli tool interest-keyword info # ← reverse: keyword_id → name + EFFECTIVE/INEFFECTIVE status
195
+ ttcli tool action-category list # → behavior categories (CREATOR_RELATED + VIDEO_RELATED in one call)
196
+ ttcli tool hashtag recommend # → hashtag IDs from seeds (action_scene=HASHTAG_RELATED)
197
+ ttcli tool hashtag info # ← reverse: keyword_id → hashtag + ONLINE/OFFLINE
198
+ ttcli tool targeting-category recommend # → system-recommended interest+action subset for region/app
199
+ ttcli tool search-keyword recommend # → Search-Ads keywords + monthly search volume (US only)
200
+ ttcli tool search-keyword idea # → keyword research (volume RANGE + 3mo/yoy trend + competition + CPC)
201
+ ttcli tool diagnosis search-health # → Search Ads adgroup/ad health (volume + relevance + bid/budget)
202
+ ttcli tool os-version list # → audience OS version IDs (per --os-type=ANDROID|IOS; os_id NOT globally unique)
203
+ ttcli tool device-model list # → device model tree (3-level BRAND/SERIES/MODEL; ~14k total but only ~12% is_active)
204
+ ttcli tool carrier list # → mobile carriers per country (~69 countries / ~251 carriers, ~92% in_use)
205
+ ttcli tool targeting list # → ISP (broadband) targeting tags by country (NOT mobile carriers; feeds isp_ids)
206
+ ttcli tool contextual-tag list # → contextual targeting tags (whitelist; REACH/VIDEO_VIEWS/RF_REACH only)
207
+ ttcli tool contextual-tag info # ← reverse: contextual_tag_id → details. NOTE: list can return empty while info still works (use info for whitelist validation)
208
+ ttcli tool content-exclusion list # → content exclusion + vertical sensitivity categories (REACH/VIDEO_VIEWS/ENGAGEMENT only)
209
+ ttcli tool content-exclusion info # ← reverse: category_id → details (mix EXCLUSION + VERTICAL OK; merged into one list)
210
+ ttcli tool bid recommend # → TikTok-suggested bid for cost-cap (BID_TYPE_CUSTOM); TRAFFIC/WEB_CONVERSIONS only
211
+ ttcli tool vbo-status # → check Value-Based Optimization support for adgroup config (12 status fields)
212
+ ttcli tool brand-safety partner-status # → 3rd-party brand-safety partner authz (Zefr only)
213
+ ttcli tool url-validate # → check if a URL is a valid Universal Link / App Link / custom scheme
214
+ ttcli tool phone-region-code # → 235 phone region entries (ISO + calling code, e.g. US/+1, AT/+43)
215
+ ttcli tool timezone # → 150 timezones; gmt_offset is FIXED standard-time (ignores DST)
216
+ ttcli tool open-url # → TikTok web URL → in-app sslocal:// deep link (for RF Reach ads' deeplink field)
217
+ ttcli targeting search # → interest/behavior/hashtag IDs (NOT 'tool targeting'; see note below)
218
+ ttcli campaign-label list # → list campaign labels (tags applied to campaigns; GENERAL / MARKETING_EVENT)
219
+ ttcli creative auto-message create # → create welcome message (DM Ads; auto-reply Q&A library)
220
+ ttcli creative auto-message list # ← list welcome messages (audit_status: AUDITING/PASS/REJECTED)
142
221
  ```
143
222
 
223
+ **⚠️ Two `targeting search` endpoints, do not conflate:**
224
+
225
+ | Command | URL | Returns | Feeds into |
226
+ |---|---|---|---|
227
+ | `ttcli tool targeting search` | `/tool/targeting/search/` | GEO IDs / ZIP IDs from name | `targeting_spec.location_ids` / `zipcode_ids` |
228
+ | `ttcli targeting search` | `/targeting/search/` (no `tool/` prefix!) | Interest / behavior / hashtag IDs | `targeting_spec.interest_category_ids` / `interest_keyword_ids` / `purchase_intention_keyword_ids` / `actions[].action_category_ids` |
229
+ | `ttcli tool interest-category list` | `/tool/interest_category/` | The full general-interest tree (no keyword search) | `targeting_spec.interest_category_ids` (overlaps with `targeting search` GENERAL_INTEREST browse mode; pick whichever; this one only needs `--advertiser-id`) |
230
+ | `ttcli tool interest-keyword recommend` | `/tool/interest_keyword/recommend/` | "Other-interest" keyword IDs from a seed (status=EFFECTIVE only) | `targeting_spec.interest_keyword_ids` (overlaps with `targeting search --keywords=...` ADDITIONAL_INTEREST; this endpoint is the simpler one if all you need is interest_keyword reverse lookup) |
231
+ | `ttcli tool action-category list` | `/tool/action_category/` | Behavior categories tagged by `action_scene` (CREATOR_RELATED + VIDEO_RELATED) | adgroup body `actions[]`: `{action_scene, action_category_ids, action_period}` — group IDs by scene (each `actions[]` entry uses ONE scene). action_category_id is NOT globally unique; same id="10" exists in both scenes. |
232
+ | `ttcli tool hashtag recommend` | `/tool/hashtag/recommend/` | Hashtag IDs from seed keywords (status=ONLINE only) | adgroup body `actions[]` with `action_scene=HASHTAG_RELATED`. **Same field name `action_category_ids` reused** — distinguish by `action_scene`. Operator AND combines all keywords; OR returns per-keyword (with `input_keyword`). |
233
+ | `ttcli tool targeting-category recommend` | `/tool/targeting_category/recommend/` (POST) | Recommended SUBSET for region+app (industry-driven) — interest + action only (no hashtag) | `targeting_spec.interest_category_ids` AND `actions[].action_category_ids` (with `action_scene` from response). Use this when you want a pre-curated starting set instead of the full tree. |
234
+ | `ttcli tool search-keyword recommend` | `/tool/search_keyword/recommend/` | Search-Ads keyword recommendations + estimated monthly search volume | Search Ads campaigns (NOT feed/Smart+ targeting). Three input modes (mutually exclusive): `--search-queries` (max 5 English words) / `--ad-ids` (whitelist) / `--landing-page-urls` (whitelist). Regions: US only. |
235
+ | `ttcli tool search-keyword idea` | `/tool/search_keyword/keyword_idea/` | Keyword research — volume RANGE + 3mo/yoy trend + competition + CPC range | Search Ads campaigns. Use when you need bid/budget planning data, not just expansion. Up to 1 country (12 supported, US default). `--brand-type` only for US. |
236
+ | `ttcli tool diagnosis search-health` | `/tool/diagnosis/search/health/` | Health diagnosis for a Search-Ads adgroup or ads (search_volume / keyword_relevance / bid_budget) | Search Ads only. `--adgroup-id` OR `--ad-ids` (max 50, all in same adgroup; both passed → adgroup_id ignored server-side). Returns suggested bid + relevance breakdown per ad. |
237
+
144
238
  `tool region` accepts `--language=zh-CN` (or any of 78 supported codes) for localized region names — useful when surfacing options to the user.
145
239
 
146
240
  ## Write safety: ALWAYS dry-run first
@@ -344,7 +438,12 @@ Per the doc: "对于现有广告账号,当广告组的投放广告位为自动
344
438
  | `tiktok_item_id` (Spark Ads) | `/tt_video/info/` | `ttcli tt-video info --auth-code=...` |
345
439
  | List posts under an identity | `/identity/video/get/` | `ttcli identity video list --identity-id=... --identity-type=...` |
346
440
  | Verify `identity_id` | `/identity/info/` | `ttcli identity info --identity-id=... --identity-type=...` |
441
+ | List native series under an identity | `/identity/native_series/get/` | `ttcli identity native-series list --identity-id=... --identity-type=...` |
347
442
  | Search ad-library videos (`video_id`) | `/file/video/ad/search/` | `ttcli file video search` |
443
+ | Upload video to ad library | `/file/video/ad/upload/` | `ttcli file video upload --video-file=PATH` (or `--upload-type=UPLOAD_BY_URL --video-url=...`) |
444
+ | Inspect ad-library video by ID | `/file/video/ad/info/` | `ttcli file video info --video-ids=...` (max 60; unusable IDs silently dropped) |
445
+ | Suggest cover images for a video | `/file/video/suggestcover/` | `ttcli file video suggest-cover --video-id=...` (wait 30s-5min after upload for transcoding) |
446
+ | Rename an ad-library video | `/file/video/ad/update/` | `ttcli file video update --video-id=... --file-name=...` (collisions auto-suffixed by TikTok) |
348
447
  | Search ad-library images (`image_id`) | `/file/image/ad/search/` | `ttcli file image search` |
349
448
  | Upload video → `video_id` | `/file/video/ad/upload/` | ⏳ not yet wrapped |
350
449
  | Upload image → `web_uri` | `/file/image/ad/upload/` | ⏳ not yet wrapped |
@@ -380,6 +479,42 @@ For MINI_GAME or any TikTok-placement ad creation:
380
479
 
381
480
  Note: TikTok identity-list pagination requires `identity_type` to be set — without a type filter, `page_info` is null in the response.
382
481
 
482
+ ## Automated Rules (`optimizer rule create`)
483
+
484
+ Set conditions on campaigns/adgroups/ads (CPA > X, CTR < Y, etc.) and trigger actions automatically (turn on/off, adjust budget/bid, message). Like adgroup create, the body is deeply nested (`apply_objects[]`, `conditions[]`, `actions[]` with nested `value`/`frequency_info`, `notification`, `rule_exec_info` with optional `time_period_info[]`) so it's a body-driven endpoint:
485
+
486
+ ```bash
487
+ ttcli optimizer rule create --body-from-file=/tmp/rule.json --dry-run # preview create
488
+ ttcli optimizer rule create --body-from-file=/tmp/rule.json # create
489
+ ttcli optimizer rule update --body-from-file=/tmp/rule.json --dry-run # preview update (must include rule_id per rule)
490
+ ttcli optimizer rule update --body-from-file=/tmp/rule.json # update
491
+ ttcli optimizer rule status update --operate-type=TURN_ON --rule-ids=R # enable / disable / delete in bulk
492
+ ttcli optimizer rule status update --operate-type=DELETE --rule-ids=R --dry-run
493
+ ttcli optimizer rule batch-bind --rule-id=R --dimension=CAMPAIGN \
494
+ --dimension-ids=C1,C2 --bind-type=BIND # attach rule to objects
495
+ ttcli optimizer rule batch-bind --rule-id=R --dimension=CAMPAIGN \
496
+ --dimension-ids=C1 --bind-type=UNBIND --dry-run # detach (preview)
497
+ ttcli optimizer rule info --rule-ids=6984697088064290818 # by IDs (read-after-write)
498
+ ttcli optimizer rule list --status=ON # by filters/pagination
499
+ ttcli optimizer rule list --data-dimension=CAMPAIGN --page=1 --page-size=20
500
+ ttcli optimizer rule result list --action=MESSAGE # execution history (aggregate)
501
+ ttcli optimizer rule result list --time='2026-06-01 00:00:00,2026-06-30 23:59:59'
502
+ ttcli optimizer rule result info --rule-ids=R1 --exec-ids=E1 # per-object outcomes
503
+ ```
504
+
505
+ - `create`, `update`, `status update`, and `batch-bind` are write endpoints — all support `--dry-run`. `create`/`update` return `rule_ids[]`; `status update` returns the rule_ids that were successfully changed; `batch-bind` returns empty `data:{}` (success means everything bound/unbound).
506
+ - `update` body shape is identical to `create`'s but each rule **must** include `rule_id`. Recommended workflow: `rule info` to pull → edit JSON → `rule update --dry-run` → `rule update`.
507
+ - `status update` is the bulk lifecycle endpoint: `--operate-type=TURN_ON|TURN_OFF|DELETE` + `--rule-ids=X,Y,Z`. **Atomic**: if any rule fails, the whole batch rolls back. Client-side enum validation catches bad operate_type early.
508
+ - `batch-bind` attaches/detaches existing rules to objects without rewriting rule definitions. Two input modes: convenience flags (`--rule-id/--dimension/--dimension-ids/--bind-type` for one entry) or `--body / --body-from-file` (multi-entry). **Smart+ Upgraded ads are NOT supported by this endpoint** — TikTok returns `code=40002 This API does not support Upgraded Smart Plus ads.` on Smart+ campaigns; for those, edit `apply_objects` via `rule update` instead.
509
+ - DELETE is soft-delete — deleted rules still show up via `optimizer rule list --status=DELETED`.
510
+ - Drill-down chain: `rule list` (definitions) → `rule result list` (each execution's aggregate counts) → `rule result info` (each affected object's SUCCESS/FAIL + error_msg)
511
+ - `info` (by IDs) and `list` (by filters) return rule definitions; `result list` returns execution history; `result info` returns per-object outcomes for given (rule_id, exec_id) pairs
512
+ - Common shapes shown in `ttcli optimizer rule create --help` (message-only rule, budget-adjust rule with frequency limit)
513
+ - Permission gate split: `list` and `result list` are open (return empty array if no data); `create`, `update`, `status update`, `batch-bind`, `info`, and `result info` require BC admin to grant `optimizer` resource scope (without it return 40002 / 52404). Note: `update`, `status update`, and `batch-bind` reach **business-level validation** (TikTok parses the body and validates rule_id/object existence) rather than failing at the scope layer.
514
+ - Filter shape: `--status=ON|OFF|DELETED`, `--rule-info=ID,name`, `--data-dimension=CAMPAIGN|ADGROUP|AD`. `result list` adds `--action=TURN_ON|TURN_OFF|MESSAGE|DAILY_BUDGET|LIFETIME_BUDGET|BID` (TikTok docs typo it as LIFERIME_BUDGET — use the correct LIFETIME_BUDGET) and `--time='start,end'` (UTC, format YYYY-MM-DD HH:MM:SS). cmd encodes as `filtering` JSON object (TikTok doc shows v1.2 `filters: [{filter_type, filter_input}]` in curl example, but real v1.3 uses `filtering` per the parameter table).
515
+ - `result info` takes paired flags: `--rule-ids` and `--exec-ids` must have equal length; index N pairs them into the `result_detail` array TikTok expects.
516
+ - Field-name split inside `rules[]`: `info`/`list` populate `last_check_result_summary`; `result list` populates `rule_check_result` (same nested struct). Use `Rule.CheckResult()` helper to ignore the difference.
517
+
383
518
  ## Idempotency: reuse request_id on retry
384
519
 
385
520
  Without `--request-id`, ttcli generates one from `time.Now().UnixNano()` and logs it to stderr: