siluzan-tso-cli 1.1.46-beta.2 → 1.1.46-beta.6
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 +63 -132
- package/dist/skill/SKILL.md +3 -1
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +5 -3
- package/dist/skill/references/analytics/account-analytics.md +5 -1
- package/dist/skill/references/core/agent-conventions.md +1 -1
- package/dist/skill/references/core/workflows.md +7 -5
- package/dist/skill/references/operations/guard.md +19 -28
- package/dist/skill/references/operations/hosted-automation-bing.md +118 -0
- package/dist/skill/references/operations/hosted-automation-monitoring-json.md +3 -2
- package/dist/skill/references/operations/hosted-automation-optimize-index.md +2 -1
- package/dist/skill/references/operations/hosted-automation-scenarios.md +18 -19
- package/dist/skill/references/operations/hosted-automation-self-control.md +10 -8
- package/dist/skill/references/operations/hosted-automation-user-catalog.md +35 -14
- package/dist/skill/references/operations/hosted-automation-yandex.md +83 -0
- package/dist/skill/references/report-templates/yandex-period-report.md +1 -1
- package/dist/skill/report-templates/yandex-period-report.html +12 -1
- package/dist/skill/report-templates/yandex-period-report.md +1 -1
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/eval/cases/guard-budget-circuit-all-google.scenario.json +1 -1
- package/eval/cases/guard-zero-conv-empty-spend.scenario.json +1 -1
- package/eval/stub-fixtures/guard-budget-circuit.json +2 -7
- package/eval/stub-fixtures/guard-zero-conv.json +2 -7
- 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.46-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.46-beta.6),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -107451,8 +107451,8 @@ function assertGoogleOnly(media) {
|
|
|
107451
107451
|
if (media !== "Google") {
|
|
107452
107452
|
console.error(
|
|
107453
107453
|
`
|
|
107454
|
-
\u274C guard \u7194\u65AD\
|
|
107455
|
-
\
|
|
107454
|
+
\u274C guard \u7194\u65AD\u626B\u63CF\u76EE\u524D\u4EC5\u652F\u6301 Google\uFF08\u5F53\u524D\uFF1A${media}\uFF09\u3002
|
|
107455
|
+
\u8BF7\u6539\u7528 -m Google\u3002
|
|
107456
107456
|
`
|
|
107457
107457
|
);
|
|
107458
107458
|
process.exit(1);
|
|
@@ -107543,46 +107543,6 @@ async function fetchAdsForDay(config, accountId, date, verbose) {
|
|
|
107543
107543
|
};
|
|
107544
107544
|
}).filter((r) => r.id);
|
|
107545
107545
|
}
|
|
107546
|
-
async function pauseCampaign(config, accountId, campaignId, verbose) {
|
|
107547
|
-
const googleApiUrl = requireGoogleApi(config);
|
|
107548
|
-
const detailUrl = `${googleApiUrl}/campaignmanagement/campaign/${accountId}/${campaignId}`;
|
|
107549
|
-
const res = await apiFetch2(detailUrl, config, {}, verbose);
|
|
107550
|
-
const campaign = res.data ?? res;
|
|
107551
|
-
const body = { ...campaign, statusV2: "Paused" };
|
|
107552
|
-
await apiFetch2(detailUrl, config, { method: "PUT", body: JSON.stringify(body) }, verbose);
|
|
107553
|
-
}
|
|
107554
|
-
async function pauseAdGroup(config, accountId, adGroupId, date, verbose) {
|
|
107555
|
-
const googleApiUrl = requireGoogleApi(config);
|
|
107556
|
-
const listUrl = adgroupListUrl(googleApiUrl, accountId, date, date);
|
|
107557
|
-
const adgroup = await findItemInList(
|
|
107558
|
-
listUrl,
|
|
107559
|
-
config,
|
|
107560
|
-
adGroupId,
|
|
107561
|
-
verbose
|
|
107562
|
-
);
|
|
107563
|
-
const putUrl = `${googleApiUrl}/adgroupnmanagement/adgroup/${accountId}/${adGroupId}`;
|
|
107564
|
-
await apiFetch2(
|
|
107565
|
-
putUrl,
|
|
107566
|
-
config,
|
|
107567
|
-
{ method: "PUT", body: JSON.stringify({ ...adgroup, statusV2: "Paused" }) },
|
|
107568
|
-
verbose
|
|
107569
|
-
);
|
|
107570
|
-
}
|
|
107571
|
-
async function pauseAd(config, accountId, adId, date, verbose) {
|
|
107572
|
-
const googleApiUrl = requireGoogleApi(config);
|
|
107573
|
-
const params = new URLSearchParams();
|
|
107574
|
-
params.set("startDate", toGoogleDate(date, 0));
|
|
107575
|
-
params.set("endDate", toGoogleDate(date, 0));
|
|
107576
|
-
const listUrl = `${googleApiUrl}/admanagement/v2/list/${accountId}?${params}`;
|
|
107577
|
-
const ad = await findItemInList(listUrl, config, adId, verbose);
|
|
107578
|
-
const putUrl = `${googleApiUrl}/admanagement/campaign/${accountId}/${adId}`;
|
|
107579
|
-
await apiFetch2(
|
|
107580
|
-
putUrl,
|
|
107581
|
-
config,
|
|
107582
|
-
{ method: "PUT", body: JSON.stringify({ ...ad, statusV2: "Paused" }) },
|
|
107583
|
-
verbose
|
|
107584
|
-
);
|
|
107585
|
-
}
|
|
107586
107546
|
function printHitsTable(title, rows, cols) {
|
|
107587
107547
|
console.log(`
|
|
107588
107548
|
${title}
|
|
@@ -107641,14 +107601,13 @@ async function runBudgetCircuit(opts) {
|
|
|
107641
107601
|
}
|
|
107642
107602
|
const statusFilter = opts.status === void 0 ? "Enabled" : opts.status;
|
|
107643
107603
|
const filterAll = statusFilter === "" || statusFilter === "*";
|
|
107644
|
-
const apply = Boolean(opts.apply);
|
|
107645
107604
|
const accounts = await resolveGuardAccounts(opts, config);
|
|
107646
107605
|
if (accounts.length === 0) {
|
|
107647
107606
|
console.error("\n\u274C \u672A\u627E\u5230\u53EF\u626B\u63CF\u7684 Google \u8D26\u6237\u3002\n");
|
|
107648
107607
|
process.exit(1);
|
|
107649
107608
|
}
|
|
107650
107609
|
process.stderr.write(
|
|
107651
|
-
`\u23F3 [guard budget-circuit] ${accounts.length} \u6237 \xB7 \u65E5\u671F ${date} \xB7 ratio=${ratio}
|
|
107610
|
+
`\u23F3 [guard budget-circuit] ${accounts.length} \u6237 \xB7 \u65E5\u671F ${date} \xB7 ratio=${ratio} \xB7 \u53EA\u8BFB\u626B\u63CF
|
|
107652
107611
|
`
|
|
107653
107612
|
);
|
|
107654
107613
|
const accountResults = await runWithConcurrency(
|
|
@@ -107682,18 +107641,8 @@ async function runBudgetCircuit(opts) {
|
|
|
107682
107641
|
spend: c.spend,
|
|
107683
107642
|
budget,
|
|
107684
107643
|
ratio,
|
|
107685
|
-
threshold: budget * ratio
|
|
107686
|
-
applied: false
|
|
107644
|
+
threshold: budget * ratio
|
|
107687
107645
|
};
|
|
107688
|
-
if (apply) {
|
|
107689
|
-
try {
|
|
107690
|
-
await pauseCampaign(config, acc.mediaCustomerId, c.id, opts.verbose);
|
|
107691
|
-
hit.applied = true;
|
|
107692
|
-
hit.statusV2 = "Paused";
|
|
107693
|
-
} catch (err) {
|
|
107694
|
-
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107695
|
-
}
|
|
107696
|
-
}
|
|
107697
107646
|
hits2.push(hit);
|
|
107698
107647
|
}
|
|
107699
107648
|
return {
|
|
@@ -107720,7 +107669,6 @@ async function runBudgetCircuit(opts) {
|
|
|
107720
107669
|
accountName: r.accountName,
|
|
107721
107670
|
error: r.error
|
|
107722
107671
|
}));
|
|
107723
|
-
const paused = hits.filter((h) => h.applied);
|
|
107724
107672
|
const checkedCampaigns = accountResults.reduce((n, r) => n + r.checked, 0);
|
|
107725
107673
|
const payload = {
|
|
107726
107674
|
meta: {
|
|
@@ -107728,20 +107676,16 @@ async function runBudgetCircuit(opts) {
|
|
|
107728
107676
|
date,
|
|
107729
107677
|
ratio,
|
|
107730
107678
|
statusFilter: filterAll ? "*" : statusFilter,
|
|
107731
|
-
|
|
107732
|
-
note: "\u975E Google \u5A92\u4F53\u672C CLI \u65E0\u7CFB\u5217\u7194\u65AD\u5199\u80FD\u529B\uFF1B\u672C\u547D\u4EE4\u4EC5\u626B\u63CF Google\u3002"
|
|
107679
|
+
note: "\u672C\u547D\u4EE4\u53EA\u626B\u63CF\u5217\u51FA\u547D\u4E2D\uFF0C\u4E0D\u6682\u505C\u3002\u8981\u5BF9\u67D0\u6761\u7CFB\u5217\u505C\u6295\uFF0C\u987B\u5355\u72EC\u6267\u884C ad campaign-status --status Paused --commit\u3002"
|
|
107733
107680
|
},
|
|
107734
107681
|
summary: {
|
|
107735
107682
|
label: "\u8D85\u9884\u7B97\u7194\u65AD",
|
|
107736
107683
|
accountCount: accounts.length,
|
|
107737
107684
|
checkedCampaigns,
|
|
107738
107685
|
hitCount: hits.length,
|
|
107739
|
-
|
|
107740
|
-
errorCount: errors.length,
|
|
107741
|
-
mode: apply ? "apply" : "dry-run"
|
|
107686
|
+
errorCount: errors.length
|
|
107742
107687
|
},
|
|
107743
107688
|
hits,
|
|
107744
|
-
paused,
|
|
107745
107689
|
errors
|
|
107746
107690
|
};
|
|
107747
107691
|
if (await emitCliJsonOrSnapshot(opts, {
|
|
@@ -107750,7 +107694,7 @@ async function runBudgetCircuit(opts) {
|
|
|
107750
107694
|
payload
|
|
107751
107695
|
})) {
|
|
107752
107696
|
}
|
|
107753
|
-
const title = `\u8D85\u9884\u7B97\u7194\u65AD\
|
|
107697
|
+
const title = `\u8D85\u9884\u7B97\u7194\u65AD\u626B\u63CF \xB7 ${date} \xB7 ratio=${ratio} \xB7 \u547D\u4E2D ${hits.length}/${checkedCampaigns}`;
|
|
107754
107698
|
printHitsTable(
|
|
107755
107699
|
title,
|
|
107756
107700
|
hits.map((h) => ({
|
|
@@ -107758,16 +107702,14 @@ async function runBudgetCircuit(opts) {
|
|
|
107758
107702
|
campaign: h.campaignName.slice(0, 36),
|
|
107759
107703
|
spend: h.spend.toFixed(2),
|
|
107760
107704
|
budget: h.budget.toFixed(2),
|
|
107761
|
-
threshold: h.threshold.toFixed(2)
|
|
107762
|
-
applied: h.applied ? "Paused" : h.applyError ? `ERR:${h.applyError.slice(0, 20)}` : "\u2014"
|
|
107705
|
+
threshold: h.threshold.toFixed(2)
|
|
107763
107706
|
})),
|
|
107764
107707
|
[
|
|
107765
107708
|
{ key: "account", header: "\u8D26\u6237ID" },
|
|
107766
107709
|
{ key: "campaign", header: "\u7CFB\u5217" },
|
|
107767
107710
|
{ key: "spend", header: "\u5F53\u65E5\u82B1\u8D39" },
|
|
107768
107711
|
{ key: "budget", header: "\u65E5\u9884\u7B97" },
|
|
107769
|
-
{ key: "threshold", header: "\u9608\u503C" }
|
|
107770
|
-
{ key: "applied", header: "\u6682\u505C" }
|
|
107712
|
+
{ key: "threshold", header: "\u9608\u503C" }
|
|
107771
107713
|
]
|
|
107772
107714
|
);
|
|
107773
107715
|
if (errors.length > 0) {
|
|
@@ -107776,14 +107718,9 @@ async function runBudgetCircuit(opts) {
|
|
|
107776
107718
|
console.error(` \u2022 ${e.mediaCustomerId}: ${e.error}`);
|
|
107777
107719
|
}
|
|
107778
107720
|
}
|
|
107779
|
-
if (
|
|
107721
|
+
if (hits.length > 0) {
|
|
107780
107722
|
console.log(
|
|
107781
|
-
'\u63D0\u793A\uFF1A\
|
|
107782
|
-
);
|
|
107783
|
-
} else if (apply) {
|
|
107784
|
-
console.log(
|
|
107785
|
-
`\u2705 apply \u5B8C\u6210\uFF1A\u547D\u4E2D ${hits.length}\uFF0C\u6210\u529F\u6682\u505C ${paused.length}${hits.length - paused.length > 0 ? `\uFF0C\u5931\u8D25 ${hits.length - paused.length}` : ""}\u3002
|
|
107786
|
-
`
|
|
107723
|
+
'\u63D0\u793A\uFF1A\u672C\u547D\u4EE4\u53EA\u5217\u51FA\u547D\u4E2D\uFF0C\u4E0D\u4F1A\u6682\u505C\u3002\u8981\u5BF9\u67D0\u6761\u7CFB\u5217\u505C\u6295\uFF0C\u8BF7\u5BF9\u8BE5\u8D26\u6237\u5355\u72EC\u6267\u884C\uFF1A\n siluzan-tso ad campaign-status -a <\u8D26\u6237ID> --id <\u7CFB\u5217ID> --status Paused --commit "\u8D85\u9884\u7B97\u7194\u65AD <date>"\n'
|
|
107787
107724
|
);
|
|
107788
107725
|
} else {
|
|
107789
107726
|
console.log("\u2705 \u4ECA\u65E5\u65E0\u7CFB\u5217\u89E6\u53D1\u8D85\u9884\u7B97\u7194\u65AD\u3002\n");
|
|
@@ -107810,7 +107747,6 @@ async function runZeroConv(opts) {
|
|
|
107810
107747
|
const level = parseLevel(opts.level);
|
|
107811
107748
|
const fallback = opts.fallbackTargetCpa != null && Number.isFinite(opts.fallbackTargetCpa) ? opts.fallbackTargetCpa : null;
|
|
107812
107749
|
const onlyEnabled = opts.onlyEnabled !== false;
|
|
107813
|
-
const apply = Boolean(opts.apply);
|
|
107814
107750
|
if ((level === "ad" || level === "both") && fallback == null) {
|
|
107815
107751
|
process.stderr.write(
|
|
107816
107752
|
"\u26A0\uFE0F [guard zero-conv] \u521B\u610F\u7EF4\u65E0\u7EC4\u7EA7 targetCpa \u5B57\u6BB5\uFF0C\u672A\u4F20 --fallback-target-cpa \u65F6\u521B\u610F\u547D\u4E2D\u53EF\u80FD\u4E3A 0\uFF08\u4F1A\u8BB0\u5165 skipped\uFF09\u3002\n"
|
|
@@ -107822,7 +107758,7 @@ async function runZeroConv(opts) {
|
|
|
107822
107758
|
process.exit(1);
|
|
107823
107759
|
}
|
|
107824
107760
|
process.stderr.write(
|
|
107825
|
-
`\u23F3 [guard zero-conv] ${accounts.length} \u6237 \xB7 ${date} \xB7 \xD7${multiple} \xB7 level=${level}
|
|
107761
|
+
`\u23F3 [guard zero-conv] ${accounts.length} \u6237 \xB7 ${date} \xB7 \xD7${multiple} \xB7 level=${level} \xB7 \u53EA\u8BFB\u626B\u63CF
|
|
107826
107762
|
`
|
|
107827
107763
|
);
|
|
107828
107764
|
const accountResults = await runWithConcurrency(
|
|
@@ -107860,18 +107796,8 @@ async function runZeroConv(opts) {
|
|
|
107860
107796
|
conversions: g.conversions ?? 0,
|
|
107861
107797
|
targetCpaYuan: target,
|
|
107862
107798
|
multiple,
|
|
107863
|
-
threshold: target * multiple
|
|
107864
|
-
applied: false
|
|
107799
|
+
threshold: target * multiple
|
|
107865
107800
|
};
|
|
107866
|
-
if (apply) {
|
|
107867
|
-
try {
|
|
107868
|
-
await pauseAdGroup(config, acc.mediaCustomerId, g.id, date, opts.verbose);
|
|
107869
|
-
hit.applied = true;
|
|
107870
|
-
hit.statusV2 = "Paused";
|
|
107871
|
-
} catch (err) {
|
|
107872
|
-
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107873
|
-
}
|
|
107874
|
-
}
|
|
107875
107801
|
hits2.push(hit);
|
|
107876
107802
|
}
|
|
107877
107803
|
}
|
|
@@ -107903,18 +107829,8 @@ async function runZeroConv(opts) {
|
|
|
107903
107829
|
conversions: ad.conversions ?? 0,
|
|
107904
107830
|
targetCpaYuan: fallback,
|
|
107905
107831
|
multiple,
|
|
107906
|
-
threshold: fallback * multiple
|
|
107907
|
-
applied: false
|
|
107832
|
+
threshold: fallback * multiple
|
|
107908
107833
|
};
|
|
107909
|
-
if (apply) {
|
|
107910
|
-
try {
|
|
107911
|
-
await pauseAd(config, acc.mediaCustomerId, ad.id, date, opts.verbose);
|
|
107912
|
-
hit.applied = true;
|
|
107913
|
-
hit.statusV2 = "Paused";
|
|
107914
|
-
} catch (err) {
|
|
107915
|
-
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107916
|
-
}
|
|
107917
|
-
}
|
|
107918
107834
|
hits2.push(hit);
|
|
107919
107835
|
}
|
|
107920
107836
|
}
|
|
@@ -107945,7 +107861,6 @@ async function runZeroConv(opts) {
|
|
|
107945
107861
|
accountName: r.accountName,
|
|
107946
107862
|
error: r.error
|
|
107947
107863
|
}));
|
|
107948
|
-
const paused = hits.filter((h) => h.applied);
|
|
107949
107864
|
const checked = accountResults.reduce((n, r) => n + r.checked, 0);
|
|
107950
107865
|
const payload = {
|
|
107951
107866
|
meta: {
|
|
@@ -107954,21 +107869,17 @@ async function runZeroConv(opts) {
|
|
|
107954
107869
|
cpaMultiple: multiple,
|
|
107955
107870
|
level,
|
|
107956
107871
|
fallbackTargetCpa: fallback,
|
|
107957
|
-
|
|
107958
|
-
note: "\u975E Google \u5A92\u4F53\u672C CLI \u65E0\u7EC4/\u521B\u610F\u7194\u65AD\u5199\u80FD\u529B\uFF1B\u672C\u547D\u4EE4\u4EC5\u626B\u63CF Google\u3002P1\u300C\u7A7A\u8017\u7194\u65AD\u300D\u901A\u77E5\u7531\u5BBF\u4E3B\u53D1\u9001\u3002"
|
|
107872
|
+
note: "\u672C\u547D\u4EE4\u53EA\u626B\u63CF\u5217\u51FA\u547D\u4E2D\uFF0C\u4E0D\u6682\u505C\u3002\u8981\u5BF9\u67D0\u4E2A\u7EC4/\u521B\u610F\u505C\u6295\uFF0C\u987B\u5355\u72EC\u6267\u884C ad adgroup-status / ad-status --status Paused --commit\u3002P1\u300C\u7A7A\u8017\u7194\u65AD\u300D\u901A\u77E5\u7531\u5BBF\u4E3B\u53D1\u9001\u3002"
|
|
107959
107873
|
},
|
|
107960
107874
|
summary: {
|
|
107961
107875
|
label: "\u7A7A\u8017\u7194\u65AD",
|
|
107962
107876
|
accountCount: accounts.length,
|
|
107963
107877
|
checkedObjects: checked,
|
|
107964
107878
|
hitCount: hits.length,
|
|
107965
|
-
pausedCount: paused.length,
|
|
107966
107879
|
skippedCount: skipped.length,
|
|
107967
|
-
errorCount: errors.length
|
|
107968
|
-
mode: apply ? "apply" : "dry-run"
|
|
107880
|
+
errorCount: errors.length
|
|
107969
107881
|
},
|
|
107970
107882
|
hits,
|
|
107971
|
-
paused,
|
|
107972
107883
|
skipped,
|
|
107973
107884
|
errors
|
|
107974
107885
|
};
|
|
@@ -107977,7 +107888,7 @@ async function runZeroConv(opts) {
|
|
|
107977
107888
|
commandLabel: "guard zero-conv",
|
|
107978
107889
|
payload
|
|
107979
107890
|
});
|
|
107980
|
-
const title = `\u7A7A\u8017\u7194\u65AD\
|
|
107891
|
+
const title = `\u7A7A\u8017\u7194\u65AD\u626B\u63CF \xB7 ${date} \xB7 \xD7${multiple} \xB7 \u547D\u4E2D ${hits.length}/${checked}`;
|
|
107981
107892
|
printHitsTable(
|
|
107982
107893
|
title,
|
|
107983
107894
|
hits.map((h) => ({
|
|
@@ -107986,8 +107897,7 @@ async function runZeroConv(opts) {
|
|
|
107986
107897
|
name: h.objectName.slice(0, 32),
|
|
107987
107898
|
spend: h.spend.toFixed(2),
|
|
107988
107899
|
target: h.targetCpaYuan.toFixed(2),
|
|
107989
|
-
threshold: h.threshold.toFixed(2)
|
|
107990
|
-
applied: h.applied ? "Paused" : h.applyError ? `ERR` : "\u2014"
|
|
107900
|
+
threshold: h.threshold.toFixed(2)
|
|
107991
107901
|
})),
|
|
107992
107902
|
[
|
|
107993
107903
|
{ key: "account", header: "\u8D26\u6237ID" },
|
|
@@ -107995,21 +107905,15 @@ async function runZeroConv(opts) {
|
|
|
107995
107905
|
{ key: "name", header: "\u5BF9\u8C61" },
|
|
107996
107906
|
{ key: "spend", header: "\u5F53\u65E5\u82B1\u8D39" },
|
|
107997
107907
|
{ key: "target", header: "\u76EE\u6807CPA" },
|
|
107998
|
-
{ key: "threshold", header: "\u9608\u503C" }
|
|
107999
|
-
{ key: "applied", header: "\u6682\u505C" }
|
|
107908
|
+
{ key: "threshold", header: "\u9608\u503C" }
|
|
108000
107909
|
]
|
|
108001
107910
|
);
|
|
108002
107911
|
if (errors.length > 0) {
|
|
108003
107912
|
console.error(`\u26A0\uFE0F ${errors.length} \u4E2A\u8D26\u6237\u62C9\u6570\u5931\u8D25\uFF08\u8BE6\u89C1 json-out errors[]\uFF09`);
|
|
108004
107913
|
}
|
|
108005
|
-
if (
|
|
108006
|
-
console.log(
|
|
108007
|
-
'\u63D0\u793A\uFF1A\u4EE5\u4E0A\u4E3A dry-run\u3002\u786E\u8BA4\u540E\u8FFD\u52A0 --apply --commit "zero-conv <date>" \u6267\u884C\u6682\u505C\u3002\n'
|
|
108008
|
-
);
|
|
108009
|
-
} else if (apply) {
|
|
107914
|
+
if (hits.length > 0) {
|
|
108010
107915
|
console.log(
|
|
108011
|
-
|
|
108012
|
-
`
|
|
107916
|
+
'\u63D0\u793A\uFF1A\u672C\u547D\u4EE4\u53EA\u5217\u51FA\u547D\u4E2D\uFF0C\u4E0D\u4F1A\u6682\u505C\u3002\u8981\u5BF9\u67D0\u4E2A\u7EC4/\u521B\u610F\u505C\u6295\uFF0C\u8BF7\u5BF9\u8BE5\u8D26\u6237\u5355\u72EC\u6267\u884C\uFF1A\n siluzan-tso ad adgroup-status -a <\u8D26\u6237ID> --id <\u7EC4ID> --status Paused --commit "\u7A7A\u8017\u7194\u65AD <date>"\n siluzan-tso ad ad-status -a <\u8D26\u6237ID> --id <\u5E7F\u544AID> --status Paused --commit "\u7A7A\u8017\u7194\u65AD <date>"\n'
|
|
108013
107917
|
);
|
|
108014
107918
|
} else {
|
|
108015
107919
|
console.log("\u2705 \u4ECA\u65E5\u65E0\u5BF9\u8C61\u89E6\u53D1\u7A7A\u8017\u7194\u65AD\u3002\n");
|
|
@@ -108019,14 +107923,14 @@ async function runZeroConv(opts) {
|
|
|
108019
107923
|
// src/commands/guard/_register.ts
|
|
108020
107924
|
function register11(program2) {
|
|
108021
107925
|
const guard = program2.command("guard").description(
|
|
108022
|
-
"Google \u6295\u653E\u81EA\u63A7\u7194\u65AD\uFF1A\u5168\u6237\uFF08\u6216 -a \u5B50\u96C6\uFF09\
|
|
107926
|
+
"Google \u6295\u653E\u81EA\u63A7\u7194\u65AD\u626B\u63CF\uFF1A\u5168\u6237\uFF08\u6216 -a \u5B50\u96C6\uFF09\u5217\u51FA\u5F53\u65E5\u8D85\u9884\u7B97/\u7A7A\u8017\u547D\u4E2D\uFF0C\u53EA\u8BFB\u4E0D\u6682\u505C\u3002\u8981\u505C\u6295\u653E\u987B\u5BF9\u6BCF\u4E2A\u547D\u4E2D\u5BF9\u8C61\u5355\u72EC\u6267\u884C ad campaign-status / adgroup-status / ad-status\uFF08\u5E26 --commit\uFF09\u3002\u975E Google \u5A92\u4F53\u4E0D\u652F\u6301\u3002"
|
|
108023
107927
|
);
|
|
108024
107928
|
guard.command("budget-circuit").description(
|
|
108025
|
-
"\u5355\u65E5\u9884\u7B97\u7194\u65AD\uFF1A\u5F53\u65E5\u7CFB\u5217 spend \u2265 \u65E5\u9884\u7B97 \xD7 ratio \u65F6\u5217\u51FA\uFF08\
|
|
107929
|
+
"\u5355\u65E5\u9884\u7B97\u7194\u65AD\u626B\u63CF\uFF1A\u5F53\u65E5\u7CFB\u5217 spend \u2265 \u65E5\u9884\u7B97 \xD7 ratio \u65F6\u5217\u51FA\u547D\u4E2D\uFF08\u4E0D\u6682\u505C\uFF09\u3002\u66FF\u4EE3\u300Clist-accounts \xD7 N + \u9010\u6237 ad campaigns + \u811A\u672C\u300D\u3002"
|
|
108026
107930
|
).requiredOption("-m, --media <type>", "\u76EE\u524D\u4EC5\u652F\u6301 Google").option(
|
|
108027
107931
|
"-a, --accounts <ids>",
|
|
108028
107932
|
"\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u540D\u4E0B\u5168\u90E8 Google \u8D26\u6237"
|
|
108029
|
-
).option("--date <YYYY-MM-DD>", "\u7EDF\u8BA1\u65E5\uFF08Asia/Shanghai \u9ED8\u8BA4\u4ECA\u5929\uFF09\uFF1B\u5F3A\u5236 start=end=\u8BE5\u65E5").option("--ratio <n>", "\u9608\u503C\u7CFB\u6570\uFF1Aspend >= budget * ratio\uFF08\u9ED8\u8BA4 1.1\uFF09", (v) => parseFloat(v)).option("--status <statusV2>", "\u53EA\u68C0\u67E5\u8BE5\u72B6\u6001\u7684\u7CFB\u5217\uFF08\u9ED8\u8BA4 Enabled\uFF1B\u4F20 * \u8868\u793A\u4E0D\u8FC7\u6EE4\uFF09", "Enabled").option("--
|
|
107933
|
+
).option("--date <YYYY-MM-DD>", "\u7EDF\u8BA1\u65E5\uFF08Asia/Shanghai \u9ED8\u8BA4\u4ECA\u5929\uFF09\uFF1B\u5F3A\u5236 start=end=\u8BE5\u65E5").option("--ratio <n>", "\u9608\u503C\u7CFB\u6570\uFF1Aspend >= budget * ratio\uFF08\u9ED8\u8BA4 1.1\uFF09", (v) => parseFloat(v)).option("--status <statusV2>", "\u53EA\u68C0\u67E5\u8BE5\u72B6\u6001\u7684\u7CFB\u5217\uFF08\u9ED8\u8BA4 Enabled\uFF1B\u4F20 * \u8868\u793A\u4E0D\u8FC7\u6EE4\uFF09", "Enabled").option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF09").option(
|
|
108030
107934
|
"--json-out <path>",
|
|
108031
107935
|
"\u843D\u76D8\u76EE\u5F55\u6216 *.json\uFF1Bstdout \u4E00\u884C\u6458\u8981\uFF1B\u4EBA\u7C7B\u53EF\u8BFB\u8868\u59CB\u7EC8\u6253\u5370",
|
|
108032
107936
|
void 0
|
|
@@ -108038,7 +107942,6 @@ function register11(program2) {
|
|
|
108038
107942
|
date: opts.date,
|
|
108039
107943
|
ratio: opts.ratio,
|
|
108040
107944
|
status: opts.status,
|
|
108041
|
-
apply: opts.apply,
|
|
108042
107945
|
pageSize: opts.pageSize,
|
|
108043
107946
|
maxPages: opts.maxPages,
|
|
108044
107947
|
token: opts.token,
|
|
@@ -108049,7 +107952,7 @@ function register11(program2) {
|
|
|
108049
107952
|
}
|
|
108050
107953
|
);
|
|
108051
107954
|
guard.command("zero-conv").description(
|
|
108052
|
-
"\u7A7A\u8017\u7194\u65AD\uFF1A\u5F53\u65E5 spend \u2265 \u76EE\u6807 CPA \xD7 N \u4E14\u8F6C\u5316\u4E3A 0 \u65F6\u5217\u51FA\u7EC4/\u521B\u610F\uFF08\
|
|
107955
|
+
"\u7A7A\u8017\u7194\u65AD\u626B\u63CF\uFF1A\u5F53\u65E5 spend \u2265 \u76EE\u6807 CPA \xD7 N \u4E14\u8F6C\u5316\u4E3A 0 \u65F6\u5217\u51FA\u7EC4/\u521B\u610F\uFF08\u4E0D\u6682\u505C\uFF09\u3002\u7ED3\u679C summary.label=\u300C\u7A7A\u8017\u7194\u65AD\u300D\uFF1BP1 \u901A\u77E5\u7531\u5BBF\u4E3B\u53D1\u9001\u3002"
|
|
108053
107956
|
).requiredOption("-m, --media <type>", "\u76EE\u524D\u4EC5\u652F\u6301 Google").option(
|
|
108054
107957
|
"-a, --accounts <ids>",
|
|
108055
107958
|
"\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u540D\u4E0B\u5168\u90E8 Google \u8D26\u6237"
|
|
@@ -108057,7 +107960,7 @@ function register11(program2) {
|
|
|
108057
107960
|
"--fallback-target-cpa <yuan>",
|
|
108058
107961
|
"\u7EC4\u65E0 targetCpa\uFF08\u6216\u521B\u610F\u7EF4\uFF09\u65F6\u4F7F\u7528\u7684\u76EE\u6807 CPA\uFF08\u5143\uFF09",
|
|
108059
107962
|
(v) => parseFloat(v)
|
|
108060
|
-
).option("--
|
|
107963
|
+
).option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF09").option("--json-out <path>", "\u843D\u76D8\u76EE\u5F55\u6216 *.json", void 0).option("--refresh-dp", "\u5F3A\u5236\u91CD\u62C9 Datapermission", false).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF", false).action(
|
|
108061
107964
|
async (opts) => {
|
|
108062
107965
|
await runZeroConv({
|
|
108063
107966
|
media: opts.media,
|
|
@@ -108066,7 +107969,6 @@ function register11(program2) {
|
|
|
108066
107969
|
cpaMultiple: opts.cpaMultiple,
|
|
108067
107970
|
level: opts.level,
|
|
108068
107971
|
fallbackTargetCpa: opts.fallbackTargetCpa,
|
|
108069
|
-
apply: opts.apply,
|
|
108070
107972
|
pageSize: opts.pageSize,
|
|
108071
107973
|
maxPages: opts.maxPages,
|
|
108072
107974
|
token: opts.token,
|
|
@@ -132267,7 +132169,14 @@ function parseLocalYmd(ymd) {
|
|
|
132267
132169
|
return /* @__PURE__ */ new Date(NaN);
|
|
132268
132170
|
}
|
|
132269
132171
|
const [y, m, day] = parts;
|
|
132270
|
-
|
|
132172
|
+
if (m < 1 || m > 12 || day < 1 || day > 31) {
|
|
132173
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
132174
|
+
}
|
|
132175
|
+
const d = new Date(y, m - 1, day);
|
|
132176
|
+
if (d.getFullYear() !== y || d.getMonth() !== m - 1 || d.getDate() !== day) {
|
|
132177
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
132178
|
+
}
|
|
132179
|
+
return d;
|
|
132271
132180
|
}
|
|
132272
132181
|
function formatLocalYmd(d) {
|
|
132273
132182
|
const y = d.getFullYear();
|
|
@@ -134469,7 +134378,14 @@ function parseLocalYmd2(ymd) {
|
|
|
134469
134378
|
return /* @__PURE__ */ new Date(NaN);
|
|
134470
134379
|
}
|
|
134471
134380
|
const [y, m, day] = parts;
|
|
134472
|
-
|
|
134381
|
+
if (m < 1 || m > 12 || day < 1 || day > 31) {
|
|
134382
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
134383
|
+
}
|
|
134384
|
+
const d = new Date(y, m - 1, day);
|
|
134385
|
+
if (d.getFullYear() !== y || d.getMonth() !== m - 1 || d.getDate() !== day) {
|
|
134386
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
134387
|
+
}
|
|
134388
|
+
return d;
|
|
134473
134389
|
}
|
|
134474
134390
|
function formatLocalYmd2(d) {
|
|
134475
134391
|
const y = d.getFullYear();
|
|
@@ -134600,6 +134516,11 @@ function num10(value) {
|
|
|
134600
134516
|
function round25(value) {
|
|
134601
134517
|
return value == null ? void 0 : Math.round(value * 100) / 100;
|
|
134602
134518
|
}
|
|
134519
|
+
function normalizeYandexRoi(value) {
|
|
134520
|
+
if (typeof value !== "number" && typeof value !== "string") return void 0;
|
|
134521
|
+
const r = num10(value);
|
|
134522
|
+
return r === -1 ? void 0 : r;
|
|
134523
|
+
}
|
|
134603
134524
|
function asItems(payload) {
|
|
134604
134525
|
const obj = asRecord26(payload);
|
|
134605
134526
|
if (!obj) return [];
|
|
@@ -134621,7 +134542,7 @@ function pickMetrics2(row, extras = []) {
|
|
|
134621
134542
|
averageCpc: num10(row.averageCpc) ?? (clicks > 0 ? round25(spend / clicks) : void 0),
|
|
134622
134543
|
conversionRate: num10(row.conversionRate) ?? (clicks > 0 ? conversions / clicks : void 0),
|
|
134623
134544
|
costPerConversion: num10(row.costPerConversion) ?? (conversions > 0 ? round25(spend / conversions) : void 0),
|
|
134624
|
-
roi:
|
|
134545
|
+
roi: normalizeYandexRoi(row.roi)
|
|
134625
134546
|
};
|
|
134626
134547
|
for (const f of extras) {
|
|
134627
134548
|
if (row[f] !== void 0 && row[f] !== null) out[f] = row[f];
|
|
@@ -134666,8 +134587,14 @@ function parseYmd2(value) {
|
|
|
134666
134587
|
const s = normalizeYandexDailyDate(value);
|
|
134667
134588
|
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
134668
134589
|
if (!m) return null;
|
|
134669
|
-
const
|
|
134670
|
-
|
|
134590
|
+
const y = Number(m[1]);
|
|
134591
|
+
const month = Number(m[2]);
|
|
134592
|
+
const day = Number(m[3]);
|
|
134593
|
+
const d = new Date(y, month - 1, day);
|
|
134594
|
+
if (Number.isNaN(d.getTime()) || d.getFullYear() !== y || d.getMonth() !== month - 1 || d.getDate() !== day) {
|
|
134595
|
+
return null;
|
|
134596
|
+
}
|
|
134597
|
+
return d;
|
|
134671
134598
|
}
|
|
134672
134599
|
function formatYmd2(d) {
|
|
134673
134600
|
const y = d.getFullYear();
|
|
@@ -134746,9 +134673,12 @@ var YANDEX_DAILY_OUTLINE_HINTS = [
|
|
|
134746
134673
|
"// `items[].date` \u5DF2\u89C4\u8303\u4E3A YYYY-MM-DD\u3002\u63A5\u53E3\u53EF\u80FD\u8FD4\u56DE ISO \u65F6\u95F4\u6233\uFF08\u5982 2026-07-01T00:00:00+00:00\uFF09\uFF0CCLI \u5DF2\u622A\u65AD\uFF1B\u7981\u6B62\u518D\u62FC\u63A5 T00:00:00Z\uFF0C\u5426\u5219 new Date() \u4F1A Invalid Date\uFF0C\u5468\u6807\u7B7E\u53D8\u6210 NaN\u3002",
|
|
134747
134674
|
"// \u5468\u8D8B\u52BF\u8BFB\u672C\u6587\u4EF6 `weekly[]`\uFF08ISO \u5468\u4E00~\u5468\u65E5\uFF1B`days` \u4E3A\u6709\u6570\u636E\u7684\u5929\u6570\uFF09\u3002\u7981\u6B62\u81EA\u884C\u6309 date \u805A\u5468\u3002"
|
|
134748
134675
|
];
|
|
134676
|
+
var YANDEX_ROI_OUTLINE_HINTS = [
|
|
134677
|
+
"// `roi` = (Revenue-Spend)/Spend\uFF0C\u5DF2\u662F\u500D\u6570\uFF083.72 \u2248 \u5229\u6DA6 372%\uFF09\uFF0C\u4E0D\u662F 0~1\u3002\u7981\u6B62\u518D \xD7100\u3002\u65E0\u6536\u76CA\u65F6\u5E38\u4E3A -1\uFF0C\u6309\u7F3A\u5931\u5904\u7406\u3002"
|
|
134678
|
+
];
|
|
134749
134679
|
function buildYandexOutlineHints(section) {
|
|
134750
|
-
if (section === "daily") return YANDEX_DAILY_OUTLINE_HINTS;
|
|
134751
|
-
return
|
|
134680
|
+
if (section === "daily") return [...YANDEX_DAILY_OUTLINE_HINTS, ...YANDEX_ROI_OUTLINE_HINTS];
|
|
134681
|
+
return YANDEX_ROI_OUTLINE_HINTS;
|
|
134752
134682
|
}
|
|
134753
134683
|
function mapDailyRows(payload) {
|
|
134754
134684
|
return asItems(payload).map((r) => {
|
|
@@ -134835,7 +134765,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
134835
134765
|
kpis.costPerConversion = round25(num10(totals.costPerConversion));
|
|
134836
134766
|
}
|
|
134837
134767
|
if (num10(totals.conversionRate) != null) kpis.conversionRate = num10(totals.conversionRate);
|
|
134838
|
-
|
|
134768
|
+
const overviewRoi = normalizeYandexRoi(totals.roi);
|
|
134769
|
+
if (overviewRoi != null) kpis.roi = overviewRoi;
|
|
134839
134770
|
}
|
|
134840
134771
|
if (overview) {
|
|
134841
134772
|
if (num10(overview.balance) != null) kpis.balance = round25(num10(overview.balance));
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -113,7 +113,9 @@ siluzan-tso -h
|
|
|
113
113
|
| TikTok / Meta 线索表单 | W11 | `references/operations/clue.md` |
|
|
114
114
|
| 日/周巡检 | W12 | `references/core/workflows.md`(W12)+ `references/accounts/accounts-balance-stats.md` |
|
|
115
115
|
| 超预算熔断 / 空耗熔断(全户 Google) | — | `references/operations/guard.md`(`guard budget-circuit` / `guard zero-conv`;禁止逐户 for-loop) |
|
|
116
|
-
|
|
|
116
|
+
| Bing 自动化巡检(封禁/拒审/超预算/空耗预警) | — | `references/operations/hosted-automation-bing.md`(只读告警,不能自动暂停/改价) |
|
|
117
|
+
| Yandex 自动化巡检(余额/CPA/日花费预警) | — | `references/operations/hosted-automation-yandex.md`(只读告警,不能自动改投放) |
|
|
118
|
+
| 宿主编排 / 投放自控 / 异常监控 / 自动优化 | — | `references/operations/hosted-automation-user-catalog.md`(**仅当用户问自动化/巡检/熔断**;表内每行只 Read **一个** SOP;Google 熔断优先 guard.md;Bing/Yandex 走上两行) |
|
|
117
119
|
|
|
118
120
|
---
|
|
119
121
|
|
package/dist/skill/_meta.json
CHANGED
|
@@ -65,9 +65,11 @@
|
|
|
65
65
|
| `references/operations/forewarning.md` | 智能预警 |
|
|
66
66
|
| `references/operations/clue.md` | TikTok / Meta 线索表单 |
|
|
67
67
|
| `references/operations/hosted-automation-user-catalog.md` | 高阶自动化能力目录 |
|
|
68
|
-
| `references/operations/hosted-automation-self-control.md` | 预算/CPA/空耗自控 SOP
|
|
69
|
-
| `references/operations/hosted-automation-monitoring-json.md` | 异常监控 JSON 键名
|
|
70
|
-
| `references/operations/hosted-automation-optimize-index.md` | 自动优化 SOP 索引
|
|
68
|
+
| `references/operations/hosted-automation-self-control.md` | Google 预算/CPA/空耗自控 SOP |
|
|
69
|
+
| `references/operations/hosted-automation-monitoring-json.md` | Google 异常监控 JSON 键名 |
|
|
70
|
+
| `references/operations/hosted-automation-optimize-index.md` | Google 自动优化 SOP 索引 |
|
|
71
|
+
| `references/operations/hosted-automation-bing.md` | Bing 只读巡检 SOP |
|
|
72
|
+
| `references/operations/hosted-automation-yandex.md` | Yandex 只读巡检 SOP |
|
|
71
73
|
| `references/operations/hosted-automation-scenarios.md` | 宿主编排场景索引 |
|
|
72
74
|
|
|
73
75
|
## Assets 模板(`../assets/`)
|
|
@@ -332,6 +332,8 @@ siluzan-tso tiktok-analysis -a 1234567890 --start 2026-03-01 --end 2026-03-31 \
|
|
|
332
332
|
## Bing(BingV2)账户分析
|
|
333
333
|
|
|
334
334
|
> **日期限制**:Bing 报表不能包含今天或昨天。省略时 CLI 默认截至前天的近 7 天。用户要**已结束的完整自然月**(如「6月份」)→ `--start` 当月 1 日、`--end` 当月最后一天(6 月 = `06-30`,**禁止**减 1 天),见 `report-templates/bing-period-report.md` §日期规则。
|
|
335
|
+
>
|
|
336
|
+
> **自动化巡检步骤**(封禁 / 拒审 / 落地页 / 当日超预算 / 空耗预警,只读告警):`references/operations/hosted-automation-bing.md`。
|
|
335
337
|
|
|
336
338
|
与 `google-analysis` / `facebook-analysis` 同架构:`bing-analysis -a … --json-out …`(省略子命令名默认执行 `run`,批量拉取全部维度或 `--sections` 指定子集)。
|
|
337
339
|
|
|
@@ -432,13 +434,15 @@ siluzan-tso bing-analysis run -a <mediaCustomerId> --json-out ./snap --sections
|
|
|
432
434
|
|
|
433
435
|
## Yandex 账户分析
|
|
434
436
|
|
|
437
|
+
> **自动化巡检步骤**(余额 / 多账户 CPA / 日报花费,只读告警):`references/operations/hosted-automation-yandex.md`。
|
|
438
|
+
>
|
|
435
439
|
> **网关**:直打 YandexAPI `{yandexApiUrl}/yandex-analysis/*`(从 TSO `apiBaseUrl` 推导:`tso-api-ci` → `yandexapi-ci.mysiluzan.com`;可用 `SILUZAN_YANDEX_API` 覆盖)。
|
|
436
440
|
>
|
|
437
441
|
> **日期**:`start`/`end` 不能晚于今天;省略默认近 7 天(含今天)。**search-terms** 仅支持近 **180 天**(Direct 限制),超窗网关/CLI 均会拒绝。
|
|
438
442
|
>
|
|
439
443
|
> **账户 ID**:Yandex Client-Login / mediaCustomerId(如 `porg-xxx`,与 `list-accounts -m Yandex` 一致),**不是**纯数字。
|
|
440
444
|
>
|
|
441
|
-
> **金额**:已从 micros 转为账户币种小数(`/1e6`)。`ctr` / `conversionRate` 为 **0~1 小数**(先读 outline
|
|
445
|
+
> **金额**:已从 micros 转为账户币种小数(`/1e6`)。`ctr` / `conversionRate` 为 **0~1 小数**(先读 outline)。`roi` 为 **(收益-消耗)/消耗** 倍数,禁止再 ×100。
|
|
442
446
|
|
|
443
447
|
与 `bing-analysis` 同架构:`yandex-analysis -a … --json-out …`(省略子命令名默认执行 `run`);周期报告默认 **HTML**:`yandex-analysis render`(见 `report-templates/yandex-period-report.md`)。用户要 Excel → `yandex-period-report-excel.md`(Agent 脚本,无 excel 子命令)。
|
|
444
448
|
|
|
@@ -285,7 +285,7 @@
|
|
|
285
285
|
|
|
286
286
|
## 十二、风险预警与自动化(按需)
|
|
287
287
|
|
|
288
|
-
**仅当**用户问自动化 / 巡检 / 熔断 / 自控 / 异常监控时:Read `references/operations/hosted-automation-user-catalog.md`,按表选 **一个** SOP
|
|
288
|
+
**仅当**用户问自动化 / 巡检 / 熔断 / 自控 / 异常监控时:Read `references/operations/hosted-automation-user-catalog.md`,按表选 **一个** SOP 介绍或执行。Google 熔断优先 `guard.md`;Bing 走 `hosted-automation-bing.md`;Yandex 走 `hosted-automation-yandex.md`。**禁止**在无关任务(查余额、出报告、开户等)主动灌输自动化目录。
|
|
289
289
|
|
|
290
290
|
---
|
|
291
291
|
|
|
@@ -208,11 +208,13 @@
|
|
|
208
208
|
## W12 · 日 / 周巡检
|
|
209
209
|
|
|
210
210
|
- **触发**:日常/每周快速了解各媒体余额、消耗、预警与报告/智投状态。
|
|
211
|
-
- **必读**:`references/accounts/accounts-balance-stats.md`;首页看板口径见 `references/misc/tso-home.md
|
|
211
|
+
- **必读**:`references/accounts/accounts-balance-stats.md`;首页看板口径见 `references/misc/tso-home.md`。Google 超预算/空耗熔断另读 `references/operations/guard.md`。Bing / Yandex 只读巡检读 `hosted-automation-bing.md` / `hosted-automation-yandex.md`。
|
|
212
212
|
- **步骤**:
|
|
213
213
|
1. 余额:`list-accounts -m <媒体> --json-out ./snap` → `balance -m <媒体> -a <mediaCustomerId,...>`(多户续航预警走 **P2**)。
|
|
214
|
-
2. 消耗:`stats -m <媒体> -a <id> --start <昨天/上周一> --end <昨天/上周日>`(多户汇总走 **P3
|
|
214
|
+
2. 消耗:`stats -m <媒体> -a <id> --start <昨天/上周一> --end <昨天/上周日>`(多户汇总走 **P3**;Bing/Yandex **今天**不要用 `stats`)。
|
|
215
215
|
3. Google 当日超预算/空耗熔断(若用户要求):`guard budget-circuit` / `guard zero-conv -m Google --json-out`(**禁止**逐户 for-loop)。
|
|
216
|
-
4.
|
|
217
|
-
5.
|
|
218
|
-
|
|
216
|
+
4. Bing 巡检(若用户要求):按 `hosted-automation-bing.md` 跑封禁/拒审/当日超预算或空耗预警(只告警,不暂停)。
|
|
217
|
+
5. Yandex 巡检(若用户要求):按 `hosted-automation-yandex.md` 跑 `balance-scan` / `accounts-digest` / `yandex-analysis`(只告警)。
|
|
218
|
+
6. 预警触发:`forewarning records -m <媒体> --start <S>`(见 **W10**)。
|
|
219
|
+
7. 智投/线索(按需):`ad batch list --state Failed/HasFailed`(**W4**)、`clue …`(**W11**)、`optimize list/records`(**W6**)。
|
|
220
|
+
- **产物**:要与网页首页看板数字完全一致(聚合口径)时引导打开首页(`tso-home.md`);CLI 给的是单账户粒度的近似巡检;Google 熔断须交付命中表或显式「无命中」;Bing/Yandex 巡检交付告警列表(不能写成已自动暂停)。
|
|
@@ -1,27 +1,20 @@
|
|
|
1
|
-
# guard —— Google
|
|
1
|
+
# guard —— Google 全户熔断扫描(只读)
|
|
2
2
|
|
|
3
3
|
> 流程见 `hosted-automation-user-catalog.md`(预算/空耗自控)。单户排障仍可用 `ad campaigns` / `ad groups`。
|
|
4
|
-
> **仅 Google
|
|
5
|
-
|
|
6
|
-
## Contents
|
|
7
|
-
|
|
8
|
-
- 何时用
|
|
9
|
-
- budget-circuit(超预算)
|
|
10
|
-
- zero-conv(空耗)
|
|
11
|
-
- 输出与交付
|
|
12
|
-
- 与旧编排对照
|
|
13
|
-
|
|
14
|
-
---
|
|
4
|
+
> **仅 Google**。本命令**只扫描列出命中,不会暂停任何账户/系列/组/创意**。
|
|
5
|
+
> 若要对某个命中对象停投,必须对该账户单独执行 `ad campaign-status` / `ad adgroup-status` / `ad ad-status`(带 `--commit`),以便写审计能记清「改了哪个账户的哪个对象」。
|
|
15
6
|
|
|
16
7
|
## 何时用
|
|
17
8
|
|
|
18
9
|
| 用户话术 | 命令 |
|
|
19
10
|
| -------------------------------------------------- | -------------------------------------- |
|
|
20
|
-
| 所有账户系列当日花费 ≥ 日预算 110% →
|
|
21
|
-
|
|
|
11
|
+
| 所有账户系列当日花费 ≥ 日预算 110% → **列出** | `guard budget-circuit` |
|
|
12
|
+
| 空耗:花 ≥ 目标 CPA × N 且转化 0 → **列出**组/创意 | `guard zero-conv` |
|
|
13
|
+
| 确认后暂停某一户的某一条系列/组/创意 | `ad campaign-status` / `adgroup-status` / `ad-status` |
|
|
22
14
|
| 只查某一户 / 改预算后复核单系列 | 仍用 `ad campaigns -a … --start=--end` |
|
|
23
15
|
|
|
24
|
-
**禁止**外层 for-loop:`list-accounts` × 多媒体再逐户 `ad campaigns`
|
|
16
|
+
**禁止**外层 for-loop:`list-accounts` × 多媒体再逐户 `ad campaigns` 做全户扫描。
|
|
17
|
+
**禁止**指望 `guard` 一条命令批量暂停——没有 `--apply`,也不会改投放状态。
|
|
25
18
|
|
|
26
19
|
---
|
|
27
20
|
|
|
@@ -32,9 +25,9 @@ siluzan-tso guard budget-circuit -m Google \
|
|
|
32
25
|
[--date YYYY-MM-DD] [--ratio 1.1] [-a id1,id2] \
|
|
33
26
|
--json-out ./snap-guard
|
|
34
27
|
|
|
35
|
-
#
|
|
36
|
-
siluzan-tso
|
|
37
|
-
--
|
|
28
|
+
# 确认某条命中后,对该账户单独暂停(须 --commit,写审计记这一次)
|
|
29
|
+
siluzan-tso ad campaign-status -a <mediaCustomerId> --id <campaignId> \
|
|
30
|
+
--status Paused --commit "超预算熔断 2026-07-28"
|
|
38
31
|
```
|
|
39
32
|
|
|
40
33
|
| 选项 | 说明 |
|
|
@@ -44,7 +37,6 @@ siluzan-tso guard budget-circuit -m Google --date 2026-07-28 --ratio 1.1 \
|
|
|
44
37
|
| `--date` | 统计日;默认 Asia/Shanghai 今天;**强制当日 spend**(start=end) |
|
|
45
38
|
| `--ratio` | 默认 `1.1`(建议 1.10–1.20) |
|
|
46
39
|
| `--status` | 默认只查 `Enabled`;传 `*` 不过滤 |
|
|
47
|
-
| `--apply` | 默认 dry-run;加此旗才 `Paused` |
|
|
48
40
|
| `--json-out` | Agent 必带 |
|
|
49
41
|
|
|
50
42
|
命中条件:`budget > 0` 且 `spend >= budget * ratio`(`budget`/`spend` 均为元;`spend` 为该日合计)。
|
|
@@ -59,8 +51,9 @@ siluzan-tso guard zero-conv -m Google \
|
|
|
59
51
|
[--fallback-target-cpa <元>] \
|
|
60
52
|
--json-out ./snap-guard
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
# 确认某条命中后,对该账户单独暂停
|
|
55
|
+
siluzan-tso ad adgroup-status -a <mediaCustomerId> --id <adGroupId> \
|
|
56
|
+
--status Paused --commit "空耗熔断 2026-07-28"
|
|
64
57
|
```
|
|
65
58
|
|
|
66
59
|
| 选项 | 说明 |
|
|
@@ -68,18 +61,16 @@ siluzan-tso guard zero-conv -m Google --cpa-multiple 3 --apply \
|
|
|
68
61
|
| `--cpa-multiple` | 默认 `3` |
|
|
69
62
|
| `--level` | 默认 `adgroup`;`ad`/`both` 需 `--fallback-target-cpa`(创意无组级 CPA 字段) |
|
|
70
63
|
| `--fallback-target-cpa` | 组无 `targetCpaAmountYuan` 时回退;缺失则进 `skipped[]` |
|
|
71
|
-
| `--
|
|
64
|
+
| `--json-out` | Agent 必带 |
|
|
72
65
|
|
|
73
|
-
命中:`conversions === 0` 且 `spend >= targetCpaYuan * N
|
|
66
|
+
命中:`conversions === 0` 且 `spend >= targetCpaYuan * N`。摘要文案为 **「空耗熔断」**(宿主发 P1 时用此文案;CLI 不代发通知)。
|
|
74
67
|
|
|
75
68
|
---
|
|
76
69
|
|
|
77
70
|
## 输出与交付
|
|
78
71
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
- stdout:一行摘要 JSON(若 `--json-out`)+ **人类可读命中表**(无命中也打印「无命中」——巡检必须收口)
|
|
82
|
-
- dry-run 命中后提示追加 `--apply --commit …`
|
|
72
|
+
- `--json-out` 落盘命中表;无命中也必须收口(打印「无命中」)
|
|
73
|
+
- 命中后用 **逐账户** `ad *-status` 暂停,**没有** `--apply`
|
|
83
74
|
|
|
84
75
|
恢复:人工加预算 / 改出价后,用 `ad campaign-status|adgroup-status|ad-status … --status Enabled`(或网页),**禁止**无人值守自动恢复。
|
|
85
76
|
|
|
@@ -91,4 +82,4 @@ siluzan-tso guard zero-conv -m Google --cpa-multiple 3 --apply \
|
|
|
91
82
|
| -------------------------------------------------------- | -------------------------------- |
|
|
92
83
|
| 6 媒体 list-accounts → 逐户 ad campaigns → 脚本比 budget | `guard budget-circuit -m Google` |
|
|
93
84
|
| 逐户 ad groups + 手写阈值 | `guard zero-conv -m Google` |
|
|
94
|
-
| `ad campaigns -m Google`(非法) | 单户用 `-a
|
|
85
|
+
| `ad campaigns -m Google`(非法) | 单户用 `-a`;全户扫描用 `guard` |
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# 宿主编排:Bing(BingV2)只读巡检
|
|
2
|
+
|
|
3
|
+
> **何时 Read**:用户要 Bing / Microsoft Ads 自动化、巡检、熔断、封禁、拒审、落地页、超预算或空耗。Google 熔断走 `references/operations/guard.md`。
|
|
4
|
+
> **能做什么**:拉数、对比阈值、宿主告警。
|
|
5
|
+
> **不能做什么**:暂停系列/组/广告、改价、改预算。没有对应写命令,**禁止**假装已执行熔断。
|
|
6
|
+
|
|
7
|
+
**前置**:已 `siluzan-tso login`,并用 `list-accounts -m BingV2 --json-out ./snap` 确认 `mediaCustomerId`(数字)。
|
|
8
|
+
|
|
9
|
+
**硬约束**:
|
|
10
|
+
|
|
11
|
+
- `guard` **只支持 Google**。禁止 `guard … -m BingV2`。
|
|
12
|
+
- 周期报表(不带 `--aggregation`)日期**不能含今天/昨天**;省略则默认截至前天的近 7 天。
|
|
13
|
+
- 当日花费、近两小时 CPA 必须显式传 `--aggregation Daily|Hourly`,且 `--sections` 只能是 `campaigns` / `ad-groups` / `ads`。
|
|
14
|
+
- Hourly 时间桶是**太平洋时区**,和北京日期可能差一天;阈值按 `timePeriod` 对齐,不要按北京日历硬切。
|
|
15
|
+
- 花费/转化用 `bing-analysis run --sections …`;日预算/启停状态用 `campaign-entities`。两套数据不要混成一行。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. 余额 / 额度续航
|
|
20
|
+
|
|
21
|
+
多户先扫 TSO 余额(截至昨天的日均,**不含当天**):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
siluzan-tso balance-scan -m BingV2 --threshold-days 7 --json-out ./snap-bing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
有插入订单(IO)的户再核对官方额度:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
siluzan-tso bing-analysis insertion-orders -a <mediaCustomerId> --json-out ./snap-bing
|
|
31
|
+
siluzan-tso bing-analysis monthly-spend -a <mediaCustomerId> --json-out ./snap-bing
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
无 IO 时没有额度上限,只看 `monthly-spend` 与 `balance-scan`。命中续航/额度不足 → 宿主通知充值或补 IO;CLI **不能**自动充值。
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. 账户封禁
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
siluzan-tso bing-analysis account-status -a <mediaCustomerId> --json-out ./snap-bing
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`status` 不是 `Active` → 宿主发 **告警P1**(账户、状态原文)。不能在 CLI 里解封。
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 3. 素材拒审
|
|
49
|
+
|
|
50
|
+
全账户巡检用 `bulk-ads`,**禁止**按系列循环 `ad-entities`。首次全量;下次把上次响应的 `syncTimeUtc` 原样回传做增量(最早回溯 30 天):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
siluzan-tso bing-analysis bulk-ads -a <mediaCustomerId> --editorial-status Disapproved --json-out ./snap-bing
|
|
54
|
+
siluzan-tso bing-analysis bulk-ads -a <mediaCustomerId> --editorial-status Disapproved --last-sync-time-utc <上次syncTimeUtc> --json-out ./snap-bing
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`bulk-ads` 是官方异步下载,大账户可能要几分钟,适合定时任务。命中 → 告警广告 ID / 系列 / 审核状态;改创意、申诉在 Bing 后台做。
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. 落地页死链
|
|
62
|
+
|
|
63
|
+
同样用 `bulk-ads` 拉广告上的到达网址(不传 `--editorial-status` 则全量)。CLI **不**发 HTTP。宿主对 URL 做 HEAD/GET,4xx/5xx 或超时 → 告警。不要为了探活去遍历 `ad-entities`。
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 5. 当日超预算(只预警,不暂停)
|
|
68
|
+
|
|
69
|
+
1. 拉系列日预算:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
siluzan-tso bing-analysis campaign-entities -a <mediaCustomerId> --json-out ./snap-bing
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
2. 拉**当天**花费(必须 `--aggregation Daily`,日期可含今天):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
siluzan-tso bing-analysis run -a <mediaCustomerId> --json-out ./snap-bing --sections campaigns \
|
|
79
|
+
--start <当日YYYY-MM-DD> --end <当日YYYY-MM-DD> --aggregation Daily
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
3. 按同一 `campaignId` 对齐:当日花费对照 `dailyBudget`。`isSharedBudget=true` 时 `dailyBudget` 是共享总额,不要当成单系列上限。建议阈值 **110%–120%**(缓冲报表延迟)。
|
|
83
|
+
4. 超阈值 → 宿主告警系列名、花费、日预算。**禁止**调用 `ad campaign-status`(那是 Google 命令)。恢复加预算或暂停由人工在 Bing 后台处理。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 6. CPA 飙升 / 空耗(只预警,不降价、不暂停)
|
|
88
|
+
|
|
89
|
+
近实时(近两小时或当日)用 Hourly / Daily,不要用默认周期报表冒充「今天」:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 当日组级花费与转化
|
|
93
|
+
siluzan-tso bing-analysis run -a <mediaCustomerId> --json-out ./snap-bing --sections ad-groups \
|
|
94
|
+
--start <当日> --end <当日> --aggregation Daily
|
|
95
|
+
|
|
96
|
+
# 近两小时(按 adGroupId 取最近两个整点相加再算)
|
|
97
|
+
siluzan-tso bing-analysis run -a <mediaCustomerId> --json-out ./snap-bing --sections ad-groups \
|
|
98
|
+
--start <起> --end <止> --aggregation Hourly
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
宿主侧:
|
|
102
|
+
|
|
103
|
+
- 有转化:`CPA = 花费 / 转化`;超过约定目标倍数 → 告警「CPA 飙升」。
|
|
104
|
+
- 花费已达「目标 CPA × N」且转化为 0 → 告警「空耗预警」(文案不要写成「已熔断」)。
|
|
105
|
+
|
|
106
|
+
目标 CPA 以账户约定或系列出价策略为准;落盘里没有就不要猜。拉今天数据**不要**显式传 `--return-only-complete-data true`。
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 7. 多账户消耗 / 零转化巡检(截至昨天)
|
|
111
|
+
|
|
112
|
+
`accounts-digest` / `stats` 走每日同步,**今天为 0**,只适合回看已结束的日期:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
siluzan-tso accounts-digest -m BingV2 --start <S> --end <D> --zero-conversions --json-out ./snap-bing
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
看当天必须走第 5、6 步的 `--aggregation` 报表。
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# 异常监控巡检:`siluzan-tso` CLI `--json-out` 落盘 JSON 键名与命令
|
|
2
2
|
|
|
3
|
-
> **主题索引**:[`references/operations/hosted-automation-scenarios.md`](references/operations/hosted-automation-scenarios.md)
|
|
4
|
-
> **编排责任**:定时、HTTP 探活、通知等在宿主。本页只列
|
|
3
|
+
> **主题索引**:[`references/operations/hosted-automation-scenarios.md`](references/operations/hosted-automation-scenarios.md)
|
|
4
|
+
> **编排责任**:定时、HTTP 探活、通知等在宿主。本页只列 **Google 读数命令与常见 JSON 键名**。
|
|
5
5
|
> **统计日 / 时区**:与自控场景相同,见 [`references/operations/hosted-automation-self-control.md`](references/operations/hosted-automation-self-control.md)「统计日与今日」。
|
|
6
|
+
> Bing / Yandex 巡检步骤见 `hosted-automation-bing.md` / `hosted-automation-yandex.md`,不要套用本页 Google 键名。
|
|
6
7
|
|
|
7
8
|
宿主做定时巡检时,**只以当次 CLI 落盘 JSON 键名为准**(读命令统一 **`--json-out <dir>`**,以**落盘 `*.json` 文件正文**为准;`google-analysis` 等同理)。Google Ads API 文档里的资源名(如 `billing_setup`、`account_budget`、`amount_served_micros`)**与本 CLI 输出不是同一套命名**,不要当作本仓库 JSON 的键去解析。若某键缺失,**禁止猜测**:以实际输出为准,或换用 `references/analytics/account-analytics.md` 中的其它子命令。
|
|
8
9
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# 宿主编排:自动优化(Google)— 文档索引
|
|
2
2
|
|
|
3
|
-
> **编排责任**:定时、阈值、多轮状态(如「连续 3 日未改善」)、统计检验、通知(P1/P2)由 **宿主** 实现。
|
|
3
|
+
> **编排责任**:定时、阈值、多轮状态(如「连续 3 日未改善」)、统计检验、通知(P1/P2)由 **宿主** 实现。
|
|
4
4
|
> **本组文档**:说明如何用 `siluzan-tso` **拉检查项**、**执行写操作**、**写后复核**;每条 SOP 独立成文,避免单文件过长。
|
|
5
|
+
> Bing / Yandex 没有降价、暂停、改预算接口,不要套用本组 SOP;巡检见 `hosted-automation-bing.md` / `hosted-automation-yandex.md`。
|
|
5
6
|
|
|
6
7
|
| 文档 | 场景 |
|
|
7
8
|
| -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 宿主编排:文档索引
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **编排责任**:定时、多条件 IF、滑动时间窗、通知(含 P1 /「空耗熔断」文案)由 **OpenClaw / WorkBuddy / Cron** 等宿主实现。
|
|
4
|
+
> **CLI 责任**:单次调用给出检查与(仅 Google 具备的)写操作命令;**不**内置常驻调度或通知渠道。
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
> **CLI 责任**:单次调用下给出检查与写操作所需命令;**不**内置常驻调度或通知渠道。
|
|
6
|
+
按媒体选文档(本文件只做入口)。
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
| 文档 | 内容 |
|
|
9
|
+
| -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10
|
+
| [`references/operations/hosted-automation-user-catalog.md`](references/operations/hosted-automation-user-catalog.md) | **用户向一览**:先看这张表,每行只 Read **一个** SOP |
|
|
11
|
+
| [`references/operations/hosted-automation-self-control.md`](references/operations/hosted-automation-self-control.md) | **Google 三类投放自控**:单日预算熔断、CPA 飙升降价、连续空耗暂停 |
|
|
12
|
+
| [`references/operations/hosted-automation-monitoring-json.md`](references/operations/hosted-automation-monitoring-json.md) | **Google 异常监控**落盘与读数 |
|
|
13
|
+
| [`references/operations/hosted-automation-optimize-index.md`](references/operations/hosted-automation-optimize-index.md) | **Google 自动优化**:差素材降价/关停、高转化扩量、A/B 停输家 |
|
|
14
|
+
| [`references/operations/hosted-automation-bing.md`](references/operations/hosted-automation-bing.md) | **Bing 只读巡检**:余额/IO、封禁、拒审、落地页、当日超预算预警、CPA/空耗预警;**不能**自动暂停/改价 |
|
|
15
|
+
| [`references/operations/hosted-automation-yandex.md`](references/operations/hosted-automation-yandex.md) | **Yandex 只读巡检**:余额、多账户 CPA/零转化、日报花费异动;**不能**自动改投放 |
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
| -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
12
|
-
| [`references/operations/hosted-automation-self-control.md`](references/operations/hosted-automation-self-control.md) | **三类投放自控**:单日预算熔断、CPA 飙升降价、连续空耗暂停;通用约定与常用 JSON 字段表;宿主编排实现清单;与 `forewarning` 的关系 |
|
|
13
|
-
| [`references/operations/hosted-automation-monitoring-json.md`](references/operations/hosted-automation-monitoring-json.md) | **异常监控巡检**:`balance-scan` / `balance` 等 **`--json-out` 落盘**;**`google-analysis --sections overview` / `campaign-hour` / `final-urls`** 与账户分析口径一致时用 **`--json-out <dir>`** 读落盘 `*.json`;拒审相关键名与命令见该文档 |
|
|
14
|
-
| [`references/operations/hosted-automation-optimize-index.md`](references/operations/hosted-automation-optimize-index.md) | **自动优化(宿主编排)**:差素材降价/关停、高转化扩量、A/B 停输家 — 分文件 SOP(含 `ad list` 按日聚合、`google-analysis --sections campaigns` 等) |
|
|
15
|
-
| [`references/operations/hosted-automation-user-catalog.md`](references/operations/hosted-automation-user-catalog.md) | **用户向一览**:预算/ROI 自控、异常监控、自动优化表格(可节选给用户;与上表互补) |
|
|
17
|
+
**必读交叉引用**:
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
- Google 金额与写命令:`references/google-ads/google-ads.md`
|
|
20
|
+
- 各媒体拉数与日期限制:`references/analytics/account-analytics.md`
|
|
21
|
+
- 余额类命令:`references/accounts/accounts-balance-stats.md`
|
|
22
|
+
- `--json-out`:`references/core/tips.md`
|
|
18
23
|
|
|
19
|
-
-
|
|
20
|
-
- 通用读命令 **`--json-out`** 与 Node 过滤:`references/core/tips.md`;**`google-analysis` 账户分析** 用 **`--json-out`**:`references/analytics/account-analytics.md`
|
|
21
|
-
- 写命令语法:`references/google-ads/google-ads.md`
|
|
22
|
-
- 账户/维度分析、时间窗:`references/analytics/account-analytics.md`
|
|
23
|
-
- 余额类命令详解:`references/accounts/accounts-balance-stats.md`
|
|
24
|
-
|
|
25
|
-
**前置**:已 `siluzan-tso login`,并已用 `list-accounts -m Google -k <mediaCustomerId> --json-out ./snap` 确认账户与 `mediaCustomerId`。
|
|
24
|
+
**前置**:已 `siluzan-tso login`。Google 用 `list-accounts -m Google`;Bing 用 `-m BingV2`(数字 ID);Yandex 用 `-m Yandex`(`porg-…`)。
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# 宿主编排:三类 Google 投放自控(详细步骤)
|
|
2
2
|
|
|
3
|
-
> **主题索引**:[`references/operations/hosted-automation-scenarios.md`](references/operations/hosted-automation-scenarios.md)
|
|
4
|
-
> **编排责任**:定时、多条件 IF、滑动时间窗、通知(含 P1 /「空耗熔断」文案)由 **OpenClaw / WorkBuddy / Cron** 等宿主实现。
|
|
3
|
+
> **主题索引**:[`references/operations/hosted-automation-scenarios.md`](references/operations/hosted-automation-scenarios.md)
|
|
4
|
+
> **编排责任**:定时、多条件 IF、滑动时间窗、通知(含 P1 /「空耗熔断」文案)由 **OpenClaw / WorkBuddy / Cron** 等宿主实现。
|
|
5
5
|
> **本页责任**:说明如何用 `siluzan-tso` **拉检查项**、**执行最终写操作**、**写后复核**。
|
|
6
|
+
> Bing / Yandex **没有**本页写操作,只读巡检见 `hosted-automation-bing.md` / `hosted-automation-yandex.md`。
|
|
6
7
|
|
|
7
8
|
## Contents
|
|
8
9
|
|
|
@@ -57,12 +58,12 @@
|
|
|
57
58
|
|
|
58
59
|
### 首选(全户 / 多户 Google)
|
|
59
60
|
|
|
60
|
-
一条命令扫描名下 Google
|
|
61
|
+
一条命令扫描名下 Google 户并交付命中表(**只读,不暂停**):
|
|
61
62
|
|
|
62
63
|
```bash
|
|
63
64
|
siluzan-tso guard budget-circuit -m Google --date <当日YYYY-MM-DD> --ratio 1.1 --json-out ./snap-guard
|
|
64
|
-
#
|
|
65
|
-
siluzan-tso
|
|
65
|
+
# 确认某条命中后,对该账户单独暂停(写审计记这一次):
|
|
66
|
+
siluzan-tso ad campaign-status -a <mediaCustomerId> --id <campaignId> --status Paused --commit "超预算熔断"
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
参数与落盘字段见 **`references/operations/guard.md`**。**禁止** `list-accounts` 六媒体循环 + 逐户 `ad campaigns`。
|
|
@@ -106,7 +107,7 @@ siluzan-tso ad campaign-status -a <mediaCustomerId> --id <campaignId> --status E
|
|
|
106
107
|
|
|
107
108
|
| 状态 | 说明 |
|
|
108
109
|
| ---- | ---------------------------------------------------------------------------------- |
|
|
109
|
-
| 首选 | `guard budget-circuit -m Google
|
|
110
|
+
| 首选 | `guard budget-circuit -m Google`(全户扫描,只读);暂停用 `ad campaign-status` |
|
|
110
111
|
| 单户 | 读:`ad campaigns --json-out`;写:`ad campaign-status`;复核:再次 `ad campaigns` |
|
|
111
112
|
|
|
112
113
|
---
|
|
@@ -180,10 +181,11 @@ siluzan-tso ad adgroup-edit -a <mediaCustomerId> --id <adGroupId> --max-cpc <主
|
|
|
180
181
|
|
|
181
182
|
```bash
|
|
182
183
|
siluzan-tso guard zero-conv -m Google --date <当日> --cpa-multiple 3 --level adgroup --json-out ./snap-guard
|
|
183
|
-
#
|
|
184
|
+
# 确认某条命中后,对该账户单独暂停;创意维加 --level ad|both --fallback-target-cpa <元>
|
|
185
|
+
siluzan-tso ad adgroup-status -a <mediaCustomerId> --id <adGroupId> --status Paused --commit "空耗熔断"
|
|
184
186
|
```
|
|
185
187
|
|
|
186
|
-
见 **`references/operations/guard.md
|
|
188
|
+
见 **`references/operations/guard.md`**。摘要文案为「空耗熔断」。
|
|
187
189
|
|
|
188
190
|
### 单户排障(可选)
|
|
189
191
|
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
# 宿主编排能力目录
|
|
2
2
|
|
|
3
3
|
> **何时 Read**:用户明确问自动化 / 巡检 / 熔断 / 自控 / 异常监控 / 自动优化时。其他任务**跳过**本文件。
|
|
4
|
-
> **怎么读**:下表每行只 Read **一个**「SOP
|
|
4
|
+
> **怎么读**:下表每行只 Read **一个**「SOP」列路径。Google 金额口径见 `references/google-ads/google-ads.md` § Gotchas + `references/accounts/currency.md`。
|
|
5
5
|
> 宿主侧告警优先级写作 **告警P1**(勿与 Playbook **P1** 账户诊断混淆)。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- 预算与 ROI 自控
|
|
10
|
-
- 异常监控
|
|
11
|
-
- 自动优化
|
|
7
|
+
`guard` 与自动暂停/改价**只支持 Google**。Bing / Yandex 只能拉数告警,步骤见各自 SOP。
|
|
12
8
|
|
|
13
9
|
---
|
|
14
10
|
|
|
15
|
-
##
|
|
11
|
+
## Google:预算与 ROI 自控
|
|
16
12
|
|
|
17
|
-
| 场景 | 自动动作(摘要)
|
|
18
|
-
| ---------------- |
|
|
19
|
-
| 单日预算熔断 | 当日花费相对日预算达阈值 →
|
|
20
|
-
| CPA 飙升自动降价 | 窗内 CPA 超目标 → 下调出价上限
|
|
21
|
-
| 连续空耗自动暂停 | 当日花费达阈值且 0 转化 →
|
|
13
|
+
| 场景 | 自动动作(摘要) | 首选 CLI / SOP(只读一份) |
|
|
14
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
15
|
+
| 单日预算熔断 | 当日花费相对日预算达阈值 → **列出命中**;暂停须逐账户 `ad campaign-status` | **首选** `references/operations/guard.md`(`guard budget-circuit`);细节/单户排障见 `hosted-automation-self-control.md` |
|
|
16
|
+
| CPA 飙升自动降价 | 窗内 CPA 超目标 → 下调出价上限 | `references/operations/hosted-automation-optimize-weak-downbid.md` |
|
|
17
|
+
| 连续空耗自动暂停 | 当日花费达阈值且 0 转化 → **列出命中**;暂停须逐账户 `adgroup-status`/`ad-status`;宿主发 **告警P1**「空耗熔断」 | **首选** `references/operations/guard.md`(`guard zero-conv`);细节见 `hosted-automation-self-control.md` |
|
|
22
18
|
|
|
23
19
|
> **消耗 ≠ 日消耗**:`spend` 为 `--start`~`--end` 合计。`guard` 命令已强制 `--date` 单日;手写 `ad campaigns` 时须 `start=end=当日`。续航日均用 `balance-scan.dailySpend`。
|
|
24
20
|
|
|
25
|
-
##
|
|
21
|
+
## Google:异常监控
|
|
26
22
|
|
|
27
23
|
字段键名以当次 `--json-out` 为准,细则只读:`references/operations/hosted-automation-monitoring-json.md`。
|
|
28
24
|
|
|
@@ -34,7 +30,7 @@
|
|
|
34
30
|
| 花费异动 | `google-analysis --sections campaign-hour` |
|
|
35
31
|
| 余额枯竭 | `balance-scan`(P2) |
|
|
36
32
|
|
|
37
|
-
##
|
|
33
|
+
## Google:自动优化
|
|
38
34
|
|
|
39
35
|
索引(可选):`references/operations/hosted-automation-optimize-index.md`。执行时直接读 SOP:
|
|
40
36
|
|
|
@@ -44,3 +40,28 @@
|
|
|
44
40
|
| 高转化提价扩量 | `references/operations/hosted-automation-optimize-scale.md` |
|
|
45
41
|
| A/B 决出胜者 | `references/operations/hosted-automation-optimize-ab-winner.md` |
|
|
46
42
|
| 异动根因排查 | `references/analytics/account-analytics.md` + 对应 `report-templates/*.md` |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Bing(BingV2):只读巡检
|
|
47
|
+
|
|
48
|
+
全部步骤只读一份:`references/operations/hosted-automation-bing.md`。**不能**自动暂停/改价/改预算。
|
|
49
|
+
|
|
50
|
+
| 场景 | 做什么 | SOP |
|
|
51
|
+
| -------------- | ---------------------------------------------------------------------- | ------------------------------------------------ |
|
|
52
|
+
| 余额 / IO 续航 | `balance-scan -m BingV2`;有 IO 再 `insertion-orders` + `monthly-spend` | `references/operations/hosted-automation-bing.md` |
|
|
53
|
+
| 账户封禁 | `bing-analysis account-status`;非 Active 告警 | 同上 |
|
|
54
|
+
| 素材拒审 | `bing-analysis bulk-ads --editorial-status Disapproved` | 同上 |
|
|
55
|
+
| 落地页死链 | `bulk-ads` 拉 URL,宿主 HTTP 探活 | 同上 |
|
|
56
|
+
| 当日超预算 | `campaign-entities` 日预算 + `run --aggregation Daily` 当日花费;只告警 | 同上 |
|
|
57
|
+
| CPA / 空耗 | `run --aggregation Daily\|Hourly`;只告警,不降价、不暂停 | 同上 |
|
|
58
|
+
|
|
59
|
+
## Yandex:只读巡检
|
|
60
|
+
|
|
61
|
+
全部步骤只读一份:`references/operations/hosted-automation-yandex.md`。**不能**自动改投放;无封禁/拒审/落地页/小时接口。
|
|
62
|
+
|
|
63
|
+
| 场景 | 做什么 | SOP |
|
|
64
|
+
| -------------------- | ---------------------------------------------------------------------- | -------------------------------------------------- |
|
|
65
|
+
| 余额续航 | `balance-scan -m Yandex` | `references/operations/hosted-automation-yandex.md` |
|
|
66
|
+
| 多账户 CPA / 零转化 | `accounts-digest -m Yandex`(截至昨天) | 同上 |
|
|
67
|
+
| 当日/近日花费与 CPA | `yandex-analysis --sections overview,daily,campaigns`(可含今天) | 同上 |
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# 宿主编排:Yandex 只读巡检
|
|
2
|
+
|
|
3
|
+
> **何时 Read**:用户要 Yandex / 直通广告自动化、巡检、熔断、余额或 CPA 预警。Google 熔断走 `references/operations/guard.md`;Bing 走 `hosted-automation-bing.md`。
|
|
4
|
+
> **能做什么**:拉余额、拉日报/周期报表、宿主按阈值告警。
|
|
5
|
+
> **不能做什么**:暂停、改价、改预算、封禁专用接口、拒审列表、落地页列表、小时花费。没有写命令,**禁止**假装已执行熔断。
|
|
6
|
+
|
|
7
|
+
**前置**:已 `siluzan-tso login`,并用 `list-accounts -m Yandex --json-out ./snap` 确认 `mediaCustomerId`(形如 `porg-…`,**不是**纯数字,也不是 `entityId`)。
|
|
8
|
+
|
|
9
|
+
**硬约束**:
|
|
10
|
+
|
|
11
|
+
- `guard` **只支持 Google**。禁止 `guard … -m Yandex`。
|
|
12
|
+
- 没有 `account-status` / `bulk-ads` / `campaign-entities` 这类实体子命令。
|
|
13
|
+
- `yandex-analysis` 日期不能晚于今天;省略则默认近 7 天**含今天**。`search-terms` 只支持近 180 天。
|
|
14
|
+
- `balance-scan` / `accounts-digest` 的消耗是每日同步**截至昨天**;查当天消耗用 `yandex-analysis`,不要用 `stats` 判断今天。
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. 余额续航
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
siluzan-tso balance-scan -m Yandex --threshold-days 7 --json-out ./snap-yandex
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
已知子集加 `-a porg-xxx,porg-yyy`。命中续航/余额不足 → 宿主通知充值。CLI **不能**自动充值。单户复核:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
siluzan-tso balance -m Yandex -a <porg-xxx> --json-out ./snap-yandex
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 2. 多账户消耗 / CPA / 零转化(截至昨天)
|
|
33
|
+
|
|
34
|
+
一条命令扫该媒体全部户(或 `-a` 子集)。区间必须是已结束的日期,**不要把今天当完整日**:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
siluzan-tso accounts-digest -m Yandex --start <S> --end <D> --json-out ./snap-yandex
|
|
38
|
+
siluzan-tso accounts-digest -m Yandex --start <S> --end <D> --zero-conversions --json-out ./snap-yandex
|
|
39
|
+
siluzan-tso accounts-digest -m Yandex --start <S> --end <D> --max-cpa <目标CPA> --json-out ./snap-yandex
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
命中 → 宿主告警账户、区间花费、转化、CPA。不能自动关停。
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 3. 单户当日 / 近日花费与 CPA(可含今天)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
mkdir -p ./snap-yandex
|
|
50
|
+
siluzan-tso yandex-analysis -a <porg-xxx> --json-out ./snap-yandex \
|
|
51
|
+
--start <当日或近几日> --end <当日> --sections overview,daily,campaigns
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
宿主侧:
|
|
55
|
+
|
|
56
|
+
- **日花费异动**:读 `daily` 按日对比前一日或近 7 日均值,超阈值告警。
|
|
57
|
+
- **系列花费 / 预算**:同一窗口读 `campaigns`,用落盘里的花费对照 `budget`;缺字段就不要猜,改用日环比。
|
|
58
|
+
- **CPA**:`花费 / 转化`(转化为 0 不算 CPA,改走空耗判断)。超过约定目标倍数 → 告警。
|
|
59
|
+
- **空耗**:当日(或约定日)花费已达「目标 CPA × N」且转化为 0 → 告警「空耗预警」,文案不要写成「已熔断」。目标 CPA 用落盘 `targetCpa` 或账户约定。
|
|
60
|
+
|
|
61
|
+
没有小时维度,做不了「近两小时 CPA」。
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 4. 周期报告(给人看,不代替巡检告警)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
siluzan-tso yandex-analysis -a <porg-xxx> --start <S> --end <D> --json-out ./snap-yandex
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
出 HTML 按 `report-templates/yandex-period-report.md` 写 narrative 后再 `yandex-analysis render`。自动化任务里报告是可选交付物;阈值告警仍走上面 1–3 步。
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 做不到(勿编造命令)
|
|
76
|
+
|
|
77
|
+
| 场景 | 现状 |
|
|
78
|
+
| -------------- | ----------------------------------------- |
|
|
79
|
+
| 账户封禁专用 | 无;`list-accounts` 状态仅供人工看 |
|
|
80
|
+
| 素材拒审 | 无拒审列表 |
|
|
81
|
+
| 落地页探活 | 无最终到达网址接口 |
|
|
82
|
+
| 小时花费 | 无 |
|
|
83
|
+
| 自动暂停 / 改价 | 无写接口;告警后人工在 Yandex 后台处理 |
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
| `geo` | `{ …, items: GeoRow[] }` | → `tables.geo[]` |
|
|
20
20
|
| `devices` | `{ …, items: DeviceRow[] }` | → `tables.devices[]` |
|
|
21
21
|
|
|
22
|
-
> 金额已为账户币种小数;`ctr` / `conversionRate` 为 **0~1
|
|
22
|
+
> 金额已为账户币种小数;`ctr` / `conversionRate` 为 **0~1 小数**。`roi` 为 **(收益-消耗)/消耗** 的倍数(如 `3.72` 表示利润约 372%),**不是** 0~1,禁止再 ×100;无收益时常为 `-1`(按缺失)。写叙事前先读各维 `*.outline.txt`。
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -492,6 +492,17 @@
|
|
|
492
492
|
return (n * 100).toFixed(2) + "%";
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
+
/**
|
|
496
|
+
* 后端 roi = (Revenue - Spend) / Spend,已是倍数(如 3.72 = 372% 利润),
|
|
497
|
+
* **不是** CTR 那种 0~1。禁止走 pct(),否则 371.96 会显示成 37195.98%。
|
|
498
|
+
* 无收益时网关算成 -1,展示为 —。
|
|
499
|
+
*/
|
|
500
|
+
function fmtRoi(v) {
|
|
501
|
+
const n = toNum(v);
|
|
502
|
+
if (n === undefined || n === -1) return "—";
|
|
503
|
+
return n.toFixed(2) + "%";
|
|
504
|
+
}
|
|
505
|
+
|
|
495
506
|
function num2(v) {
|
|
496
507
|
const n = toNum(v);
|
|
497
508
|
return n === undefined ? "—" : n.toFixed(2);
|
|
@@ -1158,7 +1169,7 @@
|
|
|
1158
1169
|
'</td><td class="num">' +
|
|
1159
1170
|
money(r.costPerConversion, currency) +
|
|
1160
1171
|
'</td><td class="num">' +
|
|
1161
|
-
|
|
1172
|
+
fmtRoi(r.roi) +
|
|
1162
1173
|
'</td><td class="num">' +
|
|
1163
1174
|
pct(r.ctr) +
|
|
1164
1175
|
"</td><td>" +
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
| `geo` | `{ …, items: GeoRow[] }` | → `tables.geo[]` |
|
|
20
20
|
| `devices` | `{ …, items: DeviceRow[] }` | → `tables.devices[]` |
|
|
21
21
|
|
|
22
|
-
> 金额已为账户币种小数;`ctr` / `conversionRate` 为 **0~1
|
|
22
|
+
> 金额已为账户币种小数;`ctr` / `conversionRate` 为 **0~1 小数**。`roi` 为 **(收益-消耗)/消耗** 的倍数(如 `3.72` 表示利润约 372%),**不是** 0~1,禁止再 ×100;无收益时常为 `-1`(按缺失)。写叙事前先读各维 `*.outline.txt`。
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -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.46-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.46-beta.6'
|
|
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.46-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.46-beta.6"
|
|
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"
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"turns": [
|
|
5
5
|
"检查我名下的所有广告账户下所有广告系列的当日花费。如果某个系列的当日花费达到其日预算的 110% 以上,先列出被命中的系列名称、当日花费和日预算(先不要暂停)。用 siluzan-tso,JSON 落盘。这是定时任务,直接执行。"
|
|
6
6
|
],
|
|
7
|
-
"judgeExpectation": "路径:用户要求检查名下所有账户系列当日花费相对日预算达 110%
|
|
7
|
+
"judgeExpectation": "路径:用户要求检查名下所有账户系列当日花费相对日预算达 110% 并列出命中时,应执行 `siluzan-tso guard budget-circuit -m Google`(可带 --date/--ratio/--json-out),**不要**对六媒体 list-accounts 后再逐户 `ad campaigns`。\n`guard` 只扫描不暂停;若用户随后要求停某一条,须对该账户单独执行 `ad campaign-status --status Paused --commit`。输出须收口(命中列表或明确无命中)。",
|
|
8
8
|
"skillMapping": "references/operations/guard.md · budget-circuit",
|
|
9
9
|
"judgeReferencePaths": [
|
|
10
10
|
"references/operations/guard.md",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"turns": [
|
|
5
5
|
"检查我名下的所有广告账户的当日数据。对于当日累计花费已达到目标 CPA 3 倍以上、但转化数为 0 的广告组,先列出(标注「空耗熔断」),先不要暂停。用 siluzan-tso,JSON 落盘,直接执行。"
|
|
6
6
|
],
|
|
7
|
-
"judgeExpectation": "路径:用户要求空耗熔断(当日花费 ≥ 目标 CPA × 3 且转化 0)时,应执行 `siluzan-tso guard zero-conv -m Google`(--cpa-multiple 3、--json-out),结果摘要应体现「空耗熔断」。\n
|
|
7
|
+
"judgeExpectation": "路径:用户要求空耗熔断(当日花费 ≥ 目标 CPA × 3 且转化 0)时,应执行 `siluzan-tso guard zero-conv -m Google`(--cpa-multiple 3、--json-out),结果摘要应体现「空耗熔断」。\n`guard` 只扫描不暂停;禁止 `--apply`。禁止逐户 for-loop `ad groups`。",
|
|
8
8
|
"skillMapping": "references/operations/guard.md · zero-conv",
|
|
9
9
|
"judgeReferencePaths": ["references/operations/guard.md"],
|
|
10
10
|
"commandMustInclude": [["guard", "zero-conv"], ["--json-out"]]
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
"media": "Google",
|
|
8
8
|
"date": "2026-07-28",
|
|
9
9
|
"ratio": 1.1,
|
|
10
|
-
"apply": false,
|
|
11
10
|
"stub": true
|
|
12
11
|
},
|
|
13
12
|
"summary": {
|
|
@@ -15,9 +14,7 @@
|
|
|
15
14
|
"accountCount": 1,
|
|
16
15
|
"checkedCampaigns": 2,
|
|
17
16
|
"hitCount": 1,
|
|
18
|
-
"
|
|
19
|
-
"errorCount": 0,
|
|
20
|
-
"mode": "dry-run"
|
|
17
|
+
"errorCount": 0
|
|
21
18
|
},
|
|
22
19
|
"hits": [
|
|
23
20
|
{
|
|
@@ -27,10 +24,8 @@
|
|
|
27
24
|
"spend": 120,
|
|
28
25
|
"budget": 100,
|
|
29
26
|
"ratio": 1.1,
|
|
30
|
-
"threshold": 110
|
|
31
|
-
"applied": false
|
|
27
|
+
"threshold": 110
|
|
32
28
|
}
|
|
33
29
|
],
|
|
34
|
-
"paused": [],
|
|
35
30
|
"errors": []
|
|
36
31
|
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"date": "2026-07-28",
|
|
9
9
|
"cpaMultiple": 3,
|
|
10
10
|
"level": "adgroup",
|
|
11
|
-
"apply": false,
|
|
12
11
|
"stub": true
|
|
13
12
|
},
|
|
14
13
|
"summary": {
|
|
@@ -16,10 +15,8 @@
|
|
|
16
15
|
"accountCount": 1,
|
|
17
16
|
"checkedObjects": 2,
|
|
18
17
|
"hitCount": 1,
|
|
19
|
-
"pausedCount": 0,
|
|
20
18
|
"skippedCount": 0,
|
|
21
|
-
"errorCount": 0
|
|
22
|
-
"mode": "dry-run"
|
|
19
|
+
"errorCount": 0
|
|
23
20
|
},
|
|
24
21
|
"hits": [
|
|
25
22
|
{
|
|
@@ -31,11 +28,9 @@
|
|
|
31
28
|
"conversions": 0,
|
|
32
29
|
"targetCpaYuan": 100,
|
|
33
30
|
"multiple": 3,
|
|
34
|
-
"threshold": 300
|
|
35
|
-
"applied": false
|
|
31
|
+
"threshold": 300
|
|
36
32
|
}
|
|
37
33
|
],
|
|
38
|
-
"paused": [],
|
|
39
34
|
"skipped": [],
|
|
40
35
|
"errors": []
|
|
41
36
|
}
|