siluzan-tso-cli 1.1.60-beta.3 → 1.1.61-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 +116 -2
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/pmax-patch-campaign-template.json +1 -1
- package/dist/skill/references/analytics/account-analytics.md +2 -0
- package/dist/skill/references/core/playbooks.md +1 -1
- package/dist/skill/references/google-ads/google-ads-write.md +3 -3
- package/dist/skill/references/google-ads/pmax-api.md +4 -4
- package/dist/skill/references/report-templates/google-period-report-excel.md +46 -1
- package/dist/skill/references/report-templates/google-period-report.md +1 -1
- package/dist/skill/report-templates/google-period-report-excel.md +46 -1
- package/dist/skill/report-templates/google-period-report.md +1 -1
- 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.61-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -122720,6 +122720,16 @@ function pmaxAssetGroupReportUrl(googleApiUrl, accountId, query) {
|
|
|
122720
122720
|
const qs = query.toString();
|
|
122721
122721
|
return `${base}/reporting/media-account/${accountId}/pmax/asset-groups/reports${qs ? `?${qs}` : ""}`;
|
|
122722
122722
|
}
|
|
122723
|
+
function pmaxAssetReportUrl(googleApiUrl, accountId, query) {
|
|
122724
|
+
const base = googleApiUrl.replace(/\/$/, "");
|
|
122725
|
+
const qs = query.toString();
|
|
122726
|
+
return `${base}/reporting/media-account/${accountId}/pmax/asset-groups/reports/assets${qs ? `?${qs}` : ""}`;
|
|
122727
|
+
}
|
|
122728
|
+
function pmaxChannelReportUrl(googleApiUrl, accountId, query) {
|
|
122729
|
+
const base = googleApiUrl.replace(/\/$/, "");
|
|
122730
|
+
const qs = query.toString();
|
|
122731
|
+
return `${base}/reporting/media-account/${accountId}/pmax/campaigns/reports/channels${qs ? `?${qs}` : ""}`;
|
|
122732
|
+
}
|
|
122723
122733
|
function pmaxGeoReportUrl(googleApiUrl, accountId, query) {
|
|
122724
122734
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
122725
122735
|
const qs = query.toString();
|
|
@@ -125376,6 +125386,80 @@ PMax \u8D44\u4EA7\u7EC4\u6548\u679C\u62A5\u8868\uFF08${query.get("startDate")} ~
|
|
|
125376
125386
|
console.log(" \u5B8C\u6574\u6570\u636E\u8BF7\u4F7F\u7528 --json-out\n");
|
|
125377
125387
|
});
|
|
125378
125388
|
}
|
|
125389
|
+
async function runAdPmaxReportAssets(opts) {
|
|
125390
|
+
const accountId = requireAccountId(opts.account);
|
|
125391
|
+
const query = buildReportQuery(opts);
|
|
125392
|
+
await withGoogleApi(opts, async (config, googleApiUrl) => {
|
|
125393
|
+
const url = pmaxAssetReportUrl(googleApiUrl, accountId, query);
|
|
125394
|
+
let data;
|
|
125395
|
+
try {
|
|
125396
|
+
const raw = await pmaxApiFetch(url, config, {}, opts.verbose);
|
|
125397
|
+
data = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : { data: raw };
|
|
125398
|
+
} catch (err) {
|
|
125399
|
+
console.error(
|
|
125400
|
+
`
|
|
125401
|
+
\u274C \u83B7\u53D6 PMax \u7D20\u6750\u62A5\u8868\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
125402
|
+
`
|
|
125403
|
+
);
|
|
125404
|
+
process.exit(1);
|
|
125405
|
+
}
|
|
125406
|
+
if (await emitPmaxResult(
|
|
125407
|
+
{ ...opts, account: accountId },
|
|
125408
|
+
`ad-pmax-report-assets-${accountId}`,
|
|
125409
|
+
"ad pmax-report-assets",
|
|
125410
|
+
data,
|
|
125411
|
+
accountId
|
|
125412
|
+
)) {
|
|
125413
|
+
return;
|
|
125414
|
+
}
|
|
125415
|
+
const assets = data["assets"];
|
|
125416
|
+
const n = Array.isArray(assets) ? assets.length : 0;
|
|
125417
|
+
console.log(
|
|
125418
|
+
`
|
|
125419
|
+
PMax \u7D20\u6750\u62A5\u8868\uFF08${query.get("startDate")} ~ ${query.get("endDate")}\uFF0C${n} \u6761\u7D20\u6750\uFF09
|
|
125420
|
+
`
|
|
125421
|
+
);
|
|
125422
|
+
console.log(" \u6BD4\u7387\u6309\u672C\u8868\u5408\u8BA1\u3002\u4E0E\u7D20\u6750\u7EC4\u82B1\u8D39/\u70B9\u51FB\u4E0D\u5FC5\u76F8\u7B49\u3002\u7D20\u6750\u70B9\u51FB\u53EF\u5927\u4E8E\u7CFB\u5217\u70B9\u51FB\u3002");
|
|
125423
|
+
console.log(" \u5B8C\u6574\u6570\u636E\u8BF7\u4F7F\u7528 --json-out\n");
|
|
125424
|
+
});
|
|
125425
|
+
}
|
|
125426
|
+
async function runAdPmaxReportChannels(opts) {
|
|
125427
|
+
const accountId = requireAccountId(opts.account);
|
|
125428
|
+
const query = buildReportQuery(opts);
|
|
125429
|
+
await withGoogleApi(opts, async (config, googleApiUrl) => {
|
|
125430
|
+
const url = pmaxChannelReportUrl(googleApiUrl, accountId, query);
|
|
125431
|
+
let data;
|
|
125432
|
+
try {
|
|
125433
|
+
const raw = await pmaxApiFetch(url, config, {}, opts.verbose);
|
|
125434
|
+
data = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : { data: raw };
|
|
125435
|
+
} catch (err) {
|
|
125436
|
+
console.error(
|
|
125437
|
+
`
|
|
125438
|
+
\u274C \u83B7\u53D6 PMax \u6E20\u9053\u62A5\u8868\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
125439
|
+
`
|
|
125440
|
+
);
|
|
125441
|
+
process.exit(1);
|
|
125442
|
+
}
|
|
125443
|
+
if (await emitPmaxResult(
|
|
125444
|
+
{ ...opts, account: accountId },
|
|
125445
|
+
`ad-pmax-report-channels-${accountId}`,
|
|
125446
|
+
"ad pmax-report-channels",
|
|
125447
|
+
data,
|
|
125448
|
+
accountId
|
|
125449
|
+
)) {
|
|
125450
|
+
return;
|
|
125451
|
+
}
|
|
125452
|
+
const campaigns = data["campaigns"];
|
|
125453
|
+
const n = Array.isArray(campaigns) ? campaigns.length : 0;
|
|
125454
|
+
console.log(
|
|
125455
|
+
`
|
|
125456
|
+
PMax \u6E20\u9053\u62A5\u8868\uFF08${query.get("startDate")} ~ ${query.get("endDate")}\uFF0C${n} \u4E2A\u7CFB\u5217\uFF09
|
|
125457
|
+
`
|
|
125458
|
+
);
|
|
125459
|
+
console.log(" \u5408\u8BA1\u53EA\u542B\u5404\u7F51\u7EDC\u4E4B\u548C\u3002\u89C6\u9891\u3001\u5546\u54C1\u662F\u5BF9\u7167\uFF0C\u4E0D\u52A0\u5165\u5408\u8BA1\u3002");
|
|
125460
|
+
console.log(" \u5B8C\u6574\u6570\u636E\u8BF7\u4F7F\u7528 --json-out\n");
|
|
125461
|
+
});
|
|
125462
|
+
}
|
|
125379
125463
|
async function runAdPmaxReportGeo(opts) {
|
|
125380
125464
|
const accountId = requireAccountId(opts.account);
|
|
125381
125465
|
const query = buildReportQuery(opts);
|
|
@@ -126239,7 +126323,7 @@ function register21(program2) {
|
|
|
126239
126323
|
);
|
|
126240
126324
|
addPmaxJsonOptions(
|
|
126241
126325
|
adCmd.command("pmax-edit").description(
|
|
126242
|
-
"\u66F4\u65B0 PMax \u6D3B\u52A8\uFF08PATCH\uFF1B\u52FF\u7528 ad campaign-edit\uFF09\n --patch-file \u89C1 assets/pmax-patch-campaign-template.json"
|
|
126326
|
+
"\u66F4\u65B0 PMax \u6D3B\u52A8\uFF08PATCH\uFF1B\u52FF\u7528 ad campaign-edit\uFF09\n --patch-file \u89C1 assets/pmax-patch-campaign-template.json\uFF1BassetAutomationSettings \u53EA\u6539\u63D0\u4EA4\u7684\u7C7B\u578B"
|
|
126243
126327
|
).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(
|
|
126244
126328
|
"--status <status>",
|
|
126245
126329
|
"2|3|4 \u6216 Enabled|Paused|Removed\uFF08Removed \u4E0D\u53EF\u6062\u590D\uFF0C\u987B\u7528\u6237\u540C\u610F\u540E\u52A0 --i-confirm\uFF09"
|
|
@@ -126325,7 +126409,7 @@ function register21(program2) {
|
|
|
126325
126409
|
}
|
|
126326
126410
|
);
|
|
126327
126411
|
addPmaxJsonOptions(
|
|
126328
|
-
adCmd.command("pmax-signals-set").description("\u5168\u91CF\u540C\u6B65\u8D44\u4EA7\u7EC4\u4FE1\u53F7\uFF08PUT .../signals\uFF1B\
|
|
126412
|
+
adCmd.command("pmax-signals-set").description("\u5168\u91CF\u540C\u6B65\u8D44\u4EA7\u7EC4\u4FE1\u53F7\uFF08PUT .../signals\uFF1B\u4E24\u7C7B\u90FD\u7A7A\u4E14\u7EC4\u91CC\u8FD8\u6709\u4FE1\u53F7\u4F1A 400\uFF09").requiredOption("--config-file <path>", "JSON \u914D\u7F6E\u8DEF\u5F84").option("-t, --token <token>", "Auth Token")
|
|
126329
126413
|
).action(
|
|
126330
126414
|
async (opts) => {
|
|
126331
126415
|
await runAdPmaxSignalsSet(opts);
|
|
@@ -126389,6 +126473,36 @@ function register21(program2) {
|
|
|
126389
126473
|
});
|
|
126390
126474
|
}
|
|
126391
126475
|
);
|
|
126476
|
+
pmaxReportOpts(
|
|
126477
|
+
adCmd.command("pmax-report-assets").description("PMax \u5355\u7D20\u6750\u62A5\u8868\uFF08GET .../pmax/asset-groups/reports/assets\uFF09")
|
|
126478
|
+
).action(
|
|
126479
|
+
async (opts) => {
|
|
126480
|
+
await runAdPmaxReportAssets({
|
|
126481
|
+
account: opts.account,
|
|
126482
|
+
startDate: opts.start,
|
|
126483
|
+
endDate: opts.end,
|
|
126484
|
+
campaignId: opts.campaignId,
|
|
126485
|
+
token: opts.token,
|
|
126486
|
+
jsonOut: opts.jsonOut,
|
|
126487
|
+
verbose: opts.verbose
|
|
126488
|
+
});
|
|
126489
|
+
}
|
|
126490
|
+
);
|
|
126491
|
+
pmaxReportOpts(
|
|
126492
|
+
adCmd.command("pmax-report-channels").description("PMax \u6E20\u9053\u62A5\u8868\uFF08GET .../pmax/campaigns/reports/channels\uFF09")
|
|
126493
|
+
).action(
|
|
126494
|
+
async (opts) => {
|
|
126495
|
+
await runAdPmaxReportChannels({
|
|
126496
|
+
account: opts.account,
|
|
126497
|
+
startDate: opts.start,
|
|
126498
|
+
endDate: opts.end,
|
|
126499
|
+
campaignId: opts.campaignId,
|
|
126500
|
+
token: opts.token,
|
|
126501
|
+
jsonOut: opts.jsonOut,
|
|
126502
|
+
verbose: opts.verbose
|
|
126503
|
+
});
|
|
126504
|
+
}
|
|
126505
|
+
);
|
|
126392
126506
|
pmaxReportOpts(
|
|
126393
126507
|
adCmd.command("pmax-report-geo").description("PMax \u5730\u7406\u62A5\u8868 \u6D3B\u52A8\xD7\u56FD\u5BB6\uFF08GET .../pmax/campaigns/reports/geo\uFF09").option("--cost-greater <n>", "\u82B1\u8D39\u8FC7\u6EE4", (v) => parseFloat(v)).option("--click-greater <n>", "\u70B9\u51FB\u8FC7\u6EE4", (v) => parseFloat(v)).option("--conversions-greater <n>", "\u8F6C\u5316\u8FC7\u6EE4", (v) => parseFloat(v))
|
|
126394
126508
|
).action(
|
package/dist/skill/_meta.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "PATCH 活动;budget/targetCpa 填主币种元,CLI 自动 ×100",
|
|
2
|
+
"_comment": "PATCH 活动;budget/targetCpa 填主币种元,CLI 自动 ×100。assetAutomationSettings 只改提交的类型,例如 GENERATE_IMAGE_ENHANCEMENT / GENERATE_IMAGE_EXTRACTION(OPTED_IN 或 OPTED_OUT)。未提交不写,避免把默认增强关掉",
|
|
3
3
|
"id": "12345678901",
|
|
4
4
|
"budgetId": "111222333",
|
|
5
5
|
"budget": 5.5,
|
|
@@ -214,6 +214,8 @@ const data = d.record ?? d.items; // record 非空=汇总维度;否则=列表
|
|
|
214
214
|
|
|
215
215
|
`items[]` 每行额外包含:`conversionsValue`、`conversionsValuePerCost`(`spend ≤ 0` 时为 0)、`campaignTargetCpaYuan`、`maximizeConversionsTargetCpaYuan`、`manualCpcEnhancedCpcEnabled`、`percentCpcEnhancedCpcEnabled`。所有金额字段(`*Yuan` 后缀)已统一为元,可直接展示,无需换算。
|
|
216
216
|
|
|
217
|
+
账户级转化价值 / 单转化价值 / ROAS 只对 `items[]` 汇总:`Σ conversionsValue`、`Σ conversionsValue / Σ conversions`、`Σ conversionsValue / Σ spend`。禁止对行上 `conversionsValuePerCost` 再平均。`overview` 的 `currentPeriod` / `previousPeriod` **没有** `conversionsValue`。上期这三项另拉等长上一周期的 `campaigns` 再同样汇总(窗口见 `report-templates/google-period-report-excel.md`),禁止留空或用本期估算。
|
|
218
|
+
|
|
217
219
|
| 字段 | 含义 |
|
|
218
220
|
| ------------------------------------- | ------------------------------------------------ |
|
|
219
221
|
| `campaignStatus` / `campaignStatusV2` | 网关原始枚举(`Enabled` / `Paused` / `Removed`) |
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
- **步骤**:
|
|
82
82
|
1. **账户核验**:`list-accounts -m Google -k <mediaCustomerId> --json-out <dir>`;无记录则停止并告知用户。
|
|
83
83
|
2. 确认时间范围;区间 > 3 个月时分段(季度/月)。
|
|
84
|
-
3. **拉数**:用户已指定 Sheet/维度 → 只拉对应 `--sections`(见 `google-period-report-excel.md` 映射表);未指定 → 按 `google-period-report.md` 默认 9 个拉数维(含 `audience`、`negative-keywords
|
|
84
|
+
3. **拉数**:用户已指定 Sheet/维度 → 只拉对应 `--sections`(见 `google-period-report-excel.md` 映射表);未指定 → 按 `google-period-report.md` 默认 9 个拉数维(含 `audience`、`negative-keywords`),并可并行追问可选追加。终稿要「转化价值 / 单转化价值 / ROAS」的上期时,再按 excel 规格拉等长上期 `--sections campaigns` 后汇总,禁止把这三格留成「—」。
|
|
85
85
|
4. **门禁**:对每个 section Read `<section>-<accountId>_*.outline.txt` 后再写脚本。
|
|
86
86
|
5. 脚本读盘写 `google-period-report.json`(`meta` + `narrative`,`meta.lang` 跟本轮语言);用户要 **Excel** → Agent 脚本写 xlsx(**禁止**宿主第三方 xlsx Skill;**无** CLI excel 子命令;表头跟 `meta.lang`)。
|
|
87
87
|
6. 默认 HTML:`google-analysis render --data ./google-period-report.json --snapshot-dir ./snap-google --out ./google-period-report.html --lang <zh|en>`。须含账户概览、投放趋势、Top 关键词/系列/地区/受众分布、当前否词名单、优化建议。
|
|
@@ -84,18 +84,18 @@
|
|
|
84
84
|
| 能力 | 命令 |
|
|
85
85
|
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
86
86
|
| 详情 | `ad pmax-get -a <id> --campaign-id <cid>`(读 `_brandGuidelinesActive`) |
|
|
87
|
-
| 改活动 | `ad pmax-edit`(`--patch-file` 或 `--status` / `--budget` + `--budget-id
|
|
87
|
+
| 改活动 | `ad pmax-edit`(`--patch-file` 或 `--status` / `--budget` + `--budget-id`;`assetAutomationSettings` 只改提交类型,如图片增强/提取;改 `Removed` 须用户同意 + `--i-confirm`) |
|
|
88
88
|
| 改 Campaign 品牌 | `ad pmax-brand-assets-edit`(BG 已开启) |
|
|
89
89
|
| 启用 BG | `ad pmax-brand-guidelines-enable --config-file …`(存量活动) |
|
|
90
90
|
| 新资产组 | `ad pmax-asset-group-create --config-file …`(BG 下自动省略品牌) |
|
|
91
91
|
| 改资产组 | `ad pmax-asset-group-edit` |
|
|
92
|
-
| 删资产组 | `ad pmax-asset-group-edit --status REMOVED`(软删;网关无 DELETE
|
|
92
|
+
| 删资产组 | `ad pmax-asset-group-edit --status REMOVED`(软删;网关无 DELETE 端点。最后一组会 400,应暂停该组或系列) |
|
|
93
93
|
| 改资产 | `ad pmax-assets-update --config-file …` |
|
|
94
94
|
| YouTube 追加 | `ad pmax-youtube-link`(单条 `--youtube` / `--video-path`);批量见 `ad pmax-assets-update` |
|
|
95
95
|
| 信号 | `ad pmax-signals-get` / `ad pmax-signals-set`;受众下拉 `ad pmax-audiences` |
|
|
96
96
|
| 附加资产 | `ad extension pmax-types`;`callout` / `snippet` / `lead-form` / `whatsapp`(见 `pmax-api.md` § 附加资产) |
|
|
97
97
|
| 图片库 | `ad pmax-image-upload` |
|
|
98
|
-
| 报表 | `ad pmax-report-asset-groups` / `ad pmax-report-geo`
|
|
98
|
+
| 报表 | `ad pmax-report-asset-groups` / `ad pmax-report-assets` / `ad pmax-report-geo` / `ad pmax-report-channels`(单素材与素材组不必相等;素材点击可大于系列点击;渠道合计只含各网络) |
|
|
99
99
|
| 删活动 | 用户同意后 `ad campaign-delete -a <id> --id <campaignId> --i-confirm --commit "…"`(与 Search 共用;勿用 `ad campaign-edit`) |
|
|
100
100
|
|
|
101
101
|
模板与 HTTP 对照:`references/google-ads/pmax-api.md`。
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
| `ad pmax-create` | 创建系列(同步返回 `campaignId` 等;失败时把已建成编号写回 JSON 再跑) |
|
|
20
20
|
| `ad pmax-channel-types` | 渠道类型列表 |
|
|
21
21
|
| `ad pmax-get` | 系列详情(含 `brandAssets[]`;`--json-out` 附加 `_brandGuidelinesActive`、`_agentBrandHint`) |
|
|
22
|
-
| `ad pmax-edit` |
|
|
22
|
+
| `ad pmax-edit` | 编辑系列(预算/出价/状态/`assetAutomationSettings`;**不可**改 `brandGuidelinesEnabled`)。图片增强/提取只改提交的类型,不进创建默认值 |
|
|
23
23
|
| `ad pmax-brand-assets-edit` | BG 已开启时改 Campaign 级品牌(商家名/Logo/样式) |
|
|
24
24
|
| `ad pmax-brand-guidelines-enable` | 存量活动启用 BG(不可关闭) |
|
|
25
25
|
| `ad pmax-asset-group-create` | 新建资产组 |
|
|
26
26
|
| `ad pmax-asset-group-edit` | 编辑资产组 |
|
|
27
27
|
| `ad pmax-assets-update` | 更新资产 |
|
|
28
28
|
| `ad pmax-youtube-link` | **追加**单条 YouTube 视频(不替换已有视频) |
|
|
29
|
-
| `ad pmax-signals-get` / `ad pmax-signals-set` | 读/写信号(**全量** PUT)
|
|
29
|
+
| `ad pmax-signals-get` / `ad pmax-signals-set` | 读/写信号(**全量** PUT。两类都空且组里还有信号会 400) |
|
|
30
30
|
| `ad pmax-audiences` | 受众列表 |
|
|
31
31
|
| `ad pmax-image-upload` | 单张图片上传 |
|
|
32
|
-
| `ad pmax-report-asset-groups` / `ad pmax-report-geo`
|
|
32
|
+
| `ad pmax-report-asset-groups` / `ad pmax-report-assets` / `ad pmax-report-geo` / `ad pmax-report-channels` | 报表(素材组 / 单素材 / 地理 / 渠道)。单素材与素材组花费/点击不必相等;素材点击可大于系列点击。渠道表的 `total` 只等于各 `channels` 之和;`video` / `product` 是对照,不要再加进合计 |
|
|
33
33
|
| `ad campaigns` | 列表(筛 `PERFORMANCE_MAX`) |
|
|
34
34
|
| `ad extension pmax-types` | PMax 支持的附加资产类型与层级 |
|
|
35
35
|
| `ad extension callout` / `snippet` / `lead-form` / `whatsapp` | 宣传信息 / 结构化摘要 / 潜在客户表单 / WhatsApp |
|
|
@@ -202,7 +202,7 @@ Google v21+ 新建 PMax **默认开启** BG:`businessName` / Logo 挂在 **Cam
|
|
|
202
202
|
## 删除
|
|
203
203
|
|
|
204
204
|
- **系列**:用户同意后 `ad campaign-delete -a <id> --id <campaignId> --i-confirm --commit "…"`(`ad pmax-edit --status Removed` 同样须 `--i-confirm`)
|
|
205
|
-
- **资产组**:`ad pmax-asset-group-edit --status REMOVED
|
|
205
|
+
- **资产组**:`ad pmax-asset-group-edit --status REMOVED`(最后一组会 400,应暂停该组或系列)
|
|
206
206
|
- **资产**:`ad pmax-assets-update` 的 `unlink`(见模板)
|
|
207
207
|
|
|
208
208
|
---
|
|
@@ -65,7 +65,7 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
65
65
|
|
|
66
66
|
| 维度 | ❌ 禁止猜 | ✅ outline 真实字段 |
|
|
67
67
|
| ----------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
68
|
-
| `overview` | `currentPeriod.activeDays`、`previousPeriod.activeDays`、`currentPeriod.averageDailyCost` | `record.activeDays`、`record.averageDailyCost`(只在 **record
|
|
68
|
+
| `overview` | `currentPeriod.activeDays`、`previousPeriod.activeDays`、`currentPeriod.averageDailyCost`、`*.conversionsValue` | `record.activeDays`、`record.averageDailyCost`(只在 **record 根**。上期活跃天数另拉上期 `daily-metrics` 数 `spend>0` 天数)。period 块没有转化价值,见「转化价值环比」 |
|
|
69
69
|
| `keywords` | `keywordText`、`status`、`matchType`(单独作展示列) | `keyword`、`userStatus`、`keywordMatchTypeZh`(或 `keywordMatchType`) |
|
|
70
70
|
| `search-terms` | `query` | `searchTermText`;匹配类型用 `matchTypeZh`;状态用 `queryTargetingStatusZh` |
|
|
71
71
|
| `geographic` | `geoName`、`countryCriterionIdName` | `countryOrRegion`、`countryNameZh`、`countryCode` |
|
|
@@ -78,6 +78,50 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
81
|
+
## 转化价值环比(核心指标必做)
|
|
82
|
+
|
|
83
|
+
`overview.currentPeriod` / `previousPeriod` **没有** `conversionsValue`。账户级「转化价值 / 单转化价值 / ROAS」只从 **`campaigns` 的 `items[]`** 汇总。消耗、点击、转化次数、CTR、CPC、CPA 的环比仍读 overview 的 `previousPeriod`。
|
|
84
|
+
|
|
85
|
+
终稿核心指标(或等价的本期 vs 上期表)出现这三行时,**必须**再拉等长上期的 `campaigns`,两期用同一公式。上期这三格禁止写成「—」,也禁止用本期去估。
|
|
86
|
+
|
|
87
|
+
**上期窗口**(与 Web `calcPrePeriodTimeRange` 相同,含首尾):
|
|
88
|
+
|
|
89
|
+
- 本期天数 `N = end − start + 1`(日历日)
|
|
90
|
+
- 上期结束 = 本期开始的前一天;上期开始 = 上期结束再往前 `N − 1` 天
|
|
91
|
+
- 例:本期 `2026-10-16` ~ `2026-10-28`(13 天)→ 上期 `2026-10-03` ~ `2026-10-15`
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
mkdir -p ./snap-p4-prev
|
|
95
|
+
siluzan-tso google-analysis -a <id> --start <prevStart> --end <prevEnd> \
|
|
96
|
+
--sections campaigns --json-out ./snap-p4-prev
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
落盘后先 Read 上期 `campaigns-*.outline.txt`,再在脚本里读 `items[]`:
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const sum = (rows, key) => rows.reduce((a, r) => a + (Number(r[key]) || 0), 0);
|
|
103
|
+
function valueKpis(items) {
|
|
104
|
+
const value = sum(items, "conversionsValue");
|
|
105
|
+
const conversions = sum(items, "conversions");
|
|
106
|
+
const spend = sum(items, "spend");
|
|
107
|
+
return {
|
|
108
|
+
conversionsValue: value,
|
|
109
|
+
// 单转化价值;转化次数为 0 时单元格写「—」
|
|
110
|
+
valuePerConversion: conversions > 0 ? value / conversions : null,
|
|
111
|
+
// ROAS;花费为 0 时单元格写「—」
|
|
112
|
+
roas: spend > 0 ? value / spend : null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
禁止对行上的 `conversionsValuePerCost` 再平均(那是行级「转化价值/费用」,不是账户 ROAS)。
|
|
118
|
+
|
|
119
|
+
关键词、搜索词、设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」,禁止把系列转化价值摊进去。上期 `campaigns` 拉数失败时,这三格写明原因,不要留空。
|
|
120
|
+
|
|
121
|
+
英文终稿表头:转化价值 → Conversion value,单转化价值 → Value / conversion,ROAS 保持 ROAS。
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
81
125
|
## 禁止的数据探查方式
|
|
82
126
|
|
|
83
127
|
写 Excel 脚本**之前**,不得用以下方式「预览」业务 JSON(与 `agent-conventions.md`、`tips.md` 一致):
|
|
@@ -115,6 +159,7 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
115
159
|
- [ ] 脚本 stdout 打印的 `itemCount` 与 Excel 数据行数一致(±合计行)
|
|
116
160
|
- [ ] 全部 ID 列为文本(非数字类型 / 无科学计数法)
|
|
117
161
|
- [ ] 未使用第三方 xlsx Skill 替代本 Skill 拉数与字段口径
|
|
162
|
+
- [ ] 核心指标若有转化价值 / 单转化价值 / ROAS:上期来自等长区间的 `campaigns` 汇总,不是 overview,也不是「—」
|
|
118
163
|
|
|
119
164
|
---
|
|
120
165
|
|
|
@@ -49,7 +49,7 @@ siluzan-tso google-analysis render \
|
|
|
49
49
|
**Excel 分支**(用户明确要 xlsx 时):
|
|
50
50
|
|
|
51
51
|
1. 步骤 1~2 与 HTML 流程相同(拉数 → 分析)。
|
|
52
|
-
2. 改为 Agent 执行 node/python 脚本按 `google-period-report-excel.md` 写出 `.xlsx`(先读齐 `*.outline.txt
|
|
52
|
+
2. 改为 Agent 执行 node/python 脚本按 `google-period-report-excel.md` 写出 `.xlsx`(先读齐 `*.outline.txt`)。核心指标的上期转化价值 / 单转化价值 / ROAS 按该文「转化价值环比」再拉等长上期 `campaigns` 后汇总。
|
|
53
53
|
3. **不要**调用 `google-analysis render`(除非用户同时要 HTML + Excel)。
|
|
54
54
|
4. **禁止**假设存在 `siluzan-tso … excel` 子命令。
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
65
65
|
|
|
66
66
|
| 维度 | ❌ 禁止猜 | ✅ outline 真实字段 |
|
|
67
67
|
| ----------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
68
|
-
| `overview` | `currentPeriod.activeDays`、`previousPeriod.activeDays`、`currentPeriod.averageDailyCost` | `record.activeDays`、`record.averageDailyCost`(只在 **record
|
|
68
|
+
| `overview` | `currentPeriod.activeDays`、`previousPeriod.activeDays`、`currentPeriod.averageDailyCost`、`*.conversionsValue` | `record.activeDays`、`record.averageDailyCost`(只在 **record 根**。上期活跃天数另拉上期 `daily-metrics` 数 `spend>0` 天数)。period 块没有转化价值,见「转化价值环比」 |
|
|
69
69
|
| `keywords` | `keywordText`、`status`、`matchType`(单独作展示列) | `keyword`、`userStatus`、`keywordMatchTypeZh`(或 `keywordMatchType`) |
|
|
70
70
|
| `search-terms` | `query` | `searchTermText`;匹配类型用 `matchTypeZh`;状态用 `queryTargetingStatusZh` |
|
|
71
71
|
| `geographic` | `geoName`、`countryCriterionIdName` | `countryOrRegion`、`countryNameZh`、`countryCode` |
|
|
@@ -78,6 +78,50 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
81
|
+
## 转化价值环比(核心指标必做)
|
|
82
|
+
|
|
83
|
+
`overview.currentPeriod` / `previousPeriod` **没有** `conversionsValue`。账户级「转化价值 / 单转化价值 / ROAS」只从 **`campaigns` 的 `items[]`** 汇总。消耗、点击、转化次数、CTR、CPC、CPA 的环比仍读 overview 的 `previousPeriod`。
|
|
84
|
+
|
|
85
|
+
终稿核心指标(或等价的本期 vs 上期表)出现这三行时,**必须**再拉等长上期的 `campaigns`,两期用同一公式。上期这三格禁止写成「—」,也禁止用本期去估。
|
|
86
|
+
|
|
87
|
+
**上期窗口**(与 Web `calcPrePeriodTimeRange` 相同,含首尾):
|
|
88
|
+
|
|
89
|
+
- 本期天数 `N = end − start + 1`(日历日)
|
|
90
|
+
- 上期结束 = 本期开始的前一天;上期开始 = 上期结束再往前 `N − 1` 天
|
|
91
|
+
- 例:本期 `2026-10-16` ~ `2026-10-28`(13 天)→ 上期 `2026-10-03` ~ `2026-10-15`
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
mkdir -p ./snap-p4-prev
|
|
95
|
+
siluzan-tso google-analysis -a <id> --start <prevStart> --end <prevEnd> \
|
|
96
|
+
--sections campaigns --json-out ./snap-p4-prev
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
落盘后先 Read 上期 `campaigns-*.outline.txt`,再在脚本里读 `items[]`:
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const sum = (rows, key) => rows.reduce((a, r) => a + (Number(r[key]) || 0), 0);
|
|
103
|
+
function valueKpis(items) {
|
|
104
|
+
const value = sum(items, "conversionsValue");
|
|
105
|
+
const conversions = sum(items, "conversions");
|
|
106
|
+
const spend = sum(items, "spend");
|
|
107
|
+
return {
|
|
108
|
+
conversionsValue: value,
|
|
109
|
+
// 单转化价值;转化次数为 0 时单元格写「—」
|
|
110
|
+
valuePerConversion: conversions > 0 ? value / conversions : null,
|
|
111
|
+
// ROAS;花费为 0 时单元格写「—」
|
|
112
|
+
roas: spend > 0 ? value / spend : null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
禁止对行上的 `conversionsValuePerCost` 再平均(那是行级「转化价值/费用」,不是账户 ROAS)。
|
|
118
|
+
|
|
119
|
+
关键词、搜索词、设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」,禁止把系列转化价值摊进去。上期 `campaigns` 拉数失败时,这三格写明原因,不要留空。
|
|
120
|
+
|
|
121
|
+
英文终稿表头:转化价值 → Conversion value,单转化价值 → Value / conversion,ROAS 保持 ROAS。
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
81
125
|
## 禁止的数据探查方式
|
|
82
126
|
|
|
83
127
|
写 Excel 脚本**之前**,不得用以下方式「预览」业务 JSON(与 `agent-conventions.md`、`tips.md` 一致):
|
|
@@ -115,6 +159,7 @@ siluzan-tso google-analysis -a <id> --start <S> --end <E> --json-out ./snap-p4 \
|
|
|
115
159
|
- [ ] 脚本 stdout 打印的 `itemCount` 与 Excel 数据行数一致(±合计行)
|
|
116
160
|
- [ ] 全部 ID 列为文本(非数字类型 / 无科学计数法)
|
|
117
161
|
- [ ] 未使用第三方 xlsx Skill 替代本 Skill 拉数与字段口径
|
|
162
|
+
- [ ] 核心指标若有转化价值 / 单转化价值 / ROAS:上期来自等长区间的 `campaigns` 汇总,不是 overview,也不是「—」
|
|
118
163
|
|
|
119
164
|
---
|
|
120
165
|
|
|
@@ -49,7 +49,7 @@ siluzan-tso google-analysis render \
|
|
|
49
49
|
**Excel 分支**(用户明确要 xlsx 时):
|
|
50
50
|
|
|
51
51
|
1. 步骤 1~2 与 HTML 流程相同(拉数 → 分析)。
|
|
52
|
-
2. 改为 Agent 执行 node/python 脚本按 `google-period-report-excel.md` 写出 `.xlsx`(先读齐 `*.outline.txt
|
|
52
|
+
2. 改为 Agent 执行 node/python 脚本按 `google-period-report-excel.md` 写出 `.xlsx`(先读齐 `*.outline.txt`)。核心指标的上期转化价值 / 单转化价值 / ROAS 按该文「转化价值环比」再拉等长上期 `campaigns` 后汇总。
|
|
53
53
|
3. **不要**调用 `google-analysis render`(除非用户同时要 HTML + Excel)。
|
|
54
54
|
4. **禁止**假设存在 `siluzan-tso … excel` 子命令。
|
|
55
55
|
|
|
@@ -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.61-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.61-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"
|