siluzan-tso-cli 1.1.61-beta.2 → 1.1.62-beta.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 +1 -1
- package/dist/index.js +39 -9
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/google-ads/google-ads-read.md +1 -1
- package/dist/skill/references/google-ads/google-ads-write.md +5 -1
- package/dist/skill/references/google-ads/pmax-api.md +1 -1
- package/dist/skill/references/google-ads/rules/google-ads-pmax-guide.md +1 -0
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.
|
|
54
|
+
> **注意**:当前为测试版(1.1.62-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -114974,6 +114974,12 @@ function sameWriteValue(expected, actual) {
|
|
|
114974
114974
|
}
|
|
114975
114975
|
return false;
|
|
114976
114976
|
}
|
|
114977
|
+
function biddingStrategiesMatch(expected, actual) {
|
|
114978
|
+
if (sameWriteValue(expected, actual)) return true;
|
|
114979
|
+
const exp = String(expected).trim().toUpperCase();
|
|
114980
|
+
const act = String(actual ?? "").trim().toUpperCase();
|
|
114981
|
+
return exp === "TARGET_CPA" && act === "MAXIMIZE_CONVERSIONS" || exp === "TARGET_ROAS" && act === "MAXIMIZE_CONVERSION_VALUE";
|
|
114982
|
+
}
|
|
114977
114983
|
function fieldCheck(field, expected, actual, present) {
|
|
114978
114984
|
if (!present) return { field, expected, actual: void 0, state: "unread" };
|
|
114979
114985
|
return {
|
|
@@ -115027,10 +115033,22 @@ function evaluateCampaignReadback(after, expected, readFailed) {
|
|
|
115027
115033
|
};
|
|
115028
115034
|
push("name", expected.name, ["name", "Name"]);
|
|
115029
115035
|
push("statusV2", expected.statusV2, ["statusV2", "StatusV2"]);
|
|
115030
|
-
|
|
115031
|
-
"biddingStrategyTypeV2",
|
|
115032
|
-
|
|
115033
|
-
|
|
115036
|
+
if (expected.biddingStrategyTypeV2 !== void 0) {
|
|
115037
|
+
const found = readKey(after, ["biddingStrategyTypeV2", "BiddingStrategyTypeV2"]);
|
|
115038
|
+
checks.push(
|
|
115039
|
+
found.present ? {
|
|
115040
|
+
field: "biddingStrategyTypeV2",
|
|
115041
|
+
expected: expected.biddingStrategyTypeV2,
|
|
115042
|
+
actual: found.value,
|
|
115043
|
+
state: biddingStrategiesMatch(expected.biddingStrategyTypeV2, found.value) ? "match" : "mismatch"
|
|
115044
|
+
} : {
|
|
115045
|
+
field: "biddingStrategyTypeV2",
|
|
115046
|
+
expected: expected.biddingStrategyTypeV2,
|
|
115047
|
+
actual: void 0,
|
|
115048
|
+
state: "unread"
|
|
115049
|
+
}
|
|
115050
|
+
);
|
|
115051
|
+
}
|
|
115034
115052
|
push("targetSpend_BidCeilingAmount", expected.targetSpendBidCeilingCents, [
|
|
115035
115053
|
"targetSpend_BidCeilingAmount",
|
|
115036
115054
|
"TargetSpend_BidCeilingAmount"
|
|
@@ -124693,6 +124711,16 @@ async function runAdPmaxGet(opts) {
|
|
|
124693
124711
|
`);
|
|
124694
124712
|
});
|
|
124695
124713
|
}
|
|
124714
|
+
function readDisplayNumber(value, label2) {
|
|
124715
|
+
const n = typeof value === "number" ? value : Number(String(value).trim());
|
|
124716
|
+
if (!Number.isFinite(n)) {
|
|
124717
|
+
console.error(`
|
|
124718
|
+
\u274C ${label2}\u987B\u4E3A\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${String(value)}
|
|
124719
|
+
`);
|
|
124720
|
+
process.exit(1);
|
|
124721
|
+
}
|
|
124722
|
+
return n;
|
|
124723
|
+
}
|
|
124696
124724
|
async function runAdPmaxEdit(opts) {
|
|
124697
124725
|
const accountId = requireAccountId(opts.account);
|
|
124698
124726
|
const campaignId = opts.campaignId.trim();
|
|
@@ -124702,11 +124730,13 @@ async function runAdPmaxEdit(opts) {
|
|
|
124702
124730
|
} else {
|
|
124703
124731
|
body = {};
|
|
124704
124732
|
if (opts.status !== void 0) body["statusV2"] = parseStatusV2(opts.status);
|
|
124705
|
-
if (opts.budget !== void 0) body["budget"] = toCentAmount(opts.budget);
|
|
124733
|
+
if (opts.budget !== void 0) body["budget"] = toCentAmount(readDisplayNumber(opts.budget, "\u9884\u7B97"));
|
|
124706
124734
|
if (opts.budgetId !== void 0) body["budgetId"] = opts.budgetId.trim();
|
|
124707
124735
|
if (opts.bidding !== void 0) body["biddingStrategyTypeV2"] = opts.bidding.toUpperCase();
|
|
124708
|
-
if (opts.targetCpa !== void 0)
|
|
124709
|
-
|
|
124736
|
+
if (opts.targetCpa !== void 0) {
|
|
124737
|
+
body["targetCpa_BidingAmount"] = toCentAmount(readDisplayNumber(opts.targetCpa, "\u76EE\u6807 CPA"));
|
|
124738
|
+
}
|
|
124739
|
+
if (opts.targetRoas !== void 0) body["targetRoas"] = readDisplayNumber(opts.targetRoas, "\u76EE\u6807 ROAS");
|
|
124710
124740
|
if (opts.urlExpansionOptOut !== void 0) {
|
|
124711
124741
|
body["urlExpansionOptOut"] = opts.urlExpansionOptOut;
|
|
124712
124742
|
}
|
|
@@ -126327,7 +126357,7 @@ function register21(program2) {
|
|
|
126327
126357
|
).requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u6D3B\u52A8 ID").option("--patch-file <path>", "PATCH JSON\uFF08budget/targetCpa \u586B\u5143\uFF09").option(
|
|
126328
126358
|
"--status <status>",
|
|
126329
126359
|
"2|3|4 \u6216 Enabled|Paused|Removed\uFF08Removed \u4E0D\u53EF\u6062\u590D\uFF0C\u987B\u7528\u6237\u540C\u610F\u540E\u52A0 --i-confirm\uFF09"
|
|
126330
|
-
).option("--i-confirm", "\u72B6\u6001\u6539 Removed \u65F6\u5FC5\u586B\uFF1A\u5DF2\u83B7\u7528\u6237\u660E\u786E\u540C\u610F", false).option("--budget <yuan>", "\u65E5\u9884\u7B97\uFF08\u5143\uFF09\uFF1B\u987B\u914D\u5408 --budget-id").option("--budget-id <id>", "budgetId\uFF08\u6765\u81EA pmax-get\uFF09").option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF0C\u5982 MAXIMIZE_CONVERSIONS").option("--target-cpa <yuan>", "\u76EE\u6807 CPA\uFF08\u5143\uFF09").option("--target-roas <n>", "\u76EE\u6807 ROAS").option("--url-expansion-opt-out", "\u5173\u95ED\u6700\u7EC8\u5230\u8FBE\u7F51\u5740\u6269\u5C55").option("-t, --token <token>", "Auth Token")
|
|
126360
|
+
).option("--i-confirm", "\u72B6\u6001\u6539 Removed \u65F6\u5FC5\u586B\uFF1A\u5DF2\u83B7\u7528\u6237\u660E\u786E\u540C\u610F", false).option("--budget <yuan>", "\u65E5\u9884\u7B97\uFF08\u5143\uFF09\uFF1B\u987B\u914D\u5408 --budget-id", parseFloat).option("--budget-id <id>", "budgetId\uFF08\u6765\u81EA pmax-get\uFF09").option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF0C\u5982 MAXIMIZE_CONVERSIONS").option("--target-cpa <yuan>", "\u76EE\u6807 CPA\uFF08\u5143\uFF09", parseFloat).option("--target-roas <n>", "\u76EE\u6807 ROAS", parseFloat).option("--url-expansion-opt-out", "\u5173\u95ED\u6700\u7EC8\u5230\u8FBE\u7F51\u5740\u6269\u5C55").option("-t, --token <token>", "Auth Token")
|
|
126331
126361
|
).action(
|
|
126332
126362
|
async (opts) => {
|
|
126333
126363
|
await runAdPmaxEdit(opts);
|
|
@@ -126595,7 +126625,7 @@ function register21(program2) {
|
|
|
126595
126625
|
parseFloat
|
|
126596
126626
|
).option(
|
|
126597
126627
|
"--target-cpa <n>",
|
|
126598
|
-
"\u7EC4\u7EA7\u76EE\u6807 CPA\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08CLI \u5185\u90E8 \xD7100 \u5199\u5165\u300C\u5206\u300D\u5B57\u6BB5\uFF09",
|
|
126628
|
+
"\u7EC4\u7EA7\u76EE\u6807 CPA\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08CLI \u5185\u90E8 \xD7100 \u5199\u5165\u300C\u5206\u300D\u5B57\u6BB5\uFF1B0 \u6E05\u7A7A\uFF0C\u56DE\u5230\u7CFB\u5217\u51FA\u4EF7\uFF09",
|
|
126599
126629
|
parseFloat
|
|
126600
126630
|
).option("--start <date>", "\u5217\u8868\u67E5\u8BE2\u8D77\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u5217\u8868\u67E5\u8BE2\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
126601
126631
|
async (opts) => {
|
package/dist/skill/_meta.json
CHANGED
|
@@ -120,7 +120,7 @@ siluzan-tso ad adgroup-edit \
|
|
|
120
120
|
[--start/--end <YYYY-MM-DD>]
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
-
`--max-cpc` / `--target-cpa` 与 `ad groups --json-out ./snap` 中 `maxCPCAmountYuan` / `targetCpaAmountYuan` 对齐(**元**,CLI 出口已统一)。列表里的 `0` 多半是未设置。`--target-cpa 0`
|
|
123
|
+
`--max-cpc` / `--target-cpa` 与 `ad groups --json-out ./snap` 中 `maxCPCAmountYuan` / `targetCpaAmountYuan` 对齐(**元**,CLI 出口已统一)。列表里的 `0` 多半是未设置。`--target-cpa 0` 清空组级目标 CPA,回到系列出价。`--max-cpc` 仍须大于 0,广告组不能没有最高 CPC。
|
|
124
124
|
|
|
125
125
|
### 删除
|
|
126
126
|
|
|
@@ -246,6 +246,8 @@ siluzan-tso ad campaign-edit \
|
|
|
246
246
|
| `TARGET_ROAS` | **必填** `--target-roas`(2.5 = 250%) |
|
|
247
247
|
| `MAXIMIZE_CONVERSIONS` | 可选 `--target-cpa`(目标 CPA,元) |
|
|
248
248
|
|
|
249
|
+
`TARGET_CPA` 写到 Google 的「尽可能提高转化次数」并带上目标 CPA。回读 `biddingStrategyTypeV2` 可能是 `MAXIMIZE_CONVERSIONS`,以 `targetCpa_BidingAmount` 是否等于本次金额为准。`TARGET_ROAS` 在目标回报率大于 0 时回读为 `TARGET_ROAS`;旧网关可能仍回 `MAXIMIZE_CONVERSION_VALUE`,同样以 `targetRoas` 为准。
|
|
250
|
+
|
|
249
251
|
示例:
|
|
250
252
|
|
|
251
253
|
```bash
|
|
@@ -262,6 +264,8 @@ siluzan-tso ad campaign-edit -a <accountId> --id <campaignId> \
|
|
|
262
264
|
|
|
263
265
|
`campaign-edit` 的名称、预算、出价、投放网络,以及 `campaign-status`,走字段级 PATCH(`writeScope=search-field-patch`)。请求只带本次传入的字段,没传的字段保持原样。金额仍是主币种元,CLI ×100 写入网关「分」。`--search-network` / `--content-network` 传 `true` 或 `false`,关闭传 `false`,不能传空。`budgetShared=true` 时本命令直接拒绝 `--budget`,不会改共享预算。PMax 不要用本命令。
|
|
264
266
|
|
|
267
|
+
**AI Max:** 不要写系列级 `keyword_match_type`(AI Max 开启后 Google 会拒)。改单条关键词匹配类型仍用关键词命令。列表/判断渠道类型用 `channelTypeV2`,不要用旧 `channelType`。
|
|
268
|
+
|
|
265
269
|
网关还支持开始/结束时间、地区类型、地区/语言/时段/否定 IP/设备的整表替换,以及动态搜索广告域名。CLI 还没有这些参数,不要自己拼 PUT 或 PATCH。
|
|
266
270
|
|
|
267
271
|
写完会再 GET:`verification=verified` 才表示对上了本次字段;没改预算但回读预算变了则是 `partial`;读不到是 `unknown`(再查 `ad campaigns`,不要当成没改成,也不要立刻重发)。请求失败时会再 GET 一次预算:金额相对提交前变了是 `partial`(退出码 0),读不到或无法对比是 `unknown`(退出码 0),都不要立刻重发;金额没变才是失败(退出码 1)。
|
|
@@ -359,7 +363,7 @@ siluzan-tso ad keyword-edit \
|
|
|
359
363
|
[--max-cpc <n>] [--final-url <url>] [--status Enabled|Paused]
|
|
360
364
|
```
|
|
361
365
|
|
|
362
|
-
传 `--match-type` 时 CLI 自动规范 `keywordText` 括号/引号格式。至少传一项。`--max-cpc` 为主币种元(CLI ×100 写入 `maxCpc`「分」字段,与 `adgroup-edit --max-cpc` 同口径)。`ad keywords --json-out ./snap` 出价见 `maxCPCYuan`。列表里的 `0`
|
|
366
|
+
传 `--match-type` 时 CLI 自动规范 `keywordText` 括号/引号格式。至少传一项。`--max-cpc` 为主币种元(CLI ×100 写入 `maxCpc`「分」字段,与 `adgroup-edit --max-cpc` 同口径)。`ad keywords --json-out ./snap` 出价见 `maxCPCYuan`。列表里的 `0` 多半是未设置。`--max-cpc 0` 清空关键词出价,回到广告组出价;不要用它表示「写成 0 元」。`--status` 写入 `userStatus`(关键词级开关,非系列的 `status`)。
|
|
363
367
|
|
|
364
368
|
---
|
|
365
369
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
| `ad pmax-validate` | 本地校验 |
|
|
19
19
|
| `ad pmax-create` | 创建系列(同步返回 `campaignId` 等;失败时把已建成编号写回 JSON 再跑) |
|
|
20
20
|
| `ad pmax-channel-types` | 渠道类型列表 |
|
|
21
|
-
| `ad pmax-get` | 系列详情(含 `brandAssets[]
|
|
21
|
+
| `ad pmax-get` | 系列详情(含 `brandAssets[]`;`negativeGenderExclusions` / `negativeKeywordExclusions` / `negativeAgeExclusions`;PATCH 可整表替换,未传不改;`--json-out` 附加 `_brandGuidelinesActive`、`_agentBrandHint`) |
|
|
22
22
|
| `ad pmax-edit` | 编辑系列(预算/出价/状态/`assetAutomationSettings`/`textGuidelines`;**不可**改 `brandGuidelinesEnabled`)。图片增强/提取只改提交的类型;`textGuidelines` 未传不写,传了整段替换,传 `{}` 清空 |
|
|
23
23
|
| `ad pmax-brand-assets-edit` | BG 已开启时改 Campaign 级品牌(商家名/Logo/样式) |
|
|
24
24
|
| `ad pmax-brand-guidelines-enable` | 存量活动启用 BG(不可关闭) |
|
|
@@ -370,6 +370,7 @@ AI Max for Search 是 Google 在 Search 系列中集成的 AI 优化功能包:
|
|
|
370
370
|
- `[UI 操作]` **品牌设置(Brand Settings):** 控制 AI 如何使用品牌名称
|
|
371
371
|
- `[UI 操作]` **网址排除(URL Exclusions):** 排除不想作为着陆页的页面(如博客、关于我们)
|
|
372
372
|
- `[UI 操作]` **网址规则(URL Rules):** 限定 AI 只能在特定目录下选择着陆页
|
|
373
|
+
- **勿写系列级匹配类型:** AI Max 开启后不要设置 `Campaign.keyword_match_type`(会被 Google 拒)。可继续改**广告组内单条关键词**的匹配类型。网关 Search PATCH 当前也不写该系列级字段;以后若加写,须先判断 `enable_ai_max`。
|
|
373
374
|
|
|
374
375
|
### 10.4 与 PMax 的交互
|
|
375
376
|
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.
|
|
12
|
+
$PKG_VERSION = '1.1.62-beta.1'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.
|
|
12
|
+
readonly PKG_VERSION="1.1.62-beta.1"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|