siluzan-tso-cli 1.1.14-beta.1 → 1.1.14-beta.3
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 -3
- package/dist/index.js +214 -21
- package/dist/skill/SKILL.md +71 -24
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/account-analytics.md +52 -2
- package/dist/skill/references/accounts.md +8 -5
- package/dist/skill/references/clue.md +5 -0
- package/dist/skill/references/finance.md +4 -0
- package/dist/skill/references/forewarning.md +6 -0
- package/dist/skill/references/google-ads.md +67 -66
- package/dist/skill/references/hosted-automation-monitoring-json.md +94 -0
- package/dist/skill/references/hosted-automation-optimize-ab-winner.md +69 -0
- package/dist/skill/references/hosted-automation-optimize-index.md +32 -0
- package/dist/skill/references/hosted-automation-optimize-scale.md +90 -0
- package/dist/skill/references/hosted-automation-optimize-weak-downbid.md +94 -0
- package/dist/skill/references/hosted-automation-scenarios.md +22 -0
- package/dist/skill/references/hosted-automation-self-control.md +212 -0
- package/dist/skill/references/open-account-google-ui.md +0 -6
- package/dist/skill/references/reporting.md +2 -0
- package/dist/skill/references/tips.md +6 -0
- package/dist/skill/references/workflows.md +14 -1
- package/dist/skill/report-templates/google-account-diagnosis-report.md +1 -1
- package/dist/skill/report-templates/google-period-report.md +1 -0
- package/eval/cases/accounts-entityid-vs-mediaccustomerid.scenario.json +23 -0
- package/eval/cases/accounts-mcc-bind-inquiry.scenario.json +12 -0
- package/eval/cases/accounts-single-balance-not-bulk.scenario.json +23 -0
- package/eval/cases/budget-display-not-raw-micros.scenario.json +17 -0
- package/eval/cases/clue-meta-leads-json.scenario.json +23 -0
- package/eval/cases/clue-tiktok-leads-json.scenario.json +20 -0
- package/eval/cases/destructive-account-delink-needs-confirm.scenario.json +15 -0
- package/eval/cases/destructive-forewarning-delete-needs-confirm.scenario.json +15 -0
- package/eval/cases/destructive-invoice-apply-needs-confirm.scenario.json +15 -0
- package/eval/cases/destructive-unshare-needs-confirm.scenario.json +9 -0
- package/eval/cases/finance-invoice-info-list.scenario.json +17 -0
- package/eval/cases/forewarning-list-google.scenario.json +20 -0
- package/eval/cases/google-ads-no-structural-without-confirm.scenario.json +12 -0
- package/eval/cases/google-analysis-keywords-route.scenario.json +23 -0
- package/eval/cases/hosted-sop-cpa-spike-downbid.scenario.json +14 -0
- package/eval/cases/hosted-sop-daily-budget-circuit-breaker.scenario.json +13 -0
- package/eval/cases/hosted-sop-empty-spend-pause-p1.scenario.json +14 -0
- package/eval/cases/human-p1-multiturn.scenario.json +17 -0
- package/eval/cases/meta-single-balance-not-bulk.scenario.json +26 -0
- package/eval/cases/open-account-bing-noninteractive.scenario.json +13 -0
- package/eval/cases/open-account-google-noninteractive.scenario.json +12 -0
- package/eval/cases/open-account-tiktok-license-file.scenario.json +12 -0
- package/eval/cases/optimize-list-by-account.scenario.json +17 -0
- package/eval/cases/p1-single-account-profile.scenario.json +20 -0
- package/eval/cases/p2-balance-scan-bulk.scenario.json +18 -0
- package/eval/cases/p3-accounts-digest.scenario.json +20 -0
- package/eval/cases/p4-period-report-window.scenario.json +17 -0
- package/eval/cases/report-list-google.scenario.json +20 -0
- package/eval/cases/report-push-list-google.scenario.json +20 -0
- package/eval/cases/reporting-vs-account-analytics-routing.scenario.json +13 -0
- package/eval/cases/setup-login-or-env.scenario.json +12 -0
- package/eval/cases/setup-siluzan-data-permission-env.scenario.json +19 -0
- package/eval/cases/skill-async-poll-guidance.scenario.json +9 -0
- package/eval/cases/skill-optimize-vs-google-ads-distinction.scenario.json +13 -0
- package/eval/cases/tiktok-bc-bind-inquiry.scenario.json +12 -0
- package/eval/cases/time-range-must-ask.scenario.json +16 -0
- package/eval/cases/time-range-user-delegates-default.scenario.json +17 -0
- package/eval/cases/tips-json-filtering.scenario.json +12 -0
- package/eval/cases/tips-large-json-pagination.scenario.json +19 -0
- package/eval/cases/uj-ad-bluetooth-keywords-exclude-cheap-free.scenario.json +9 -0
- package/eval/cases/uj-ad-keywords-camping-tent-outdoor-plan.scenario.json +9 -0
- package/eval/cases/uj-ad-outdoor-campgear-search-plan.scenario.json +12 -0
- package/eval/cases/uj-analytics-30d-pdf-campaign-device-geo.scenario.json +29 -0
- package/eval/cases/uj-analytics-compare-google-tiktok-last-month-roi.scenario.json +17 -0
- package/eval/cases/uj-analytics-google-weekly-trends-campaigns-keywords.scenario.json +20 -0
- package/eval/cases/uj-analytics-report-push-weekly-email.scenario.json +12 -0
- package/eval/cases/uj-finance-invoice-records-this-month.scenario.json +20 -0
- package/eval/cases/uj-life-newbie-siluzan-google-end-to-end.scenario.json +13 -0
- package/eval/cases/uj-ops-google-accounts-list-normal.scenario.json +23 -0
- package/eval/cases/uj-ops-google-yesterday-spend-conversions.scenario.json +23 -0
- package/eval/cases/uj-ops-open-google-b2c-usd-shenzhen.scenario.json +13 -0
- package/eval/cases/uj-ops-pause-worst-adgroup-confirm.scenario.json +12 -0
- package/eval/cases/uj-ops-tiktok-leads-last-week.scenario.json +23 -0
- package/eval/cases/uj-patrol-all-media-balance-stats-forewarning.scenario.json +9 -0
- package/eval/cases/uj-patrol-cpc-spike-adgroups-over-15.scenario.json +18 -0
- package/eval/cases/uj-patrol-forewarning-create-daily-cap-3000.scenario.json +12 -0
- package/eval/cases/uj-patrol-forewarning-trigger-records.scenario.json +23 -0
- package/eval/cases/uj-patrol-google-balances-low.scenario.json +20 -0
- package/eval/cases/uj-roi-full-google-account-diagnosis.scenario.json +9 -0
- package/eval/cases/uj-roi-keywords-high-cpa-low-cvr-triage.scenario.json +9 -0
- package/eval/cases/uj-roi-optimize-records-then-execute-cautiously.scenario.json +20 -0
- package/eval/cases/uj-roi-search-terms-add-negative-keywords.scenario.json +23 -0
- package/eval/stub-fixtures/accounts-digest.json +33 -0
- package/eval/stub-fixtures/ad-campaigns.json +14 -0
- package/eval/stub-fixtures/balance-meta.json +6 -0
- package/eval/stub-fixtures/balance-scan.json +21 -0
- package/eval/stub-fixtures/balance.json +6 -0
- package/eval/stub-fixtures/clue-meta.json +7 -0
- package/eval/stub-fixtures/clue-tiktok.json +7 -0
- package/eval/stub-fixtures/forewarning-create-ok.json +1 -0
- package/eval/stub-fixtures/forewarning-records.json +7 -0
- package/eval/stub-fixtures/generic-ok.json +1 -0
- package/eval/stub-fixtures/google-analysis-search-terms.json +10 -0
- package/eval/stub-fixtures/google-analysis.json +7 -0
- package/eval/stub-fixtures/invoice-billable.json +7 -0
- package/eval/stub-fixtures/invoice-info-list.json +13 -0
- package/eval/stub-fixtures/invoice-list.json +10 -0
- package/eval/stub-fixtures/list-accounts.json +13 -0
- package/eval/stub-fixtures/optimize-list.json +7 -0
- package/eval/stub-fixtures/report-push-list.json +7 -0
- package/eval/stub-fixtures/stats.json +9 -0
- package/package.json +5 -1
- package/dist/skill/references/open-account-by-media.md +0 -61
package/README.md
CHANGED
|
@@ -19,8 +19,6 @@
|
|
|
19
19
|
| 项目 | 说明 |
|
|
20
20
|
| --------------- | --------------------------------------------------------------- |
|
|
21
21
|
| API Key / Token | 存储在 `~/.siluzan/config.json`,用于所有 API 调用鉴权 |
|
|
22
|
-
| TSO API | `tso-api.siluzan.com`(生产)/ `tso-api-ci.siluzan.com`(测试) |
|
|
23
|
-
| Google API 网关 | `googleapi.mysiluzan.com` / `googleapi-ci.mysiluzan.com` |
|
|
24
22
|
| 前端页面 | `www.siluzan.com`(充值、激活等浏览器操作) |
|
|
25
23
|
| 错误追踪 | `o605862.ingest.us.sentry.io`(匿名崩溃日志) |
|
|
26
24
|
| 版本检查 | `registry.npmjs.org` |
|
|
@@ -53,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
53
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
54
52
|
```
|
|
55
53
|
|
|
56
|
-
> **注意**:当前为测试版(1.1.14-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.14-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
57
55
|
|
|
58
56
|
| 助手 | 建议 `--ai` |
|
|
59
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -3676,18 +3676,25 @@ var VALID_MEDIA_TYPES2 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwa
|
|
|
3676
3676
|
async function runBalance(opts) {
|
|
3677
3677
|
const config = loadConfig(opts.token);
|
|
3678
3678
|
if (!VALID_MEDIA_TYPES2.includes(opts.media)) {
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3679
|
+
const msg = `\u4E0D\u652F\u6301\u7684\u5A92\u4F53\u7C7B\u578B\uFF1A${opts.media}\uFF08\u53EF\u9009\uFF1A${VALID_MEDIA_TYPES2.join(" | ")}\uFF09`;
|
|
3680
|
+
if (opts.json) {
|
|
3681
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
3682
|
+
process.exit(1);
|
|
3683
|
+
}
|
|
3684
|
+
console.error(`
|
|
3685
|
+
\u274C ${msg}
|
|
3686
|
+
`);
|
|
3685
3687
|
process.exit(1);
|
|
3686
3688
|
}
|
|
3687
3689
|
const media = opts.media;
|
|
3688
3690
|
if (!BALANCE_SUPPORTED_MEDIA.includes(media)) {
|
|
3691
|
+
const msg = `${media} \u6682\u4E0D\u652F\u6301\u4F59\u989D\u67E5\u8BE2`;
|
|
3692
|
+
if (opts.json) {
|
|
3693
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
3694
|
+
process.exit(1);
|
|
3695
|
+
}
|
|
3689
3696
|
console.error(`
|
|
3690
|
-
\u26A0\uFE0F ${
|
|
3697
|
+
\u26A0\uFE0F ${msg}
|
|
3691
3698
|
`);
|
|
3692
3699
|
process.exit(1);
|
|
3693
3700
|
}
|
|
@@ -3707,8 +3714,13 @@ async function runBalance(opts) {
|
|
|
3707
3714
|
opts.verbose
|
|
3708
3715
|
);
|
|
3709
3716
|
} catch (err) {
|
|
3717
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3718
|
+
if (opts.json) {
|
|
3719
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
3720
|
+
process.exit(1);
|
|
3721
|
+
}
|
|
3710
3722
|
console.error(`
|
|
3711
|
-
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
3723
|
+
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${message}
|
|
3712
3724
|
`);
|
|
3713
3725
|
process.exit(1);
|
|
3714
3726
|
}
|
|
@@ -3948,18 +3960,54 @@ async function runBalanceScan(opts) {
|
|
|
3948
3960
|
const CHUNK = 100;
|
|
3949
3961
|
const chunks = [];
|
|
3950
3962
|
for (let i = 0; i < validIds.length; i += CHUNK) chunks.push(validIds.slice(i, i + CHUNK));
|
|
3963
|
+
process.stderr.write(
|
|
3964
|
+
`\u23F3 [balance-scan] \u6709\u6548\u8D26\u6237 ${validIds.length} \u4E2A\uFF0C\u5206 ${chunks.length} \u6279\uFF1B\u4F59\u989D\u4E0E\u8FD1 7 \u65E5\u6D88\u8017\u5E76\u884C\u8BF7\u6C42\uFF08\u5355\u8BF7\u6C42\u6700\u957F\u7EA6 10 \u5206\u949F\uFF09\u3002
|
|
3965
|
+
`
|
|
3966
|
+
);
|
|
3967
|
+
const logBalanceChunk = (idx, ids, m) => {
|
|
3968
|
+
process.stderr.write(
|
|
3969
|
+
` \u2713 [\u4F59\u989D] \u7B2C ${idx + 1}/${chunks.length} \u6279\u5B8C\u6210\uFF08${ids.length} \u6237 \u2192 ${m.size} \u6761\uFF09
|
|
3970
|
+
`
|
|
3971
|
+
);
|
|
3972
|
+
};
|
|
3973
|
+
const logOverviewChunk = (idx, ids, m) => {
|
|
3974
|
+
process.stderr.write(
|
|
3975
|
+
` \u2713 [\u8FD17\u65E5\u6D88\u8017] \u7B2C ${idx + 1}/${chunks.length} \u6279\u5B8C\u6210\uFF08${ids.length} \u6237 \u2192 ${m.size} \u6761\uFF09
|
|
3976
|
+
`
|
|
3977
|
+
);
|
|
3978
|
+
};
|
|
3951
3979
|
const [bMaps, oMaps] = await Promise.all([
|
|
3952
3980
|
Promise.all(
|
|
3953
|
-
chunks.map(
|
|
3954
|
-
(
|
|
3955
|
-
|
|
3981
|
+
chunks.map((ids, chunkIdx) => {
|
|
3982
|
+
process.stderr.write(
|
|
3983
|
+
` \u2192 [\u4F59\u989D] \u7B2C ${chunkIdx + 1}/${chunks.length} \u6279\u8BF7\u6C42\u4E2D\uFF08${ids.length} \u6237\uFF09\u2026
|
|
3984
|
+
`
|
|
3985
|
+
);
|
|
3986
|
+
return fetchBalanceMap(media, ids, config, void 0, void 0, opts.verbose).then(
|
|
3987
|
+
(m) => {
|
|
3988
|
+
logBalanceChunk(chunkIdx, ids, m);
|
|
3989
|
+
return m;
|
|
3990
|
+
}
|
|
3991
|
+
);
|
|
3992
|
+
})
|
|
3956
3993
|
),
|
|
3957
3994
|
Promise.all(
|
|
3958
|
-
chunks.map(
|
|
3959
|
-
(
|
|
3960
|
-
|
|
3995
|
+
chunks.map((ids, chunkIdx) => {
|
|
3996
|
+
process.stderr.write(
|
|
3997
|
+
` \u2192 [\u8FD17\u65E5\u6D88\u8017] \u7B2C ${chunkIdx + 1}/${chunks.length} \u6279\u8BF7\u6C42\u4E2D\uFF08${ids.length} \u6237\uFF09\u2026
|
|
3998
|
+
`
|
|
3999
|
+
);
|
|
4000
|
+
return fetchOverviewMap(media, ids, config, void 0, void 0, opts.verbose).then(
|
|
4001
|
+
(m) => {
|
|
4002
|
+
logOverviewChunk(chunkIdx, ids, m);
|
|
4003
|
+
return m;
|
|
4004
|
+
}
|
|
4005
|
+
);
|
|
4006
|
+
})
|
|
3961
4007
|
)
|
|
3962
4008
|
]);
|
|
4009
|
+
process.stderr.write(`\u23F3 [balance-scan] \u4F59\u989D\u4E0E\u6D88\u8017\u5DF2\u9F50\uFF0C\u6B63\u5728\u6309\u9608\u503C\u7B5B\u9009\u2026
|
|
4010
|
+
`);
|
|
3963
4011
|
for (const m of bMaps) for (const [k, v] of m) balanceMap.set(k, v);
|
|
3964
4012
|
for (const m of oMaps) for (const [k, v] of m) overviewMap.set(k, v);
|
|
3965
4013
|
}
|
|
@@ -4382,8 +4430,13 @@ async function runStats(opts) {
|
|
|
4382
4430
|
try {
|
|
4383
4431
|
raw = await apiFetch2(url, config, {}, opts.verbose);
|
|
4384
4432
|
} catch (err) {
|
|
4433
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4434
|
+
if (opts.json) {
|
|
4435
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
4436
|
+
process.exit(1);
|
|
4437
|
+
}
|
|
4385
4438
|
console.error(`
|
|
4386
|
-
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
4439
|
+
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${message}
|
|
4387
4440
|
`);
|
|
4388
4441
|
process.exit(1);
|
|
4389
4442
|
}
|
|
@@ -5131,6 +5184,12 @@ var SECTIONS = [
|
|
|
5131
5184
|
dateMode: "range",
|
|
5132
5185
|
path: (id) => `/reporting/media-account/${id}/CampaignSectionData`
|
|
5133
5186
|
},
|
|
5187
|
+
{
|
|
5188
|
+
name: "campaign-hour",
|
|
5189
|
+
description: "\u7CFB\u5217\u6309\u5C0F\u65F6 campaign-hour\uFF08Query\uFF1AstartDate\u3001endDate\uFF09",
|
|
5190
|
+
dateMode: "range",
|
|
5191
|
+
path: (id) => `/reporting/media-account/${id}/campaign-hour`
|
|
5192
|
+
},
|
|
5134
5193
|
{
|
|
5135
5194
|
name: "ads",
|
|
5136
5195
|
description: "\u5E7F\u544A\u7EA7\u5217\u8868 admanagement/v2/list",
|
|
@@ -5266,6 +5325,55 @@ async function fetchJson(config, pathWithQuery, verbose) {
|
|
|
5266
5325
|
const url = `${config.googleApiUrl}${pathWithQuery}`;
|
|
5267
5326
|
return apiFetch2(url, config, {}, verbose);
|
|
5268
5327
|
}
|
|
5328
|
+
function assertNever(x, ctx) {
|
|
5329
|
+
throw new Error(`${ctx}\uFF1A\u672A\u5904\u7406\u7684\u5206\u652F ${String(x)}`);
|
|
5330
|
+
}
|
|
5331
|
+
async function fetchGoogleAnalysisSectionJson(config, fullPath, verbose, name) {
|
|
5332
|
+
switch (name) {
|
|
5333
|
+
case "overview":
|
|
5334
|
+
return fetchJson(config, fullPath, verbose);
|
|
5335
|
+
case "keywords":
|
|
5336
|
+
return fetchJson(config, fullPath, verbose);
|
|
5337
|
+
case "search-terms":
|
|
5338
|
+
return fetchJson(config, fullPath, verbose);
|
|
5339
|
+
case "campaigns":
|
|
5340
|
+
return fetchJson(config, fullPath, verbose);
|
|
5341
|
+
case "campaign-hour":
|
|
5342
|
+
return fetchJson(config, fullPath, verbose);
|
|
5343
|
+
case "ads":
|
|
5344
|
+
return fetchJson(config, fullPath, verbose);
|
|
5345
|
+
case "extensions":
|
|
5346
|
+
return fetchJson(config, fullPath, verbose);
|
|
5347
|
+
case "devices":
|
|
5348
|
+
return fetchJson(config, fullPath, verbose);
|
|
5349
|
+
case "geographic":
|
|
5350
|
+
return fetchJson(config, fullPath, verbose);
|
|
5351
|
+
case "audience":
|
|
5352
|
+
return fetchJson(config, fullPath, verbose);
|
|
5353
|
+
case "asset-images":
|
|
5354
|
+
return fetchJson(config, fullPath, verbose);
|
|
5355
|
+
case "videos":
|
|
5356
|
+
return fetchJson(config, fullPath, verbose);
|
|
5357
|
+
case "resource-counts":
|
|
5358
|
+
return fetchJson(config, fullPath, verbose);
|
|
5359
|
+
case "conversion-actions":
|
|
5360
|
+
return fetchJson(config, fullPath, verbose);
|
|
5361
|
+
case "daily-metrics":
|
|
5362
|
+
return fetchJson(config, fullPath, verbose);
|
|
5363
|
+
case "gold-account":
|
|
5364
|
+
return fetchJson(config, fullPath, verbose);
|
|
5365
|
+
case "ads-index":
|
|
5366
|
+
return fetchJson(config, fullPath, verbose);
|
|
5367
|
+
case "final-urls":
|
|
5368
|
+
return fetchJson(config, fullPath, verbose);
|
|
5369
|
+
case "dimension-summary":
|
|
5370
|
+
return fetchJson(config, fullPath, verbose);
|
|
5371
|
+
case "campaign-types":
|
|
5372
|
+
return fetchJson(config, fullPath, verbose);
|
|
5373
|
+
default:
|
|
5374
|
+
return assertNever(name, "google-analysis");
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5269
5377
|
function summarizeHuman(section, data) {
|
|
5270
5378
|
if (data === null || data === void 0) return "\u65E0\u6570\u636E";
|
|
5271
5379
|
if (Array.isArray(data)) return `\u6570\u7EC4\uFF0C\u5171 ${data.length} \u6761`;
|
|
@@ -5336,7 +5444,12 @@ async function runOneSection(def, opts) {
|
|
|
5336
5444
|
);
|
|
5337
5445
|
return;
|
|
5338
5446
|
}
|
|
5339
|
-
const data = await
|
|
5447
|
+
const data = await fetchGoogleAnalysisSectionJson(
|
|
5448
|
+
config,
|
|
5449
|
+
fullPath,
|
|
5450
|
+
!!opts.verbose,
|
|
5451
|
+
def.name
|
|
5452
|
+
);
|
|
5340
5453
|
if (opts.json) {
|
|
5341
5454
|
console.log(JSON.stringify(stripLegacyGoogleFieldsIfV2Present(data), null, 2));
|
|
5342
5455
|
return;
|
|
@@ -7991,6 +8104,53 @@ async function runAdGroupRename(opts) {
|
|
|
7991
8104
|
\u2705 \u5E7F\u544A\u7EC4 ${opts.id} \u5DF2\u6539\u540D\u4E3A\u300C${opts.name}\u300D
|
|
7992
8105
|
`);
|
|
7993
8106
|
}
|
|
8107
|
+
async function runAdGroupEdit(opts) {
|
|
8108
|
+
const hasName = opts.name !== void 0 && opts.name.trim() !== "";
|
|
8109
|
+
const hasMax = opts.maxCPCAmount !== void 0;
|
|
8110
|
+
const hasTcpa = opts.targetCpaAmount !== void 0;
|
|
8111
|
+
if (!hasName && !hasMax && !hasTcpa) {
|
|
8112
|
+
console.error(
|
|
8113
|
+
"\n\u274C \u8BF7\u81F3\u5C11\u6307\u5B9A\u4E00\u9879\u4FEE\u6539\uFF1A--name / --max-cpc / --target-cpa\n"
|
|
8114
|
+
);
|
|
8115
|
+
process.exit(1);
|
|
8116
|
+
}
|
|
8117
|
+
if (hasMax && (!Number.isFinite(opts.maxCPCAmount) || opts.maxCPCAmount < 0)) {
|
|
8118
|
+
console.error("\n\u274C --max-cpc \u987B\u4E3A\u975E\u8D1F\u6570\u5B57\n");
|
|
8119
|
+
process.exit(1);
|
|
8120
|
+
}
|
|
8121
|
+
if (hasTcpa && (!Number.isFinite(opts.targetCpaAmount) || opts.targetCpaAmount < 0)) {
|
|
8122
|
+
console.error("\n\u274C --target-cpa \u987B\u4E3A\u975E\u8D1F\u6570\u5B57\n");
|
|
8123
|
+
process.exit(1);
|
|
8124
|
+
}
|
|
8125
|
+
const config = loadConfig(opts.token);
|
|
8126
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
8127
|
+
const listUrl = adgroupListUrl(googleApiUrl, opts.account, opts.startDate, opts.endDate);
|
|
8128
|
+
let adgroup;
|
|
8129
|
+
try {
|
|
8130
|
+
adgroup = await findItemInList(listUrl, config, opts.id, opts.verbose);
|
|
8131
|
+
} catch (err) {
|
|
8132
|
+
console.error(`
|
|
8133
|
+
\u274C \u67E5\u8BE2\u5E7F\u544A\u7EC4\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
8134
|
+
`);
|
|
8135
|
+
process.exit(1);
|
|
8136
|
+
}
|
|
8137
|
+
const body = { ...adgroup };
|
|
8138
|
+
if (hasName) body["name"] = opts.name.trim();
|
|
8139
|
+
if (hasMax) body["maxCPCAmount"] = Math.round(opts.maxCPCAmount);
|
|
8140
|
+
if (hasTcpa) body["targetCpaAmount"] = Math.round(opts.targetCpaAmount);
|
|
8141
|
+
const putUrl = `${googleApiUrl}/adgroupnmanagement/adgroup/${opts.account}/${opts.id}`;
|
|
8142
|
+
try {
|
|
8143
|
+
await apiFetch2(putUrl, config, { method: "PUT", body: JSON.stringify(body) }, opts.verbose);
|
|
8144
|
+
} catch (err) {
|
|
8145
|
+
console.error(`
|
|
8146
|
+
\u274C \u7F16\u8F91\u5E7F\u544A\u7EC4\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
8147
|
+
`);
|
|
8148
|
+
process.exit(1);
|
|
8149
|
+
}
|
|
8150
|
+
console.log(`
|
|
8151
|
+
\u2705 \u5E7F\u544A\u7EC4 ${opts.id} \u5DF2\u66F4\u65B0
|
|
8152
|
+
`);
|
|
8153
|
+
}
|
|
7994
8154
|
async function runAdEdit(opts) {
|
|
7995
8155
|
const config = await ensureDataPermission(loadConfig(opts.token));
|
|
7996
8156
|
const googleApiUrl = requireGoogleApi(config);
|
|
@@ -9510,8 +9670,13 @@ async function fetchTikTokClues(opts, config) {
|
|
|
9510
9670
|
);
|
|
9511
9671
|
leads = Array.isArray(res) ? res : res.data ?? [];
|
|
9512
9672
|
} catch (err) {
|
|
9673
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9674
|
+
if (opts.json) {
|
|
9675
|
+
console.log(JSON.stringify({ ok: false, error: message, items: [] }, null, 2));
|
|
9676
|
+
process.exit(1);
|
|
9677
|
+
}
|
|
9513
9678
|
console.error(`
|
|
9514
|
-
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
9679
|
+
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${message}
|
|
9515
9680
|
`);
|
|
9516
9681
|
process.exit(1);
|
|
9517
9682
|
}
|
|
@@ -9558,8 +9723,13 @@ async function fetchMetaClues(opts, config) {
|
|
|
9558
9723
|
try {
|
|
9559
9724
|
raw = await apiFetch2(url, config, {}, opts.verbose);
|
|
9560
9725
|
} catch (err) {
|
|
9726
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9727
|
+
if (opts.json) {
|
|
9728
|
+
console.log(JSON.stringify({ ok: false, error: message, items: [] }, null, 2));
|
|
9729
|
+
process.exit(1);
|
|
9730
|
+
}
|
|
9561
9731
|
console.error(`
|
|
9562
|
-
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
9732
|
+
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${message}
|
|
9563
9733
|
`);
|
|
9564
9734
|
process.exit(1);
|
|
9565
9735
|
}
|
|
@@ -12216,14 +12386,14 @@ program.command("accounts-digest").description(
|
|
|
12216
12386
|
program.command("stats").description("\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF09").requiredOption(
|
|
12217
12387
|
"-m, --media <type>",
|
|
12218
12388
|
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2 | Kwai"
|
|
12219
|
-
).option("-a, --accounts <ids>", "\u8D26\u6237 ID\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u7559\u7A7A\u5219\u67E5\u5168\u90E8\u8D26\u6237\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4 7 \u5929\u524D\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4\u6628\u5929\uFF09").option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
12389
|
+
).option("-a, --accounts <ids>", "\u8D26\u6237 ID\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u7559\u7A7A\u5219\u67E5\u5168\u90E8\u8D26\u6237\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4 7 \u5929\u524D\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4\u6628\u5929\uFF09").option("--start-date <date>", "\u540C --start\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option("--end-date <date>", "\u540C --end\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
12220
12390
|
async (opts) => {
|
|
12221
12391
|
await runStats({
|
|
12222
12392
|
token: opts.token,
|
|
12223
12393
|
media: opts.media,
|
|
12224
12394
|
accounts: opts.accounts,
|
|
12225
|
-
startDate: opts.start,
|
|
12226
|
-
endDate: opts.end,
|
|
12395
|
+
startDate: opts.start ?? opts.startDate,
|
|
12396
|
+
endDate: opts.end ?? opts.endDate,
|
|
12227
12397
|
json: opts.json,
|
|
12228
12398
|
verbose: opts.verbose
|
|
12229
12399
|
});
|
|
@@ -13247,6 +13417,29 @@ adCmd.command("adgroup-rename").description("\u4FEE\u6539\u5E7F\u544A\u7EC4\u540
|
|
|
13247
13417
|
});
|
|
13248
13418
|
}
|
|
13249
13419
|
);
|
|
13420
|
+
adCmd.command("adgroup-edit").description("\u7F16\u8F91\u5E7F\u544A\u7EC4\uFF08\u540D\u79F0\u3001\u6700\u9AD8 CPC\u3001\u7EC4\u7EA7\u76EE\u6807 CPA\uFF1B\u81F3\u5C11\u4F20\u4E00\u9879\uFF1B\u4E0E\u7F51\u5173 PUT \u4E00\u81F4\uFF09").requiredOption("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId").requiredOption("--id <adgroupId>", "\u5E7F\u544A\u7EC4 ID").option("--name <name>", "\u65B0\u540D\u79F0").option(
|
|
13421
|
+
"--max-cpc <n>",
|
|
13422
|
+
"\u6700\u9AD8 CPC\uFF0C\u4E0E ad groups --json \u7684 maxCPCAmount \u540C\u53E3\u5F84\uFF08\u4E3B\u5E01\u79CD\u91D1\u989D\xD7100\uFF0C\u89C1 references/google-ads.md\uFF09",
|
|
13423
|
+
parseFloat
|
|
13424
|
+
).option(
|
|
13425
|
+
"--target-cpa <n>",
|
|
13426
|
+
"\u7EC4\u7EA7\u76EE\u6807 CPA\uFF0C\u4E0E ad groups --json \u7684 targetCpaAmount \u540C\u53E3\u5F84\uFF08\xD7100 \u5206\u5355\u4F4D\uFF09",
|
|
13427
|
+
parseFloat
|
|
13428
|
+
).option("--start <date>", "\u5217\u8868\u67E5\u8BE2\u8D77\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u5217\u8868\u67E5\u8BE2\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
13429
|
+
async (opts) => {
|
|
13430
|
+
await runAdGroupEdit({
|
|
13431
|
+
token: opts.token,
|
|
13432
|
+
account: opts.account,
|
|
13433
|
+
id: opts.id,
|
|
13434
|
+
name: opts.name,
|
|
13435
|
+
maxCPCAmount: opts.maxCpc,
|
|
13436
|
+
targetCpaAmount: opts.targetCpa,
|
|
13437
|
+
startDate: opts.start,
|
|
13438
|
+
endDate: opts.end,
|
|
13439
|
+
verbose: opts.verbose
|
|
13440
|
+
});
|
|
13441
|
+
}
|
|
13442
|
+
);
|
|
13250
13443
|
adCmd.command("ad-edit").description(
|
|
13251
13444
|
"\u7F16\u8F91\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A\uFF08RESPONSIVE_SEARCH_AD\uFF09\uFF1A\u6807\u9898/\u63CF\u8FF0/\u843D\u5730\u9875/\u8DEF\u5F84/\u72B6\u6001\uFF1B\u4E0E\u7F51\u9875 PUT admanagement/campaign \u884C\u4E3A\u4E00\u81F4"
|
|
13252
13445
|
).requiredOption("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId").requiredOption("--id <adId>", "\u5E7F\u544A ID").option(
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -50,11 +50,12 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
50
50
|
| 文档 | 功能 |
|
|
51
51
|
|------|------|
|
|
52
52
|
| `references/setup.md` | 安装、登录、配置、环境切换、更新 |
|
|
53
|
-
| `references/workflows.md` |
|
|
53
|
+
| `references/workflows.md` | 多步骤业务流程、跨命令串联;入口指向宿主编排自控详页 |
|
|
54
|
+
| `references/hosted-automation-scenarios.md` | **宿主编排(Google)索引**;自控见 `references/hosted-automation-self-control.md`;监控见 `references/hosted-automation-monitoring-json.md`;**自动优化 SOP** 见 `references/hosted-automation-optimize-index.md` |
|
|
54
55
|
| `references/tips.md` | `--json`、Node 过滤、分页与调试技巧 |
|
|
55
56
|
| `references/accounts.md` | 账户列表、余额、消耗、开户记录、授权/解绑/分享/MCC/BC/BM/邮箱授权 |
|
|
56
57
|
| `references/open-account-by-media.md` | 各媒体开户、参数与资料要求 |
|
|
57
|
-
| `references/google-ads.md` | Google Ads
|
|
58
|
+
| `references/google-ads.md` | Google Ads 创建、修改、优化与管理主流程;**含 `ad list` / `google-analysis ads` 的 `--json` 拒审字段**(`policyApprovalStatusV2`、`approvalStatusDetails` 等,见该文档「拒审与政策字段」) |
|
|
58
59
|
| `references/reporting.md` | Siluzan TSO 优化报告(Google/TikTok)的生成、推送与查看 |
|
|
59
60
|
| `references/account-analytics.md` | 广告平台账户分析数据拉取与分析/诊断报告模板 |
|
|
60
61
|
| `references/optimize.md` | AI 优化建议记录、详情与历史查询 |
|
|
@@ -65,6 +66,27 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
65
66
|
|
|
66
67
|
---
|
|
67
68
|
|
|
69
|
+
## 职责划分
|
|
70
|
+
|
|
71
|
+
**定位**:`siluzan-tso` + 本 Skill 提供 **可组合的读能力(检查项)** 与 **可验证的写能力(最终操作)**;**不负责**在进程内长期驻留、定时轮询、复合条件规则引擎、或替代宿主的通知渠道。
|
|
72
|
+
|
|
73
|
+
| 由 **本 Skill + CLI** 保证 | 由 **宿主客户端 / 外部调度** 负责 |
|
|
74
|
+
|---------------------------|-----------------------------------|
|
|
75
|
+
| 单次/按需调用下,命令能拉取验证所需的 **JSON 字段**(`--json`、分页见 `references/tips.md`) | **何时**跑一轮检查(cron、事件、对话触发) |
|
|
76
|
+
| 写操作命令语义清晰,且文档给出 **写后如何用读命令复核**(成对验证) | **IF 条件**(多指标 AND/OR、滑动时间窗、相对预算比例等)的计算与决策 |
|
|
77
|
+
| 金额与 ID 口径与文档一致(`*Display`、`entityId` vs `mediaCustomerId` 等硬规范) | 命中后的 **触达**(钉钉/飞书/Slack 等)与内部 **P1/工单** 流程 |
|
|
78
|
+
| `references/google-ads.md` 等与命令、字段含义对齐 | 多账户、多系列的 **批处理循环**、限速、失败重试策略 |
|
|
79
|
+
|
|
80
|
+
**宿主集成时的推荐约定**:
|
|
81
|
+
|
|
82
|
+
1. **监控与编排**:配置定时或事件;每轮用本 Skill 指明的命令拉数,在宿主侧用脚本 / `node -e` 做条件判断。
|
|
83
|
+
2. **执行写操作**:仍遵守本 Skill **计划 →(按策略)确认 → 执行 → 验证**;若宿主策略为「全自动写」,须由**用户或配置**显式授权,避免与默认安全规范冲突。
|
|
84
|
+
3. **验证**:每次写入后,用文档中的 **读命令对同一 `id` 再拉一次**(例如 `ad campaign-status` 后 `ad campaigns --json` 看 `statusV2`;`adgroup-edit` 后 `ad groups --json` 看 `maxCPCAmount` / `targetCpaAmount`)。
|
|
85
|
+
4. **`forewarning`**:仍是丝路赞侧 **微信通知** 的可选通道;宿主已有独立通知 skill 时,**不必**重复依赖 `forewarning` 完成「告警」——二者可并行或只选其一。
|
|
86
|
+
|
|
87
|
+
更具体的 **检查项 ↔ 命令** 见 **`references/hosted-automation-self-control.md`**(三类自控);异常监控 **`--json` 键名** 见 **`references/hosted-automation-monitoring-json.md`**;**自动优化(降价/扩量/A/B)** 见 **`references/hosted-automation-optimize-index.md`**(分文件 SOP);主题入口 **`references/hosted-automation-scenarios.md`**。总览见 **`references/workflows.md`**「宿主编排下的投放自控」。
|
|
88
|
+
|
|
89
|
+
|
|
68
90
|
## Skill要如何使用
|
|
69
91
|
|
|
70
92
|
### 报告的生成
|
|
@@ -89,7 +111,7 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
89
111
|
- Google广告优化记录功能(`references/optimize.md`),这个也跟优化报告类似,你调用接口,Siluzan平台按照一定的优化逻辑自动执行,你只能查询到结果,不能控制优化流程 注意不要与`google-ads.md`中的优化流程混淆两个是互相独立的功能,`references/google-ads.md`中的优化功能更为强大,在实际的优化过程中,也推荐使用`references/google-ads.md`中提供的内容
|
|
90
112
|
- TikTok / Meta 线索表单请阅读:`references/clue.md`
|
|
91
113
|
- Siluzan平台提供的预警功能请阅读:`references/forewarning.md`
|
|
92
|
-
- 预警由Siluzan
|
|
114
|
+
- 预警由 Siluzan 平台发送,当前仅支持微信推送。若监控与通知由 **OpenClaw / WorkBuddy 等宿主**承担,可将 `forewarning` 仅作补充或不用;自定义触达仍可用宿主插件 / skill + 定时任务(见上文职责划分)。
|
|
93
115
|
- 转账、开票、发票抬头、充值网页引导请阅读:`references/finance.md`
|
|
94
116
|
-
|
|
95
117
|
|
|
@@ -126,7 +148,9 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
126
148
|
- **出报告时账户状态 ≠ 广告系列状态**:`stats` / `balance` / `list-accounts` 中的 `status`(如 Enabled)只表示**广告账户**关联/可用,**绝不能**据此填写或推断**各广告系列**是否「启用/在投」。已暂停或移除的系列若被写成启用,属于严重错误。系列是否启用**必须**来自 `ad campaigns`(或系列维报表中的系列状态)。详见 `references/account-analytics.md`「账户状态 ≠ 广告系列状态」。
|
|
127
149
|
- **不确定时读文档**:遇到不熟悉的命令,先读对应 references 文件或使用-h查看命令帮助,不要猜参数。
|
|
128
150
|
- **先查账户再操作**:对具体账户做操作前,先通过 `list-accounts -m [mediaType] -k [mediaCustomerId]` 确认。特别是不确定是Google/Bing/TikTok这些媒体平台中的哪一个的时候
|
|
129
|
-
- **使用 --json 处理数据**:需对返回数据做计算或筛选时,加 `--json`,再用 `node -e` 过滤提取(见 `references/tips.md
|
|
151
|
+
- **使用 --json 处理数据**:需对返回数据做计算或筛选时,加 `--json`,再用 `node -e` 过滤提取(见 `references/tips.md`)。若用户**已有一份 JSON**(文件或剪贴板),只问如何筛选时:优先给「stdin / 读本地文件 + `node -e`」的通用写法,不必默认再跑一遍业务命令。
|
|
152
|
+
- **CLI 输出忠实**:向用户引用 JSON 时,账户 ID、金额等须与**本次命令 stdout 一致**,不得换成别的示例 ID。禁止编造「stub/示例环境/登录异常」等**未在 CLI 输出或 stderr 中出现**的解释;`data` 为空时只说明「当前返回无记录」并附上原始 JSON。
|
|
153
|
+
- **用户明确要求原始 JSON**:须在回复中给出 CLI 返回的 JSON(或完整代码块),不得以长篇推测替代交付。
|
|
130
154
|
- **不要猜测账户 ID**:`entityId` ≠ `mediaCustomerId`,两者均来自 `list-accounts`。
|
|
131
155
|
- **媒体类型区分大小写**:`Google`、`TikTok`、`MetaAd`、`BingV2`、`Kwai`。
|
|
132
156
|
- **命令透明性**:以简洁的方式向用户说明即将执行的操作意图(如「正在查询您的 Google 账户列表」「正在为账户 xxx 创建预警规则」),让用户了解操作进度。用户主动要求查看执行细节时,应如实提供完整命令。
|
|
@@ -142,9 +166,22 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
142
166
|
> (A)最近完整自然周(周一到周日)
|
|
143
167
|
> (B)本月 1 号到昨天
|
|
144
168
|
> (C)自定义起止日(请告诉我 `YYYY-MM-DD` 起止)
|
|
145
|
-
2.
|
|
169
|
+
2. 用户给出范围后,**在报告首行显式标注** `统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:XXX)`(与 `references/account-analytics.md` 一致),与调用参数保持完全一致。
|
|
146
170
|
3. **只有在用户明确说"按你默认来 / 你决定"**时,才使用下方默认值白名单。
|
|
147
171
|
|
|
172
|
+
### 时间范围反问的例外(不要机械套用到下列任务)
|
|
173
|
+
|
|
174
|
+
- **`list-accounts` 全量**:用户要「所有 Google 账户」且 JSON 时,看返回里的 `total` / `page` / `pageSize`;若 `itemCount < total`,须翻页(增大 `--page-size` 或循环 `--page`)或说明**当前仅为第 N 页**,不得把单页当成全量结论。
|
|
175
|
+
- **「昨天」单日 stats**:用户已给出 Google `mediaCustomerId` 且只说「昨天」时:默认按 **`Asia/Shanghai` 日历日**换算昨日起止;**先** `list-accounts -m Google -k <id> --quick --json` **再** `stats -m Google -a <id> --start … --end … --json`,不要为时区再打断一轮(除非用户明确要求 UTC/其他时区)。
|
|
176
|
+
- **仅持有 `entityId`**:**禁止**把 `entityId` 传给 `stats -a` / `balance -a`。应先 `list-accounts`(必要时 `--json` + 本地筛选或 `-k` 缩小范围)解析出 `mediaCustomerId` 后再调 `stats`。
|
|
177
|
+
- **`forewarning records`**:见 `references/forewarning.md`,不要求先做投放类日期反问。
|
|
178
|
+
- **`invoice list` /「本月」**:见 `references/finance.md`,可用当月 1 日~昨天直接查。
|
|
179
|
+
- **TikTok `clue`「最近一周」**:见 `references/clue.md`,可直接 `--json` 查询,不要先做 A/B/C 日期口径反问。
|
|
180
|
+
|
|
181
|
+
### 仅输出 JSON 的交付
|
|
182
|
+
|
|
183
|
+
用户明确要求「**只输出**一个 JSON / 除 JSON 外不要文字」时:回复中**仅含一个** JSON 代码块,内容与本次 CLI **stdout 完全一致**(分页、失败体均如此);失败时 CLI 已保证 `--json` 下 stdout 仍为 JSON 对象。
|
|
184
|
+
|
|
148
185
|
### 默认值白名单(仅在用户明确授权"你决定"时才能使用)
|
|
149
186
|
|
|
150
187
|
| 场景 | 允许的默认窗口 |
|
|
@@ -169,6 +206,7 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
169
206
|
2. `list-accounts` 返回的 `mag.advertiserName`
|
|
170
207
|
3. 用户提供的网址 → 明确告诉用户"使用域名作为占位"(例如 `hy-steelpipe.com`)并在交付物里标注 `[待确认品牌名]`
|
|
171
208
|
- **严禁**"hy-steelpipe.com"这样的英文域名被输出成类似"海悦钢管"这种虚构中文品牌。
|
|
209
|
+
- 正文里写出品牌名时,应能回溯到上述来源(可写「来自 list-accounts 的 `mag.advertiserName`:…」);**禁止**写看似真实但未在上述来源或 CLI 输出中出现的名称(包括常见 Demo 风格占位名)。
|
|
172
210
|
|
|
173
211
|
### 批量任务硬约束(≥ 5 个账户或系列)
|
|
174
212
|
|
|
@@ -209,6 +247,8 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
209
247
|
- 发票申请(`invoice apply`)— 涉及财务
|
|
210
248
|
- 广告发布(`ad batch publish` / `ad campaign-create`)— 涉及预算消耗
|
|
211
249
|
- **只读操作可自主执行**:查询类命令(`list-accounts`、`balance`、`stats`、`report list`、`config show` 等)可直接执行,无需额外确认
|
|
250
|
+
- **Google 广告结构性改动(否定词/系列/关键词等)**:须遵守 `references/google-ads.md` 开篇流程——先阅读规则文档、再列计划与将参考的文档清单;**仅在用户明确确认方案后**才可执行写命令。用户未确认前,不得使用「拿到参数就立刻执行」等措辞暗示可跳过确认。
|
|
251
|
+
- **Google 开户(CLI 指引)**:`open-account google-wizard` 仅适用于真实 TTY;**Agent/自动化环境一律用非交互** `open-account google ...`,审核进度用 `account-history`(详见 `references/workflows.md` 流程一)。向用户写步骤时,把上述禁令放在指引**最前**,再给可复制命令。
|
|
212
252
|
|
|
213
253
|
---
|
|
214
254
|
|
|
@@ -220,15 +260,16 @@ allowed-tools: Bash(siluzan-tso:*) Read
|
|
|
220
260
|
|
|
221
261
|
> 触发关键词:某账户数据 / 投放情况 / 整理账户 / 看下某个账户的表现
|
|
222
262
|
|
|
223
|
-
1. **反问时间范围**(参见"时间范围强制反问"
|
|
263
|
+
1. **反问时间范围**(参见"时间范围强制反问";用户已授权「按默认」时用默认值白名单并写明区间)。
|
|
224
264
|
2. `list-accounts -m Google -k <mediaCustomerId> --quick --json`
|
|
225
265
|
- 一次拿齐:账户基础信息、创建日期、当前状态、公司名(`mag.advertiserName` 作为品牌名)
|
|
226
|
-
3. `stats
|
|
227
|
-
- 拿该区间消耗、点击、转化等;**直接读响应中的主币种数值**,不要再 ×100。
|
|
228
|
-
4. `ad campaigns
|
|
266
|
+
3. `siluzan-tso stats -m Google -a <mediaCustomerId> --start <S> --end <D> --json`(`--start-date` / `--end-date` 与 `--start` / `--end` 等价)
|
|
267
|
+
- 拿该区间消耗、点击、转化等;**直接读响应中的主币种数值**,不要再 ×100。若返回 `{"ok":false,"error":...}`,须原样展示并**不得**用系列数据编造账户级 stats。
|
|
268
|
+
4. `siluzan-tso ad campaigns -a <mediaCustomerId> --start <S> --end <D> --json`
|
|
229
269
|
- 拿广告系列类型(Search / PMax / Display 等)、日预算(**用 `budgetDisplay`**)、优化得分相关字段。
|
|
230
270
|
5. `stats` 结合 `accountsoverview` 字段派生"开始投放时间 / 有效投放天数 / 地区消耗分布"(如接口暂未直出,在 node 里聚合)。
|
|
231
271
|
6. 用 `report-templates/google-account-diagnosis-report.md` 模板输出,**首行标注统计区间和货币**。
|
|
272
|
+
7. 用户要求「先拉 JSON 再文字总结」时:回复中须包含实际 `--json` 输出(完整或明确声明截断),再写总结;**禁止**用未出现在这些 JSON / `list-accounts` 中的字段写品牌名或接口状态。
|
|
232
273
|
|
|
233
274
|
### P2 · 多账户余额扫描 / 预算预警(典型指令:"117 个 Bing 账户不足 7 天的挑出来")
|
|
234
275
|
|
|
@@ -279,8 +320,9 @@ siluzan-tso accounts-digest -m Google \
|
|
|
279
320
|
|
|
280
321
|
1. **反问时间范围**(P 级硬约束),拿到用户回复后再执行 `accounts-digest`。
|
|
281
322
|
2. 如命令已返回 `--json`,直接基于其中 `data.items` 与 `meta.totals` 生成报告;**不要**再逐账户 `stats`。
|
|
282
|
-
3.
|
|
283
|
-
4.
|
|
323
|
+
3. **多账户 `-a id1,id2,...` 时**:表格须覆盖用户请求的**每一个** ID;若某 ID 在 `data.items` 中未出现,仍占一行并标注「未返回/无数据」,并说明与 `meta.totals` 的关系;**禁止**只展示子集却声称已完成多账户汇总。
|
|
324
|
+
4. 跨币种账户:按 `item.currencyCode` 分表或在 meta.currencyNote 提示的前提下分币种小计。
|
|
325
|
+
5. 金额字段严格按"金额与货币单位硬约束"处理。
|
|
284
326
|
|
|
285
327
|
### P4 · Google 账户周期报告(典型指令:"生成 2026.1.1-2026.4.15 的报告")
|
|
286
328
|
|
|
@@ -289,6 +331,7 @@ siluzan-tso accounts-digest -m Google \
|
|
|
289
331
|
3. 使用 `report-templates/google-period-report.md` 模板输出。
|
|
290
332
|
4. 首行必须有:`统计区间:2026-01-01 ~ 2026-04-15` + `货币:XXX`。
|
|
291
333
|
5. 报告必须包含:账户概览、投放趋势、Top 关键词/系列 / 地区分布 / 优化建议;不得编造未拉取到的指标(例如没拉取到的关键词就写"未提供"而不是估算)。
|
|
334
|
+
6. 品牌名遵守上文「品牌名 / 公司名来源硬约束」;描述系列启停时只引用 `ad campaigns`(或系列维报表)中的系列级状态字段,勿与账户 `status` 混用。
|
|
292
335
|
|
|
293
336
|
---
|
|
294
337
|
|
|
@@ -343,19 +386,23 @@ HTML 报告模板(`report-templates/*.html`)引用了以下外部 CDN 资源
|
|
|
343
386
|
|
|
344
387
|
### 异常监控与报警系统
|
|
345
388
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
|
349
|
-
|
|
|
350
|
-
|
|
|
351
|
-
|
|
|
352
|
-
|
|
|
389
|
+
编排(定时、HTTP 探活、通知)在宿主;**读哪些 JSON 字段、用什么命令** 以 **`references/hosted-automation-monitoring-json.md`** 为准(键名以当次 `--json` 为准,勿套用 Google Ads API 官方字段名解析本 CLI 输出)。
|
|
390
|
+
|
|
391
|
+
| 功能名称 | 监控层级 / 说明 | CLI 检查入口(`--json`) |
|
|
392
|
+
| ----------------- | --------------- | ------------------------ |
|
|
393
|
+
| 1. 账户被封禁 | 账户级;与 Google `CustomerStatus` 及 `list-accounts` 的字段映射**暂不写进本 skill**,由宿主约定。 | `list-accounts`、`balance` 等见 `references/accounts.md` |
|
|
394
|
+
| 2. 落地页死链强停 | URL 不可用或跳错页时暂停关联创意,避免无效消耗。 | **`google-analysis final-urls`**;或 **`ad list`** / **`google-analysis ads`** 取落地页字段后由宿主 HTTP 校验 |
|
|
395
|
+
| 3. 广告素材拒审 | 创意政策状态异常时告警或配合工单。 | **`ad list`** / **`google-analysis ads`**:`policyApprovalStatusV2`、`approvalStatusDetails` 等(见 **`references/google-ads.md`**) |
|
|
396
|
+
| 4. 花费异动监控 | 系列或账户维度花费相对历史异常波动。 | **`google-analysis campaign-hour`**:按 `campaignId` + `date` + `hour` 看 **`spend`** |
|
|
397
|
+
| 5. 余额枯竭预警 | 余额过低或按日均推算续航不足。 | **`balance-scan`**(`balance`、`remainingDays`、`hitReason`、`meta`)或 **`balance`** / **`google-analysis overview`**(`remainingAccountBudget`、`averageDailyCost` 等) |
|
|
353
398
|
|
|
354
399
|
### 自动优化
|
|
355
400
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
401
|
+
编排与阈值在宿主;**命令、JSON 键名、聚合与写后复核** 见 **`references/hosted-automation-optimize-index.md`**(及链出的三份 SOP)。
|
|
402
|
+
|
|
403
|
+
| 功能名称 | 说明 | SOP |
|
|
404
|
+
| ----------------------- | ---- | ----- |
|
|
405
|
+
| 1. 表现差广告降价/关停 | 组/创意:CTR、CPA、转化等触达后 **下调 `targetCpa` 或 `Paused`**。 | [`hosted-automation-optimize-weak-downbid.md`](references/hosted-automation-optimize-weak-downbid.md) |
|
|
406
|
+
| 2. 高转化广告提价扩量 | 系列/组:ROAS 代理、预算丢失份额等触达后 **提预算 / 上调目标 CPA**。 | [`hosted-automation-optimize-scale.md`](references/hosted-automation-optimize-scale.md) |
|
|
407
|
+
| 3. A/B 测试自动决出胜者 | 同组多创意:聚合后比 **CVPI / all conv** 等,**停输家**。 | [`hosted-automation-optimize-ab-winner.md`](references/hosted-automation-optimize-ab-winner.md) |
|
|
408
|
+
| 4. 异动根因自动排查建议 | 诊断报告与归因:用 `account-analytics`、报告模板等,见 `references/account-analytics.md` 与 `report-templates/`。 | (未单独拆 SOP,沿用分析文档) |
|
package/dist/skill/_meta.json
CHANGED