siluzan-tso-cli 1.1.59-beta.2 → 1.1.59
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 -2
- package/dist/index.js +245 -49
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/google-period-report.schema.json +23 -7
- package/dist/skill/assets/pmax-create-template.json +2 -1
- package/dist/skill/assets/pmax-create-template.md +15 -1
- package/dist/skill/references/accounts/accounts-list.md +1 -1
- package/dist/skill/references/accounts/accounts-permissions.md +2 -2
- package/dist/skill/references/accounts/finance.md +1 -1
- package/dist/skill/references/accounts/open-account-by-media.md +1 -1
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/account-analytics.md +5 -5
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/agent-conventions.md +2 -2
- package/dist/skill/references/core/intent-routing.md +1 -1
- package/dist/skill/references/core/playbooks.md +7 -7
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/subagent-orchestration.md +1 -1
- package/dist/skill/references/google-ads/google-ads-write.md +1 -1
- package/dist/skill/references/google-ads/pmax-api.md +3 -1
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/references/report-templates/google-period-report.md +24 -10
- package/dist/skill/references/report-templates/okki-weekly-google-client.md +30 -13
- package/dist/skill/report-templates/google-period-report.html +56 -1
- package/dist/skill/report-templates/google-period-report.md +24 -10
- package/dist/skill/report-templates/okki-weekly-google-client.md +30 -13
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/dist/skill/snippets/handoff-p6-okki.md +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板外部资源:**ECharts** 统一使用 `https://staticpn.siluz
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,7 +51,6 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.59-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
54
|
|
|
56
55
|
| 助手 | 建议 `--ai` |
|
|
57
56
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -2570,7 +2570,9 @@ function buildAuthHeaders(config) {
|
|
|
2570
2570
|
}
|
|
2571
2571
|
async function parseApiResponse(status, text3, verbose) {
|
|
2572
2572
|
if (status < 200 || status >= 300) {
|
|
2573
|
-
|
|
2573
|
+
const err = new Error(formatHttpError(status, text3, { verbose }));
|
|
2574
|
+
Object.assign(err, { status, rawBody: text3 });
|
|
2575
|
+
throw err;
|
|
2574
2576
|
}
|
|
2575
2577
|
if (!text3.trim()) return null;
|
|
2576
2578
|
try {
|
|
@@ -4049,7 +4051,7 @@ var DEFAULT_API_BASE;
|
|
|
4049
4051
|
var init_defaults = __esm({
|
|
4050
4052
|
"src/config/defaults.ts"() {
|
|
4051
4053
|
"use strict";
|
|
4052
|
-
DEFAULT_API_BASE = "https://tso-api
|
|
4054
|
+
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
4053
4055
|
}
|
|
4054
4056
|
});
|
|
4055
4057
|
|
|
@@ -6434,7 +6436,8 @@ var init_wrap_snapshot_envelope = __esm({
|
|
|
6434
6436
|
]);
|
|
6435
6437
|
GATEWAY_LIST_SECTIONS = /* @__PURE__ */ new Set([
|
|
6436
6438
|
"search-terms",
|
|
6437
|
-
"ads"
|
|
6439
|
+
"ads",
|
|
6440
|
+
"negative-keywords"
|
|
6438
6441
|
]);
|
|
6439
6442
|
}
|
|
6440
6443
|
});
|
|
@@ -7670,6 +7673,12 @@ var init_sections = __esm({
|
|
|
7670
7673
|
defaultQuery: { limit: 0, orderByCost: true, costGreater: 0 },
|
|
7671
7674
|
keywordOptions: true
|
|
7672
7675
|
},
|
|
7676
|
+
{
|
|
7677
|
+
name: "negative-keywords",
|
|
7678
|
+
description: "\u5F53\u524D\u8D26\u6237\u5426\u8BCD negativekeywordmanagement/v2/list\uFF08\u7CFB\u5217/\u5E7F\u544A\u7EC4/\u8D26\u6237\u4E09\u7EA7\uFF1B\u540D\u5355\u4E0D\u6309\u6D88\u8017\u8FC7\u6EE4\uFF0C0 \u6761\u4E5F\u843D\u76D8\uFF09",
|
|
7679
|
+
dateMode: "range",
|
|
7680
|
+
path: (id) => `/negativekeywordmanagement/v2/list/${id}`
|
|
7681
|
+
},
|
|
7673
7682
|
{
|
|
7674
7683
|
name: "search-terms",
|
|
7675
7684
|
description: "\u641C\u7D22\u8BCD searchtermmanagement/v2/list\uFF08\u9ED8\u8BA4 limit=0 \u4E0D\u5C01\u9876\uFF0CCLI \u843D\u76D8\u524D\u8FC7\u6EE4 spend>0\uFF09",
|
|
@@ -103462,6 +103471,8 @@ async function fetchGoogleAnalysisSectionJson(config, fullPath, verbose, name2,
|
|
|
103462
103471
|
return fetchSection();
|
|
103463
103472
|
case "keywords":
|
|
103464
103473
|
return fetchSection();
|
|
103474
|
+
case "negative-keywords":
|
|
103475
|
+
return fetchSection();
|
|
103465
103476
|
case "search-terms":
|
|
103466
103477
|
return fetchSection();
|
|
103467
103478
|
case "campaigns":
|
|
@@ -103867,6 +103878,37 @@ async function loadSectionFile(snapshotDir, file) {
|
|
|
103867
103878
|
return null;
|
|
103868
103879
|
}
|
|
103869
103880
|
}
|
|
103881
|
+
function negativeKeywordText(row) {
|
|
103882
|
+
const text3 = row.keywordText;
|
|
103883
|
+
if (Array.isArray(text3)) {
|
|
103884
|
+
const parts = text3.map((part) => String(part).trim()).filter(Boolean);
|
|
103885
|
+
if (parts.length > 0) return parts.join(", ");
|
|
103886
|
+
}
|
|
103887
|
+
if (typeof text3 === "string" && text3.trim()) return text3.trim();
|
|
103888
|
+
if (typeof row.keyword === "string" && row.keyword.trim()) return row.keyword.trim();
|
|
103889
|
+
return "\u2014";
|
|
103890
|
+
}
|
|
103891
|
+
function mapNegativeKeywordRows(rows) {
|
|
103892
|
+
const seen = /* @__PURE__ */ new Set();
|
|
103893
|
+
const mapped = [];
|
|
103894
|
+
for (const row of rows) {
|
|
103895
|
+
const id = row.id == null ? "" : String(row.id);
|
|
103896
|
+
if (id && seen.has(id)) continue;
|
|
103897
|
+
if (id) seen.add(id);
|
|
103898
|
+
const level = String(row.negativeLevel ?? "").trim();
|
|
103899
|
+
const campaignName = String(row.campaignName ?? "").trim();
|
|
103900
|
+
const adGroupName = String(row.adGroupName ?? "").trim();
|
|
103901
|
+
mapped.push({
|
|
103902
|
+
keyword: negativeKeywordText(row),
|
|
103903
|
+
matchType: String(row.matchTypeV2 ?? row.matchType ?? "\u2014"),
|
|
103904
|
+
level: level || "\u2014",
|
|
103905
|
+
levelZh: NEGATIVE_LEVEL_ZH[level] ?? (level || "\u2014"),
|
|
103906
|
+
campaignName: campaignName || "\u2014",
|
|
103907
|
+
adGroupName: adGroupName || "\u2014"
|
|
103908
|
+
});
|
|
103909
|
+
}
|
|
103910
|
+
return mapped;
|
|
103911
|
+
}
|
|
103870
103912
|
function dateTagFromRange(dateRange) {
|
|
103871
103913
|
if (!dateRange || dateRange.mode !== "range") return void 0;
|
|
103872
103914
|
return `${dateRange.start.replace(/-/g, "")}-${dateRange.end.replace(/-/g, "")}`;
|
|
@@ -104095,6 +104137,9 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
104095
104137
|
);
|
|
104096
104138
|
}
|
|
104097
104139
|
}
|
|
104140
|
+
if (sectionMap.has("negative-keywords")) {
|
|
104141
|
+
tables.negativeKeywords = mapNegativeKeywordRows(items(sectionMap.get("negative-keywords")));
|
|
104142
|
+
}
|
|
104098
104143
|
return {
|
|
104099
104144
|
...payload,
|
|
104100
104145
|
meta,
|
|
@@ -104103,7 +104148,7 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
104103
104148
|
tables
|
|
104104
104149
|
};
|
|
104105
104150
|
}
|
|
104106
|
-
var REPORT_MERGE_SECTIONS;
|
|
104151
|
+
var REPORT_MERGE_SECTIONS, NEGATIVE_LEVEL_ZH;
|
|
104107
104152
|
var init_merge_snapshot = __esm({
|
|
104108
104153
|
"src/commands/google-analysis/merge-snapshot.ts"() {
|
|
104109
104154
|
"use strict";
|
|
@@ -104116,8 +104161,15 @@ var init_merge_snapshot = __esm({
|
|
|
104116
104161
|
"devices",
|
|
104117
104162
|
"geographic",
|
|
104118
104163
|
"audience",
|
|
104119
|
-
"keywords"
|
|
104164
|
+
"keywords",
|
|
104165
|
+
"negative-keywords"
|
|
104120
104166
|
];
|
|
104167
|
+
NEGATIVE_LEVEL_ZH = {
|
|
104168
|
+
Account: "\u8D26\u6237",
|
|
104169
|
+
Campaign: "\u7CFB\u5217",
|
|
104170
|
+
AdGroup: "\u5E7F\u544A\u7EC4",
|
|
104171
|
+
"Ad group": "\u5E7F\u544A\u7EC4"
|
|
104172
|
+
};
|
|
104121
104173
|
}
|
|
104122
104174
|
});
|
|
104123
104175
|
|
|
@@ -104992,6 +105044,16 @@ function validateGooglePeriodReportContent(data) {
|
|
|
104992
105044
|
"\u81F3\u5C11\u4E00\u9879\u987B\u4E3A\u6709\u6548\u6570\u5B57\uFF1B\u8BF7\u52A0 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u5408\u5E76\uFF08\u52FF\u624B\u586B HTML\uFF09"
|
|
104993
105045
|
);
|
|
104994
105046
|
}
|
|
105047
|
+
const negativeRows = asRecord22(data.tables)?.negativeKeywords;
|
|
105048
|
+
if (!Array.isArray(negativeRows)) {
|
|
105049
|
+
pushMissing2(
|
|
105050
|
+
missing,
|
|
105051
|
+
"tables-negative-keywords",
|
|
105052
|
+
"\u2468\u5426\u8BCD",
|
|
105053
|
+
"tables.negativeKeywords",
|
|
105054
|
+
"\u987B\u4E3A\u6570\u7EC4\uFF080 \u6761\u4E5F\u8981\u662F []\uFF09\u3002\u9ED8\u8BA4\u62C9\u6570\u52A0\u4E0A --sections negative-keywords\uFF0Crender \u5E26 --snapshot-dir"
|
|
105055
|
+
);
|
|
105056
|
+
}
|
|
104995
105057
|
const sectionAnalysisCounts = {};
|
|
104996
105058
|
const sectionSuggestionCounts = {};
|
|
104997
105059
|
for (const key of SECTION_KEYS) {
|
|
@@ -105028,7 +105090,7 @@ function validateGooglePeriodReportContent(data) {
|
|
|
105028
105090
|
pushMissing2(
|
|
105029
105091
|
missing,
|
|
105030
105092
|
"narrative-recommendations",
|
|
105031
|
-
"\
|
|
105093
|
+
"\u2469\u4F18\u5316\u5EFA\u8BAE",
|
|
105032
105094
|
"narrative.recommendations",
|
|
105033
105095
|
`\u22653 \u6761\u8DE8\u7EF4\u5EA6\u4F18\u5316\u5EFA\u8BAE\uFF08\u5F53\u524D ${recommendations.length} \u6761\uFF09`
|
|
105034
105096
|
);
|
|
@@ -105067,7 +105129,8 @@ var init_report_content = __esm({
|
|
|
105067
105129
|
"devices",
|
|
105068
105130
|
"geographic",
|
|
105069
105131
|
"audience",
|
|
105070
|
-
"keywords"
|
|
105132
|
+
"keywords",
|
|
105133
|
+
"negativeKeywords"
|
|
105071
105134
|
];
|
|
105072
105135
|
SECTION_LABELS = {
|
|
105073
105136
|
overview: "\u2460\u6267\u884C\u6458\u8981",
|
|
@@ -105077,7 +105140,8 @@ var init_report_content = __esm({
|
|
|
105077
105140
|
devices: "\u2464\u8BBE\u5907\u5206\u5E03",
|
|
105078
105141
|
geographic: "\u2465\u5730\u57DF\u5206\u5E03",
|
|
105079
105142
|
audience: "\u2466\u53D7\u4F17\u5206\u5E03",
|
|
105080
|
-
keywords: "\u2467\u5173\u952E\u8BCD\u8868\u73B0"
|
|
105143
|
+
keywords: "\u2467\u5173\u952E\u8BCD\u8868\u73B0",
|
|
105144
|
+
negativeKeywords: "\u2468\u5426\u8BCD"
|
|
105081
105145
|
};
|
|
105082
105146
|
}
|
|
105083
105147
|
});
|
|
@@ -105165,7 +105229,7 @@ async function runGoogleAnalysisRender(opts) {
|
|
|
105165
105229
|
\u2705 Google Ads ${cover}\u5206\u6790 HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
105166
105230
|
`);
|
|
105167
105231
|
console.log(
|
|
105168
|
-
` \u5FC5\u542B\u5B57\u6BB5\u5DF2\u5168\u90E8\u8986\u76D6\uFF5C\u6267\u884C\u6458\u8981 ${stats.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats.recommendationCount} \u6761\
|
|
105232
|
+
` \u5FC5\u542B\u5B57\u6BB5\u5DF2\u5168\u90E8\u8986\u76D6\uFF5C\u6267\u884C\u6458\u8981 ${stats.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats.recommendationCount} \u6761\uFF5C9 \u4E2A\u6570\u636E\u7EF4\u5206\u6790+\u5EFA\u8BAE\u5747\u5DF2\u9F50\u5168
|
|
105169
105233
|
`
|
|
105170
105234
|
);
|
|
105171
105235
|
console.log(
|
|
@@ -122330,6 +122394,119 @@ function assertPmaxImageSlotsResolved(slots, requiredKinds = ["marketing", "squa
|
|
|
122330
122394
|
import { readFileSync as readFileSync11 } from "fs";
|
|
122331
122395
|
init_shared();
|
|
122332
122396
|
|
|
122397
|
+
// src/commands/ad/pmax-create-http-error.ts
|
|
122398
|
+
function normalizePmaxResumeId(value) {
|
|
122399
|
+
if (value == null) return null;
|
|
122400
|
+
const text3 = String(value).trim();
|
|
122401
|
+
if (!text3 || text3.toLowerCase() === "null") return null;
|
|
122402
|
+
return text3;
|
|
122403
|
+
}
|
|
122404
|
+
function quoteLongResumeIds(rawBody) {
|
|
122405
|
+
return rawBody.replace(
|
|
122406
|
+
/"(budgetId|campaignId|assetGroupId)"\s*:\s*(-?\d+)/g,
|
|
122407
|
+
'"$1":"$2"'
|
|
122408
|
+
);
|
|
122409
|
+
}
|
|
122410
|
+
function parsePmaxCreateFailureBody(rawBody) {
|
|
122411
|
+
const text3 = rawBody.trim();
|
|
122412
|
+
if (!text3.startsWith("{")) return null;
|
|
122413
|
+
let parsed;
|
|
122414
|
+
try {
|
|
122415
|
+
parsed = JSON.parse(quoteLongResumeIds(text3));
|
|
122416
|
+
} catch {
|
|
122417
|
+
return null;
|
|
122418
|
+
}
|
|
122419
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
122420
|
+
const rec = parsed;
|
|
122421
|
+
if (typeof rec["message"] !== "string" || !rec["message"].trim()) return null;
|
|
122422
|
+
if (!("budgetId" in rec) && !("campaignId" in rec) && !("assetGroupId" in rec)) return null;
|
|
122423
|
+
return {
|
|
122424
|
+
message: rec["message"].trim(),
|
|
122425
|
+
budgetId: normalizePmaxResumeId(rec["budgetId"]),
|
|
122426
|
+
campaignId: normalizePmaxResumeId(rec["campaignId"]),
|
|
122427
|
+
assetGroupId: normalizePmaxResumeId(rec["assetGroupId"])
|
|
122428
|
+
};
|
|
122429
|
+
}
|
|
122430
|
+
function readHttpRawBody(err) {
|
|
122431
|
+
if (!err || typeof err !== "object" || !("rawBody" in err)) return "";
|
|
122432
|
+
const raw = err.rawBody;
|
|
122433
|
+
return typeof raw === "string" ? raw : "";
|
|
122434
|
+
}
|
|
122435
|
+
function sameResumeId(left, right) {
|
|
122436
|
+
const a = left?.trim() || null;
|
|
122437
|
+
const b = right?.trim() || null;
|
|
122438
|
+
return a === b;
|
|
122439
|
+
}
|
|
122440
|
+
function pmaxCreateRetryAdvice(requested, failure) {
|
|
122441
|
+
const got = [failure.budgetId, failure.campaignId, failure.assetGroupId];
|
|
122442
|
+
if (!got.some(Boolean)) return "fix-without-ids";
|
|
122443
|
+
const sent = [
|
|
122444
|
+
normalizePmaxResumeId(requested.budgetId),
|
|
122445
|
+
normalizePmaxResumeId(requested.campaignId),
|
|
122446
|
+
normalizePmaxResumeId(requested.assetGroupId)
|
|
122447
|
+
];
|
|
122448
|
+
if (sent.every((id, index) => sameResumeId(id, got[index]))) return "stop-same-step";
|
|
122449
|
+
for (let index = 0; index < sent.length; index++) {
|
|
122450
|
+
const previous = sent[index]?.trim() || null;
|
|
122451
|
+
if (previous && previous !== got[index]) return "stop-same-step";
|
|
122452
|
+
}
|
|
122453
|
+
return "resume";
|
|
122454
|
+
}
|
|
122455
|
+
function pmaxCreateResumeError(cfg) {
|
|
122456
|
+
const budgetId = normalizePmaxResumeId(cfg.budgetId) ?? "";
|
|
122457
|
+
const campaignId = normalizePmaxResumeId(cfg.campaignId) ?? "";
|
|
122458
|
+
const assetGroupId = normalizePmaxResumeId(cfg.assetGroupId) ?? "";
|
|
122459
|
+
if (campaignId && !budgetId) return "BudgetId is required when CampaignId is provided.";
|
|
122460
|
+
if (assetGroupId && (!budgetId || !campaignId)) {
|
|
122461
|
+
return "CampaignId is required when AssetGroupId is provided.";
|
|
122462
|
+
}
|
|
122463
|
+
const brandGuidelinesOn = cfg.brandGuidelinesEnabled !== false;
|
|
122464
|
+
if (brandGuidelinesOn && campaignId && !assetGroupId) {
|
|
122465
|
+
return "AssetGroupId is required when CampaignId is provided and brand guidelines are enabled.";
|
|
122466
|
+
}
|
|
122467
|
+
return null;
|
|
122468
|
+
}
|
|
122469
|
+
function classifyPmaxCreateHttpError(raw) {
|
|
122470
|
+
const msg = raw.trim() || "\u672A\u77E5\u9519\u8BEF";
|
|
122471
|
+
const lower = msg.toLowerCase();
|
|
122472
|
+
const hints = [];
|
|
122473
|
+
if (/^HTTP 400\b/i.test(msg) || lower.includes("bad request")) {
|
|
122474
|
+
if (/budget|日预算|budgetamount|micros/i.test(msg)) {
|
|
122475
|
+
hints.push("\u68C0\u67E5 campaign.budget / \u65E5\u9884\u7B97\u91D1\u989D\u4E0E\u5E01\u79CD\u662F\u5426\u5408\u7406");
|
|
122476
|
+
}
|
|
122477
|
+
if (/bidding|target.?cpa|target.?roas|maximize|出价/i.test(msg)) {
|
|
122478
|
+
hints.push("\u68C0\u67E5 BiddingStrategyTypeV2 \u4E0E\u914D\u5957\u91D1\u989D\u5B57\u6BB5\uFF08tCPA/tROAS\uFF09\u662F\u5426\u9F50\u5168\u4E14\u517C\u5BB9");
|
|
122479
|
+
}
|
|
122480
|
+
if (/image|asset|marketing|logo|图片/i.test(msg)) {
|
|
122481
|
+
hints.push("\u68C0\u67E5\u6A2A\u56FE/\u65B9\u56FE/Logo \u662F\u5426\u5DF2\u4E0A\u4F20\u6210\u529F\u3001\u89C4\u683C\u662F\u5426\u8FBE\u6807\uFF08\u5148\u8DD1 ad pmax-validate\uFF09");
|
|
122482
|
+
}
|
|
122483
|
+
if (/final.?url|landing|落地页|url/i.test(msg)) {
|
|
122484
|
+
hints.push("\u68C0\u67E5 finalUrls \u662F\u5426\u4E3A\u53EF\u8BBF\u95EE\u7684 http(s) \u843D\u5730\u9875");
|
|
122485
|
+
}
|
|
122486
|
+
if (/name|duplicate|已存在|同名/i.test(msg)) {
|
|
122487
|
+
hints.push("\u7CFB\u5217\u540D\u53EF\u80FD\u91CD\u590D\uFF1B\u6362\u4E00\u4E2A name \u518D\u8BD5");
|
|
122488
|
+
}
|
|
122489
|
+
if (/geo|location|language|地域|语言/i.test(msg)) {
|
|
122490
|
+
hints.push("\u68C0\u67E5 geo / language id \u662F\u5426\u6765\u81EA ad geo resolve / \u6587\u6863\u679A\u4E3E");
|
|
122491
|
+
}
|
|
122492
|
+
if (hints.length === 0) {
|
|
122493
|
+
hints.push(
|
|
122494
|
+
"\u5E38\u89C1\uFF1A\u9884\u7B97/\u51FA\u4EF7\u4E0D\u517C\u5BB9\u3001\u56FE\u7247\u8D44\u4EA7\u65E0\u6548\u3001finalUrl \u65E0\u6548\u3001\u7CFB\u5217\u91CD\u540D\uFF1B\u5148 ad pmax-validate\uFF0C\u4ECD\u5931\u8D25\u52A0 --verbose \u770B\u7F51\u5173\u539F\u6587"
|
|
122495
|
+
);
|
|
122496
|
+
}
|
|
122497
|
+
} else if (/^HTTP 403\b/i.test(msg)) {
|
|
122498
|
+
hints.push("\u8D26\u6237\u53EF\u80FD\u65E0\u6743\u521B\u5EFA\uFF1B\u5148 account check-access -a <id>\uFF0C\u786E\u8BA4\u5728\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u4E0B");
|
|
122499
|
+
} else if (/^HTTP 401\b/i.test(msg)) {
|
|
122500
|
+
hints.push("\u9274\u6743\u5931\u6548\uFF1B\u6267\u884C siluzan-tso login \u540E\u91CD\u8BD5");
|
|
122501
|
+
}
|
|
122502
|
+
if (hints.length === 0) return msg;
|
|
122503
|
+
return `${msg}
|
|
122504
|
+
\u63D0\u793A\uFF1A${hints.join("\uFF1B")}`;
|
|
122505
|
+
}
|
|
122506
|
+
function pmaxCreateFollowUpFailed(input) {
|
|
122507
|
+
return Boolean(input.uploadError || input.linkError || input.extensionsAllOk === false);
|
|
122508
|
+
}
|
|
122509
|
+
|
|
122333
122510
|
// src/commands/ad/pmax-campaign-extensions.ts
|
|
122334
122511
|
init_auth();
|
|
122335
122512
|
var PMAX_POLICY_CALLOUT_MIN = 20;
|
|
@@ -122912,7 +123089,12 @@ function parseLocationLanguageIds(items3) {
|
|
|
122912
123089
|
id: Number(item.id)
|
|
122913
123090
|
}));
|
|
122914
123091
|
}
|
|
123092
|
+
function trimmedId(value) {
|
|
123093
|
+
return normalizePmaxResumeId(value) ?? void 0;
|
|
123094
|
+
}
|
|
122915
123095
|
function buildPmaxCreateApiBody(cfg, imageSlots) {
|
|
123096
|
+
const resumeError = pmaxCreateResumeError(cfg);
|
|
123097
|
+
if (resumeError) throw new Error(resumeError);
|
|
122916
123098
|
assertPmaxImageSlotsResolved(imageSlots);
|
|
122917
123099
|
const body = {
|
|
122918
123100
|
name: cfg.name.trim(),
|
|
@@ -122943,6 +123125,12 @@ function buildPmaxCreateApiBody(cfg, imageSlots) {
|
|
|
122943
123125
|
if (cfg.brandGuidelinesEnabled !== void 0) {
|
|
122944
123126
|
body.brandGuidelinesEnabled = cfg.brandGuidelinesEnabled;
|
|
122945
123127
|
}
|
|
123128
|
+
const budgetId = trimmedId(cfg.budgetId);
|
|
123129
|
+
const campaignId = trimmedId(cfg.campaignId);
|
|
123130
|
+
const assetGroupId = trimmedId(cfg.assetGroupId);
|
|
123131
|
+
if (budgetId) body.budgetId = budgetId;
|
|
123132
|
+
if (campaignId) body.campaignId = campaignId;
|
|
123133
|
+
if (assetGroupId) body.assetGroupId = assetGroupId;
|
|
122946
123134
|
return body;
|
|
122947
123135
|
}
|
|
122948
123136
|
function buildPmaxCreateUrl(googleApiUrl, accountId) {
|
|
@@ -123344,51 +123532,13 @@ async function linkPmaxVideoAfterCreate(opts) {
|
|
|
123344
123532
|
}
|
|
123345
123533
|
}
|
|
123346
123534
|
|
|
123347
|
-
// src/commands/ad/pmax-create-http-error.ts
|
|
123348
|
-
function classifyPmaxCreateHttpError(raw) {
|
|
123349
|
-
const msg = raw.trim() || "\u672A\u77E5\u9519\u8BEF";
|
|
123350
|
-
const lower = msg.toLowerCase();
|
|
123351
|
-
const hints = [];
|
|
123352
|
-
if (/^HTTP 400\b/i.test(msg) || lower.includes("bad request")) {
|
|
123353
|
-
if (/budget|日预算|budgetamount|micros/i.test(msg)) {
|
|
123354
|
-
hints.push("\u68C0\u67E5 campaign.budget / \u65E5\u9884\u7B97\u91D1\u989D\u4E0E\u5E01\u79CD\u662F\u5426\u5408\u7406");
|
|
123355
|
-
}
|
|
123356
|
-
if (/bidding|target.?cpa|target.?roas|maximize|出价/i.test(msg)) {
|
|
123357
|
-
hints.push("\u68C0\u67E5 BiddingStrategyTypeV2 \u4E0E\u914D\u5957\u91D1\u989D\u5B57\u6BB5\uFF08tCPA/tROAS\uFF09\u662F\u5426\u9F50\u5168\u4E14\u517C\u5BB9");
|
|
123358
|
-
}
|
|
123359
|
-
if (/image|asset|marketing|logo|图片/i.test(msg)) {
|
|
123360
|
-
hints.push("\u68C0\u67E5\u6A2A\u56FE/\u65B9\u56FE/Logo \u662F\u5426\u5DF2\u4E0A\u4F20\u6210\u529F\u3001\u89C4\u683C\u662F\u5426\u8FBE\u6807\uFF08\u5148\u8DD1 ad pmax-validate\uFF09");
|
|
123361
|
-
}
|
|
123362
|
-
if (/final.?url|landing|落地页|url/i.test(msg)) {
|
|
123363
|
-
hints.push("\u68C0\u67E5 finalUrls \u662F\u5426\u4E3A\u53EF\u8BBF\u95EE\u7684 http(s) \u843D\u5730\u9875");
|
|
123364
|
-
}
|
|
123365
|
-
if (/name|duplicate|已存在|同名/i.test(msg)) {
|
|
123366
|
-
hints.push("\u7CFB\u5217\u540D\u53EF\u80FD\u91CD\u590D\uFF1B\u6362\u4E00\u4E2A name \u518D\u8BD5");
|
|
123367
|
-
}
|
|
123368
|
-
if (/geo|location|language|地域|语言/i.test(msg)) {
|
|
123369
|
-
hints.push("\u68C0\u67E5 geo / language id \u662F\u5426\u6765\u81EA ad geo resolve / \u6587\u6863\u679A\u4E3E");
|
|
123370
|
-
}
|
|
123371
|
-
if (hints.length === 0) {
|
|
123372
|
-
hints.push(
|
|
123373
|
-
"\u5E38\u89C1\uFF1A\u9884\u7B97/\u51FA\u4EF7\u4E0D\u517C\u5BB9\u3001\u56FE\u7247\u8D44\u4EA7\u65E0\u6548\u3001finalUrl \u65E0\u6548\u3001\u7CFB\u5217\u91CD\u540D\uFF1B\u5148 ad pmax-validate\uFF0C\u4ECD\u5931\u8D25\u52A0 --verbose \u770B\u7F51\u5173\u539F\u6587"
|
|
123374
|
-
);
|
|
123375
|
-
}
|
|
123376
|
-
} else if (/^HTTP 403\b/i.test(msg)) {
|
|
123377
|
-
hints.push("\u8D26\u6237\u53EF\u80FD\u65E0\u6743\u521B\u5EFA\uFF1B\u5148 account check-access -a <id>\uFF0C\u786E\u8BA4\u5728\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u4E0B");
|
|
123378
|
-
} else if (/^HTTP 401\b/i.test(msg)) {
|
|
123379
|
-
hints.push("\u9274\u6743\u5931\u6548\uFF1B\u6267\u884C siluzan-tso login \u540E\u91CD\u8BD5");
|
|
123380
|
-
}
|
|
123381
|
-
if (hints.length === 0) return msg;
|
|
123382
|
-
return `${msg}
|
|
123383
|
-
\u63D0\u793A\uFF1A${hints.join("\uFF1B")}`;
|
|
123384
|
-
}
|
|
123385
|
-
|
|
123386
123535
|
// src/commands/ad/pmax-create.ts
|
|
123387
123536
|
function printVideoLinkRecoveryHint(accountId, assetGroupId, campaignId, youtubeTarget) {
|
|
123388
123537
|
const cid = campaignId != null ? ` --campaign-id ${campaignId}` : "";
|
|
123389
123538
|
const yt = youtubeTarget ? ` --youtube "${youtubeTarget}"` : ` --video-path "<path>"`;
|
|
123390
123539
|
console.error(
|
|
123391
123540
|
` \u53EF\u624B\u52A8\uFF1Asiluzan-tso ad pmax-youtube-link -a ${accountId} --asset-group-id ${assetGroupId}${cid}${yt}
|
|
123541
|
+
\u6D3B\u52A8\u5DF2\u7ECF\u521B\u5EFA\u6210\u529F\uFF0C\u4E0D\u8981\u518D\u6267\u884C pmax-create\u3002
|
|
123392
123542
|
`
|
|
123393
123543
|
);
|
|
123394
123544
|
}
|
|
@@ -123471,6 +123621,39 @@ async function runAdPmaxCreate(opts) {
|
|
|
123471
123621
|
opts.verbose
|
|
123472
123622
|
);
|
|
123473
123623
|
} catch (err) {
|
|
123624
|
+
const failure = parsePmaxCreateFailureBody(readHttpRawBody(err));
|
|
123625
|
+
if (failure) {
|
|
123626
|
+
const advice = pmaxCreateRetryAdvice(cfg, failure);
|
|
123627
|
+
console.error(`
|
|
123628
|
+
\u274C \u521B\u5EFA PMax \u5E7F\u544A\u7CFB\u5217\u5931\u8D25\uFF1A${failure.message}`);
|
|
123629
|
+
console.error(` budgetId\uFF1A${failure.budgetId ?? "null"}`);
|
|
123630
|
+
console.error(` campaignId\uFF1A${failure.campaignId ?? "null"}`);
|
|
123631
|
+
console.error(` assetGroupId\uFF1A${failure.assetGroupId ?? "null"}`);
|
|
123632
|
+
if (advice === "resume") {
|
|
123633
|
+
console.error(
|
|
123634
|
+
" \u7EED\u8DD1\uFF1A\u628A\u975E\u7A7A\u7F16\u53F7\u6309\u540C\u540D\u5199\u56DE\u8FD9\u4EFD JSON\uFF0C\u5176\u4F59\u5185\u5BB9\u4E0D\u8981\u6539\uFF0C\u518D\u6267\u884C\u4E00\u6B21 pmax-create\u3002\u7F16\u53F7\u6309\u9884\u7B97\u3001\u7CFB\u5217\u3001\u7D20\u6750\u7EC4\u5E26\u3002\u540C\u4E00\u6B65\u518D\u5931\u8D25\u5C31\u505C\u3002\n"
|
|
123635
|
+
);
|
|
123636
|
+
} else if (advice === "stop-same-step") {
|
|
123637
|
+
console.error(" \u540C\u4E00\u6B65\u518D\u5931\u8D25\uFF0C\u505C\u6B62\u3002\u4E0D\u8981\u518D\u6267\u884C pmax-create\u3002\n");
|
|
123638
|
+
} else {
|
|
123639
|
+
console.error(" \u8FD9\u6B21\u8FD8\u6CA1\u6709\u5EFA\u6210\u9884\u7B97\u3001\u7CFB\u5217\u6216\u7D20\u6750\u7EC4\u3002\u4FEE\u6B63\u539F\u56E0\u540E\u7528\u539F JSON \u518D\u63D0\u4EA4\uFF0C\u4E0D\u8981\u586B\u8FD9\u4E09\u4E2A\u7F16\u53F7\u3002\n");
|
|
123640
|
+
}
|
|
123641
|
+
await emitCliJsonOrSnapshot(opts, {
|
|
123642
|
+
section: `ad-pmax-create-${accountId}`,
|
|
123643
|
+
commandLabel: "ad pmax-create",
|
|
123644
|
+
commandHint: accountId,
|
|
123645
|
+
payload: { ok: false, retryCreate: advice === "resume", ...failure },
|
|
123646
|
+
idSuffix: accountId,
|
|
123647
|
+
summaryExtras: {
|
|
123648
|
+
ok: false,
|
|
123649
|
+
retryCreate: advice === "resume",
|
|
123650
|
+
budgetId: failure.budgetId,
|
|
123651
|
+
campaignId: failure.campaignId,
|
|
123652
|
+
assetGroupId: failure.assetGroupId
|
|
123653
|
+
}
|
|
123654
|
+
});
|
|
123655
|
+
process.exit(1);
|
|
123656
|
+
}
|
|
123474
123657
|
const raw = err instanceof Error ? err.message : String(err);
|
|
123475
123658
|
console.error(`
|
|
123476
123659
|
\u274C \u521B\u5EFA PMax \u5E7F\u544A\u7CFB\u5217\u5931\u8D25\uFF1A${classifyPmaxCreateHttpError(raw)}
|
|
@@ -123534,6 +123717,7 @@ async function runAdPmaxCreate(opts) {
|
|
|
123534
123717
|
void 0
|
|
123535
123718
|
);
|
|
123536
123719
|
}
|
|
123720
|
+
console.error(" \u6D3B\u52A8\u5DF2\u7ECF\u521B\u5EFA\u6210\u529F\uFF0C\u4E0D\u8981\u518D\u6267\u884C pmax-create\u3002\n");
|
|
123537
123721
|
} else if (videoResult.linkError) {
|
|
123538
123722
|
console.error(`
|
|
123539
123723
|
\u26A0\uFE0F \u6D3B\u52A8\u5DF2\u521B\u5EFA\uFF0C\u4F46 YouTube \u94FE\u63A5\u5931\u8D25\uFF1A${videoResult.linkError}`);
|
|
@@ -123545,6 +123729,7 @@ async function runAdPmaxCreate(opts) {
|
|
|
123545
123729
|
videoResult.youtubeTarget
|
|
123546
123730
|
);
|
|
123547
123731
|
}
|
|
123732
|
+
console.error(" \u6D3B\u52A8\u5DF2\u7ECF\u521B\u5EFA\u6210\u529F\uFF0C\u4E0D\u8981\u518D\u6267\u884C pmax-create\u3002\n");
|
|
123548
123733
|
} else if (videoResult.skippedReason) {
|
|
123549
123734
|
console.error(`
|
|
123550
123735
|
\u26A0\uFE0F \u6D3B\u52A8\u5DF2\u521B\u5EFA\uFF0C\u4F46\u89C6\u9891\u672A\u94FE\u63A5\uFF1A${videoResult.skippedReason}
|
|
@@ -123557,6 +123742,7 @@ async function runAdPmaxCreate(opts) {
|
|
|
123557
123742
|
}
|
|
123558
123743
|
console.error(
|
|
123559
123744
|
` \u53EF\u624B\u52A8\u8865\u6302\uFF1Asiluzan-tso ad extension callout|snippet|lead-form -a ${accountId} --campaign-id ${campaignId} \u2026
|
|
123745
|
+
\u6D3B\u52A8\u5DF2\u7ECF\u521B\u5EFA\u6210\u529F\uFF0C\u4E0D\u8981\u518D\u6267\u884C pmax-create\u3002
|
|
123560
123746
|
`
|
|
123561
123747
|
);
|
|
123562
123748
|
} else if (extensionsResult?.allOk && extensionsResult.callouts.length + extensionsResult.structuredSnippets.length + extensionsResult.sitelinks.length + (extensionsResult.leadForm ? 1 : 0) + (extensionsResult.whatsapp ? 1 : 0) > 0) {
|
|
@@ -123564,12 +123750,22 @@ async function runAdPmaxCreate(opts) {
|
|
|
123564
123750
|
console.log("\n\u2705 Campaign \u9644\u52A0\u8D44\u4EA7\u5DF2\u6302\u8F7D");
|
|
123565
123751
|
}
|
|
123566
123752
|
}
|
|
123753
|
+
const followUpFailed = pmaxCreateFollowUpFailed({
|
|
123754
|
+
uploadError: videoResult.uploadError,
|
|
123755
|
+
linkError: videoResult.linkError,
|
|
123756
|
+
extensionsAllOk: extensionsResult ? extensionsResult.allOk : void 0
|
|
123757
|
+
});
|
|
123758
|
+
if (followUpFailed) {
|
|
123759
|
+
payload["created"] = true;
|
|
123760
|
+
payload["retryCreate"] = false;
|
|
123761
|
+
}
|
|
123567
123762
|
if (await emitCliJsonOrSnapshot(opts, {
|
|
123568
123763
|
section: `ad-pmax-create-${accountId}`,
|
|
123569
123764
|
commandLabel: "ad pmax-create",
|
|
123570
123765
|
commandHint: accountId,
|
|
123571
123766
|
payload,
|
|
123572
|
-
idSuffix: accountId
|
|
123767
|
+
idSuffix: accountId,
|
|
123768
|
+
summaryExtras: followUpFailed ? { created: true, retryCreate: false } : void 0
|
|
123573
123769
|
})) {
|
|
123574
123770
|
return;
|
|
123575
123771
|
}
|
package/dist/skill/_meta.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "siluzan-tso/google-period-report.schema.json",
|
|
4
4
|
"title": "GooglePeriodReport",
|
|
5
|
-
"description": "Google Ads 周期分析报告 JSON(对齐 google-period-report.md
|
|
5
|
+
"description": "Google Ads 周期分析报告 JSON(对齐 google-period-report.md 10 章:9 个数据维 + 优化建议;供 google-analysis render 注入 HTML)。Agent 只需撰写 narrative;kpis/charts/tables 由 --snapshot-dir 从 google-analysis 快照合并。render 校验要求合并后 kpis.cost/impressions/clicks 至少一项为有效数字,且 tables.negativeKeywords 为数组(0 条也要是 []),否则拒绝出 HTML。",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["meta", "narrative"],
|
|
8
8
|
"properties": {
|
|
@@ -93,7 +93,8 @@
|
|
|
93
93
|
"devices": { "$ref": "#/$defs/deviceRows" },
|
|
94
94
|
"geographic": { "$ref": "#/$defs/geographicRows" },
|
|
95
95
|
"audience": { "$ref": "#/$defs/audienceRows" },
|
|
96
|
-
"keywords": { "$ref": "#/$defs/keywordRows" }
|
|
96
|
+
"keywords": { "$ref": "#/$defs/keywordRows" },
|
|
97
|
+
"negativeKeywords": { "$ref": "#/$defs/negativeKeywordRows" }
|
|
97
98
|
}
|
|
98
99
|
},
|
|
99
100
|
"narrative": {
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
},
|
|
110
111
|
"sections": {
|
|
111
112
|
"type": "object",
|
|
112
|
-
"description": "
|
|
113
|
+
"description": "9 个数据维度各自的分析+建议(对应报告 §1~§9);每维度 analysis ≥2 条、suggestions ≥1 条",
|
|
113
114
|
"required": [
|
|
114
115
|
"overview",
|
|
115
116
|
"dailyTrend",
|
|
@@ -118,7 +119,8 @@
|
|
|
118
119
|
"devices",
|
|
119
120
|
"geographic",
|
|
120
121
|
"audience",
|
|
121
|
-
"keywords"
|
|
122
|
+
"keywords",
|
|
123
|
+
"negativeKeywords"
|
|
122
124
|
],
|
|
123
125
|
"properties": {
|
|
124
126
|
"overview": { "$ref": "#/$defs/sectionNarrative" },
|
|
@@ -128,12 +130,13 @@
|
|
|
128
130
|
"devices": { "$ref": "#/$defs/sectionNarrative" },
|
|
129
131
|
"geographic": { "$ref": "#/$defs/sectionNarrative" },
|
|
130
132
|
"audience": { "$ref": "#/$defs/sectionNarrative" },
|
|
131
|
-
"keywords": { "$ref": "#/$defs/sectionNarrative" }
|
|
133
|
+
"keywords": { "$ref": "#/$defs/sectionNarrative" },
|
|
134
|
+
"negativeKeywords": { "$ref": "#/$defs/sectionNarrative" }
|
|
132
135
|
}
|
|
133
136
|
},
|
|
134
137
|
"recommendations": {
|
|
135
138
|
"type": "array",
|
|
136
|
-
"description": "报告 §
|
|
139
|
+
"description": "报告 §10 优化建议;≥3 条,可跨维度综合",
|
|
137
140
|
"minItems": 3,
|
|
138
141
|
"items": {
|
|
139
142
|
"oneOf": [
|
|
@@ -249,6 +252,19 @@
|
|
|
249
252
|
"costPerConversion": { "type": "number" }
|
|
250
253
|
}
|
|
251
254
|
},
|
|
252
|
-
"keywordRows": { "type": "array", "items": { "$ref": "#/$defs/keywordRow" } }
|
|
255
|
+
"keywordRows": { "type": "array", "items": { "$ref": "#/$defs/keywordRow" } },
|
|
256
|
+
"negativeKeywordRow": {
|
|
257
|
+
"type": "object",
|
|
258
|
+
"description": "当前账户否词一行。0 条时数组为空,不要省略字段。",
|
|
259
|
+
"properties": {
|
|
260
|
+
"keyword": { "type": "string" },
|
|
261
|
+
"matchType": { "type": "string" },
|
|
262
|
+
"level": { "type": "string" },
|
|
263
|
+
"levelZh": { "type": "string" },
|
|
264
|
+
"campaignName": { "type": "string" },
|
|
265
|
+
"adGroupName": { "type": "string" }
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"negativeKeywordRows": { "type": "array", "items": { "$ref": "#/$defs/negativeKeywordRow" } }
|
|
253
269
|
}
|
|
254
270
|
}
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"勿用 Search 的 ExtensionsForBatchJob;PMax 用 campaignExtensions(CLI 会尝试自动转换 CALLOUT/SNIPPET)",
|
|
17
17
|
"Lead Gen/B2B 询盘方案:默认保留 campaignExtensions.leadForm(勿只写 callouts/snippets);用户明确不要表单才删 leadForm",
|
|
18
18
|
"审查稿须单列「潜在客户表单」节(标题/描述/字段/privacyPolicyUrl);结构见 google-ads-pmax-launch-plan-template.md",
|
|
19
|
-
"不需要任何附加资产时设 skipCampaignExtensions: true(勿仅删除 campaignExtensions 块)"
|
|
19
|
+
"不需要任何附加资产时设 skipCampaignExtensions: true(勿仅删除 campaignExtensions 块)",
|
|
20
|
+
"创建失败:只有 400 且编号变多时,才把非空 budgetId / campaignId / assetGroupId 写回本 JSON 再跑一次,内容不改。首次创建不填。已经 200 只是扩展失败就不要再 pmax-create"
|
|
20
21
|
]
|
|
21
22
|
},
|
|
22
23
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
| Lead Gen 方案 | **默认**在 `campaignExtensions` 含 **`leadForm`**(B2B/询盘/留资);仅 callouts/snippets 不算完整方案;用户明确不要才省略 |
|
|
23
23
|
| 存量补表单 | 活动已创建时用 `ad extension lead-form`(见 `pmax-lead-form-template.md` 方式 B) |
|
|
24
24
|
| 改已上线 PMax | 先 `ad pmax-get` 看 `_brandGuidelinesActive`;改品牌见 `pmax-api.md` § Brand Guidelines |
|
|
25
|
+
| 创建失败 | 只有创建接口 400,且编号比这次请求多,才把非空的 `budgetId` / `campaignId` / `assetGroupId` 写回同一份 JSON,其余内容不要改,再 `pmax-create` 一次。首次创建不填这三个字段。同一步再失败就停。已经 200、只是扩展或视频失败:不要再 `pmax-create` |
|
|
25
26
|
| 列表复核 | `ad campaigns -a <id> --json-out ./snap`,`channelTypeV2` 应为 `PERFORMANCE_MAX` |
|
|
26
27
|
|
|
27
28
|
---
|
|
@@ -81,6 +82,9 @@ siluzan-tso ad campaigns -a <accountId> --json-out ./snap
|
|
|
81
82
|
| `targetCpa_BidingAmount` | number | | `TARGET_CPA` 或带目标 CPA 的 `MAXIMIZE_CONVERSIONS` 时必填(**元**) |
|
|
82
83
|
| `targetRoas` | number | | `TARGET_ROAS` 时必填(如 `2.5` = 250%) |
|
|
83
84
|
| `brandGuidelinesEnabled` | boolean | | 省略 = 网关默认 `true`(Campaign 级 BG);`false` = 品牌在 AssetGroup(旧路径) |
|
|
85
|
+
| `budgetId` | string | | 上次创建失败后已经建成的预算编号。空着就新建。续跑时和下面两个编号一起写回,其余字段不要改 |
|
|
86
|
+
| `campaignId` | string | | 上次创建失败后已经建成的系列编号。必须和 `budgetId` 一起传 |
|
|
87
|
+
| `assetGroupId` | string | | 上次创建失败后已经建成的素材组编号。必须和 `budgetId`、`campaignId` 一起传。默认 BG 开启时不能只写到系列 |
|
|
84
88
|
| `videoPath` | string | | YOUTUBE_VIDEO(可选):本地视频 ≥10s;与 `youtubeUrlOrId` 二选一,创建时最多 1 条;更多视频创建后用 `pmax-youtube-link` / `pmax-assets-update` 追加 |
|
|
85
89
|
| `videoTitle` | string | | PyAPI 上传标题(默认文件名) |
|
|
86
90
|
| `videoDescription` | string | | PyAPI 上传描述(可选) |
|
|
@@ -130,7 +134,17 @@ siluzan-tso ad campaigns -a <accountId> --json-out ./snap
|
|
|
130
134
|
| -------------- | -------------------------------------------------- |
|
|
131
135
|
| `campaignId` | 活动 ID |
|
|
132
136
|
| `assetGroupId` | 首个资产组 ID |
|
|
133
|
-
| `budgetId` | 日预算 ID(后续 PATCH 改预算时需与 `budget`
|
|
137
|
+
| `budgetId` | 日预算 ID(后续 PATCH 改预算时需与 `budget` 成对;创建失败后续跑也用它) |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 创建失败后续跑
|
|
142
|
+
|
|
143
|
+
`POST .../campaign/pmax` 失败时返回 **JSON**,不再是纯文本。`message` 是原因。`budgetId`、`campaignId`、`assetGroupId` 里非空的是已经建成的编号,没建成的是 `null`。
|
|
144
|
+
|
|
145
|
+
把非空编号按同名写回**同一份** JSON,其余内容不要改,再执行一次 `pmax-create`。CLI 会原样转发这三个字段,不会改已有预算金额或系列名称。首次创建不要填它们。不带编号再提交会新建一套。编号按预算、系列、素材组带。默认品牌手册开启时不能只写 `campaignId`。同一步再失败就停(stdout 摘要 `retryCreate=false`)。
|
|
146
|
+
|
|
147
|
+
创建接口已经 **200**,只是附加资产或视频没挂上:活动已经在,**不要再 `pmax-create`**。扩展用 `ad extension`,视频用 `ad pmax-youtube-link`。这时 stdout 摘要是 `created=true`、`retryCreate=false`。
|
|
134
148
|
|
|
135
149
|
---
|
|
136
150
|
|
|
@@ -170,7 +170,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
|
|
|
170
170
|
| 状态 | 含义 | 下一步操作 |
|
|
171
171
|
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
172
172
|
| `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
|
|
173
|
-
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www
|
|
173
|
+
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Yandex 当前没有对应充值界面) |
|
|
174
174
|
| `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
|
|
175
175
|
|
|
176
176
|
---
|
|
@@ -490,7 +490,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
490
490
|
|
|
491
491
|
| 功能 | 媒体 | 网页路径 |
|
|
492
492
|
| --------------------------------------- | ------ | ------------------------------------------------- |
|
|
493
|
-
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www
|
|
493
|
+
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
494
494
|
|
|
495
495
|
**Agent 建议话术**:
|
|
496
496
|
|
|
@@ -499,5 +499,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
499
499
|
siluzan-tso config show # 查看 webUrl 字段
|
|
500
500
|
|
|
501
501
|
# 账户激活(Google)→ 引导至账户管理页
|
|
502
|
-
# https://www
|
|
502
|
+
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
503
503
|
```
|
|
@@ -126,7 +126,7 @@ siluzan-tso config show
|
|
|
126
126
|
|
|
127
127
|
### 充值页链接(按媒体 × 类型)
|
|
128
128
|
|
|
129
|
-
链接模式:`https://www
|
|
129
|
+
链接模式:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
|
|
130
130
|
|
|
131
131
|
| 充值类型 | `<page>` | 支持媒体(`mediaType` 参数) |
|
|
132
132
|
| ------------------------- | --------------------- | ------------------------------------------- |
|