siluzan-tso-cli 1.1.44-beta.1 → 1.1.44-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 -1
- package/dist/index.js +46 -19
- package/dist/skill/SKILL.md +2 -2
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/accounts/accounts-balance-stats.md +2 -2
- package/dist/skill/references/accounts/accounts-list.md +3 -3
- package/dist/skill/references/accounts/accounts-permissions.md +8 -8
- package/dist/skill/references/accounts/accounts.md +1 -1
- package/dist/skill/references/core/agent-conventions.md +7 -6
- package/dist/skill/references/core/workflows.md +1 -1
- package/dist/skill/references/google-ads/google-ads-campaign-plan.md +9 -8
- package/dist/skill/references/google-ads/google-ads-write.md +5 -5
- package/dist/skill/references/google-ads/google-ads.md +2 -2
- package/dist/skill/references/report-templates/google-ads-diagnosis.md +6 -6
- package/dist/skill/report-templates/GoogleAdsDiagnosisReport.html +291 -230
- package/dist/skill/report-templates/google-ads-diagnosis.md +6 -6
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.44-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.44-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -105835,7 +105835,11 @@ function register5(program2) {
|
|
|
105835
105835
|
}
|
|
105836
105836
|
|
|
105837
105837
|
// src/commands/list-accounts/_shared.ts
|
|
105838
|
+
init_dist();
|
|
105838
105839
|
init_auth();
|
|
105840
|
+
function shouldExposeScopeActivatedSources() {
|
|
105841
|
+
return resolveCompanySourceType() === "Ctaiad";
|
|
105842
|
+
}
|
|
105839
105843
|
var VALID_MEDIA_TYPES = [
|
|
105840
105844
|
"Google",
|
|
105841
105845
|
"TikTok",
|
|
@@ -105974,6 +105978,10 @@ function stripListAccountsEnrichmentFields(item) {
|
|
|
105974
105978
|
]) {
|
|
105975
105979
|
delete maExt[key];
|
|
105976
105980
|
}
|
|
105981
|
+
if (!shouldExposeScopeActivatedSources()) {
|
|
105982
|
+
delete item.ma.scopeActivatedSources;
|
|
105983
|
+
delete maExt["scopeActivatedSources"];
|
|
105984
|
+
}
|
|
105977
105985
|
}
|
|
105978
105986
|
async function fetchGoogleAccountByMediaCustomerId(config, mediaCustomerId, verbose) {
|
|
105979
105987
|
const cfg = PLATFORM_CONFIG.Google;
|
|
@@ -106058,7 +106066,7 @@ var COL_TIKTOK = [
|
|
|
106058
106066
|
{ key: "createdAt", header: "\u6388\u6743/\u5F00\u6237\u65F6\u95F4" },
|
|
106059
106067
|
{ key: "shared", header: "\u5206\u4EAB\u8D26\u6237" }
|
|
106060
106068
|
];
|
|
106061
|
-
var
|
|
106069
|
+
var COL_GOOGLE_BASE = [
|
|
106062
106070
|
{ key: "company", header: "\u516C\u53F8\u540D\u79F0" },
|
|
106063
106071
|
{ key: "id", header: "\u8D26\u6237ID" },
|
|
106064
106072
|
{ key: "name", header: "\u8D26\u6237\u540D\u79F0" },
|
|
@@ -106071,11 +106079,17 @@ var COL_GOOGLE = [
|
|
|
106071
106079
|
{ key: "arit", header: "Arit" },
|
|
106072
106080
|
{ key: "platformStatus", header: "\u8D26\u6237\u72B6\u6001" },
|
|
106073
106081
|
{ key: "authStatus", header: "\u6388\u6743\u72B6\u6001" },
|
|
106074
|
-
/** 对应 JSON `ma.scopeActivatedSources`(有未过期记录=已激活) */
|
|
106075
|
-
{ key: "packageStatus", header: "\u5957\u9910\u6FC0\u6D3B" },
|
|
106076
106082
|
{ key: "createdAt", header: "\u6388\u6743/\u5F00\u6237\u65F6\u95F4" },
|
|
106077
106083
|
{ key: "shared", header: "\u5206\u4EAB" }
|
|
106078
106084
|
];
|
|
106085
|
+
var COL_GOOGLE_PACKAGE = { key: "packageStatus", header: "\u5957\u9910\u6FC0\u6D3B" };
|
|
106086
|
+
function googleTableColumns() {
|
|
106087
|
+
if (!shouldExposeScopeActivatedSources()) return COL_GOOGLE_BASE;
|
|
106088
|
+
const authIdx = COL_GOOGLE_BASE.findIndex((c) => c.key === "authStatus");
|
|
106089
|
+
const cols = [...COL_GOOGLE_BASE];
|
|
106090
|
+
cols.splice(authIdx + 1, 0, COL_GOOGLE_PACKAGE);
|
|
106091
|
+
return cols;
|
|
106092
|
+
}
|
|
106079
106093
|
function formatTikTokAuditStatus(ma) {
|
|
106080
106094
|
const state = ma.mediaAccountState ?? "";
|
|
106081
106095
|
const tt = ma.TTADInfo?.status ?? "";
|
|
@@ -106245,11 +106259,12 @@ function printTikTokTable(items2, tableOpts) {
|
|
|
106245
106259
|
printCliTable(rows, COL_TIKTOK, tableOpts);
|
|
106246
106260
|
}
|
|
106247
106261
|
function printGoogleTable(items2, tableOpts) {
|
|
106262
|
+
const exposePackage = shouldExposeScopeActivatedSources();
|
|
106248
106263
|
const rows = items2.map((item) => {
|
|
106249
106264
|
const ma = item.ma;
|
|
106250
106265
|
const platformStatus = ma.platformStatus ?? "-";
|
|
106251
106266
|
const sharedCount = Array.isArray(ma.accountIds) ? String(Math.max(0, ma.accountIds.length - 1)) : "-";
|
|
106252
|
-
|
|
106267
|
+
const row = {
|
|
106253
106268
|
company: item.mag?.advertiserName ?? "-",
|
|
106254
106269
|
id: String(ma.mediaCustomerId ?? "(\u672A\u5F00\u901A)"),
|
|
106255
106270
|
name: ma.mediaCustomerName ?? "-",
|
|
@@ -106262,12 +106277,15 @@ function printGoogleTable(items2, tableOpts) {
|
|
|
106262
106277
|
arit: String(ma.aritScore ?? "-"),
|
|
106263
106278
|
platformStatus,
|
|
106264
106279
|
authStatus: formatOAuthAuthStatus(ma),
|
|
106265
|
-
packageStatus: formatScopeActivatedStatus(ma),
|
|
106266
106280
|
createdAt: fmtDate(ma.createdDateTime),
|
|
106267
106281
|
shared: sharedCount
|
|
106268
106282
|
};
|
|
106283
|
+
if (exposePackage) {
|
|
106284
|
+
row.packageStatus = formatScopeActivatedStatus(ma);
|
|
106285
|
+
}
|
|
106286
|
+
return row;
|
|
106269
106287
|
});
|
|
106270
|
-
printCliTable(rows,
|
|
106288
|
+
printCliTable(rows, googleTableColumns(), tableOpts);
|
|
106271
106289
|
}
|
|
106272
106290
|
var COL_DEFAULT_WITH_MEDIA = [
|
|
106273
106291
|
{ key: "mediaType", header: "\u5A92\u4F53\u7C7B\u578B" },
|
|
@@ -116667,9 +116685,9 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116667
116685
|
const remediateCount = missing.filter((m) => m.remediateCommand).length;
|
|
116668
116686
|
let agentHint;
|
|
116669
116687
|
if (!ok) {
|
|
116670
|
-
agentHint = `\u53D1\u73B0 ${missing.length} \u9879\u4E0E\u8BA1\u5212\u4E0D\u4E00\u81F4\uFF08\u8BE6\u89C1 items[] / reportMarkdown\uFF1A\u2705${statusCounts.ok} / \u274C${missing.length} / \u23ED${statusCounts.skipped}\uFF09` + (remediateCount > 0 ? `\
|
|
116688
|
+
agentHint = `\u53D1\u73B0 ${missing.length} \u9879\u4E0E\u8BA1\u5212\u4E0D\u4E00\u81F4\uFF08\u8BE6\u89C1 items[] / reportMarkdown\uFF1A\u2705${statusCounts.ok} / \u274C${missing.length} / \u23ED${statusCounts.skipped}\uFF09\u3002**\u7ACB\u523B**\u628A\u672C\u547D\u4EE4 stdout \u4E2D BEGIN_USER_DELIVERY_MARKDOWN\u2026END \u5168\u6587\u539F\u6837\u53D1\u7ED9\u7528\u6237\uFF08\u7981\u6B62\u6458\u8981/\u7981\u6B62\u53EA\u8BF4\u300C\u521B\u5EFA\u6210\u529F\u300D\uFF09\uFF0C` + (remediateCount > 0 ? `\u4EA4\u4ED8\u540E\u518D\u6267\u884C ${remediateCount} \u6761 remediateCommand \u8865\u5EFA\uFF08\u52FF\u56E0\u8865\u5EFA\u63A8\u8FDF\u4EA4\u4ED8\uFF09` : "\u4EA4\u4ED8\u540E\u518D\u6309 layer \u8865\u5EFA") + "\uFF1B\u8865\u5EFA\u540E\u518D\u6B21 ad batch diff \u5E76\u518D\u6B21\u4EA4\u4ED8\u66F4\u65B0\u540E\u7684 Markdown\u3002";
|
|
116671
116689
|
} else {
|
|
116672
|
-
agentHint = `\u4E0E JSON \u8BA1\u5212\u4E00\u81F4\uFF08\u542B\u6295\u653E\u5730\u57DF\uFF1Bitems[] \u5171 ${statusCounts.ok} \u6761\u5747\u4E3A ok\uFF09\u3002**\
|
|
116690
|
+
agentHint = `\u4E0E JSON \u8BA1\u5212\u4E00\u81F4\uFF08\u542B\u6295\u653E\u5730\u57DF\uFF1Bitems[] \u5171 ${statusCounts.ok} \u6761\u5747\u4E3A ok\uFF09\u3002**\u7ACB\u523B**\u628A\u672C\u547D\u4EE4 stdout \u4E2D BEGIN_USER_DELIVERY_MARKDOWN\u2026END \u5168\u6587\u539F\u6837\u53D1\u7ED9\u7528\u6237\uFF1B\u7981\u6B62\u53EA\u8BF4\u300C\u672A\u53D1\u73B0\u7F3A\u5931\u300D\u6216\u53EA\u8D34 counts \u6458\u8981\u3002`;
|
|
116673
116691
|
}
|
|
116674
116692
|
return {
|
|
116675
116693
|
accountId,
|
|
@@ -116845,7 +116863,7 @@ function buildBatchGetAgentWorkflow(opts) {
|
|
|
116845
116863
|
configFile: opts.configFile,
|
|
116846
116864
|
campaignId: campaignId ?? void 0
|
|
116847
116865
|
});
|
|
116848
|
-
agentHint = `\u5FC5\u505A\u4E0B\u4E00\u6B65\uFF1A\u6267\u884C nextCommand\uFF08ad batch diff\uFF09\
|
|
116866
|
+
agentHint = `\u5FC5\u505A\u4E0B\u4E00\u6B65\uFF1A\u6267\u884C nextCommand\uFF08ad batch diff\uFF09\u3002diff \u7684 stdout \u542B BEGIN_USER_DELIVERY_MARKDOWN\u2026END\u2014\u2014**\u7ACB\u523B\u539F\u6837\u53D1\u7ED9\u7528\u6237**\uFF08\u52FF\u6458\u8981\u3001\u52FF\u7B49\u8865\u5EFA\u7ED3\u675F\uFF09\uFF1B\u6709 remediateCommand \u5219\u4EA4\u4ED8\u540E\u518D\u8865\u5EFA\u5E76\u518D\u8DD1 diff\u3002`;
|
|
116849
116867
|
}
|
|
116850
116868
|
} else {
|
|
116851
116869
|
agentHint = `\u5F53\u524D status=${status || "\u2014"}\uFF0C\u6309 google-ads.md \xA7 batch \u5904\u7406\u3002`;
|
|
@@ -116922,7 +116940,7 @@ function printBatchDiffFollowUpHint(opts) {
|
|
|
116922
116940
|
console.log(` ${cmd}
|
|
116923
116941
|
`);
|
|
116924
116942
|
console.log(
|
|
116925
|
-
" Agent\uFF1A\u5E26 --json-out \u4E0E --md-out\
|
|
116943
|
+
" Agent\uFF1A\u5E26 --json-out \u4E0E --md-out\uFF1Bdiff \u540E**\u7ACB\u523B**\u628A stdout \u4E2D BEGIN_USER_DELIVERY_MARKDOWN\u2026END \u5168\u6587\u53D1\u7ED9\u7528\u6237\uFF0C\u518D\u5904\u7406 missing[].remediateCommand\u3002\n"
|
|
116926
116944
|
);
|
|
116927
116945
|
}
|
|
116928
116946
|
var LAYER_ORDER = [
|
|
@@ -117092,6 +117110,19 @@ function writeCampaignCreateStatusMarkdown(result, mdPath) {
|
|
|
117092
117110
|
fs9.writeFileSync(mdPath, reportMarkdown, "utf8");
|
|
117093
117111
|
return { reportMarkdown, reportMarkdownFile: mdPath };
|
|
117094
117112
|
}
|
|
117113
|
+
var USER_DELIVERY_MARKDOWN_BEGIN = "\u2500\u2500 BEGIN_USER_DELIVERY_MARKDOWN \uFF08\u5FC5\u987B\u539F\u6837\u7C98\u8D34\u5230\u5BF9\u7528\u6237\u7684\u4E0B\u4E00\u6761\u6D88\u606F\uFF1B\u7981\u6B62\u6458\u8981\u4EE3\u66FF\uFF1B\u4EA4\u4ED8\u4F18\u5148\u4E8E\u8865\u5EFA\uFF09\u2500\u2500";
|
|
117114
|
+
var USER_DELIVERY_MARKDOWN_END = "\u2500\u2500 END_USER_DELIVERY_MARKDOWN \u2500\u2500";
|
|
117115
|
+
function printBatchDiffUserDeliveryMarkdown(report) {
|
|
117116
|
+
console.log(`
|
|
117117
|
+
\u{1F4C4} \u521B\u5EFA\u8BE6\u60C5 Markdown \u5DF2\u5199\u5165\uFF1A${report.reportMarkdownFile}`);
|
|
117118
|
+
console.log(
|
|
117119
|
+
" Agent\uFF1A\u4E0B\u4E00\u6761\u5BF9\u7528\u6237\u6D88\u606F\u5FC5\u987B\u662F\u4E0B\u65B9 BEGIN\u2026END \u4E4B\u95F4\u7684 Markdown \u5168\u6587\uFF1B\u7981\u6B62\u53EA\u8BF4\u300C\u521B\u5EFA\u6210\u529F/\u8BE6\u60C5\u5DF2\u4EA4\u4ED8\u300D\u3002\n"
|
|
117120
|
+
);
|
|
117121
|
+
console.log(USER_DELIVERY_MARKDOWN_BEGIN);
|
|
117122
|
+
console.log(report.reportMarkdown.replace(/\s+$/, ""));
|
|
117123
|
+
console.log(USER_DELIVERY_MARKDOWN_END);
|
|
117124
|
+
console.log();
|
|
117125
|
+
}
|
|
117095
117126
|
function formatBatchDiffGrouped(result) {
|
|
117096
117127
|
console.log(
|
|
117097
117128
|
`
|
|
@@ -117247,10 +117278,7 @@ async function runCampaignBatchDiff(opts) {
|
|
|
117247
117278
|
...result,
|
|
117248
117279
|
...report
|
|
117249
117280
|
};
|
|
117250
|
-
|
|
117251
|
-
\u{1F4C4} \u521B\u5EFA\u8BE6\u60C5 Markdown \u5DF2\u5199\u5165\uFF1A${report.reportMarkdownFile}`);
|
|
117252
|
-
console.log(` Agent\uFF1A\u5FC5\u987B\u5C06 reportMarkdown \u5168\u6587\u4EE5 Markdown \u6D88\u606F\u53D1\u7ED9\u7528\u6237\uFF08\u52FF\u6458\u8981\uFF09\u3002
|
|
117253
|
-
`);
|
|
117281
|
+
printBatchDiffUserDeliveryMarkdown(report);
|
|
117254
117282
|
if (await emitCliJsonOrSnapshot(
|
|
117255
117283
|
{ jsonOut: opts.jsonOut },
|
|
117256
117284
|
{
|
|
@@ -121092,7 +121120,7 @@ function register21(program2) {
|
|
|
121092
121120
|
}
|
|
121093
121121
|
);
|
|
121094
121122
|
adBatchCmd.command("diff").description(
|
|
121095
|
-
"\u6210\u529F\u6216\u90E8\u5206\u6210\u529F\uFF1A\u6309 campaign-create JSON \u4E0E\u8D26\u6237\u5B9E\u51B5\u9010\u5C42\u6BD4\u5BF9\uFF08\u542B\u6295\u653E\u56FD\u5BB6/\u5730\u57DF\uFF09\n \u8F93\u51FA\u8BA1\u5212\u5168\u91CF items[] + Markdown \u521B\u5EFA\u8BE6\u60C5\
|
|
121123
|
+
"\u6210\u529F\u6216\u90E8\u5206\u6210\u529F\uFF1A\u6309 campaign-create JSON \u4E0E\u8D26\u6237\u5B9E\u51B5\u9010\u5C42\u6BD4\u5BF9\uFF08\u542B\u6295\u653E\u56FD\u5BB6/\u5730\u57DF\uFF09\n \u8F93\u51FA\u8BA1\u5212\u5168\u91CF items[] + Markdown \u521B\u5EFA\u8BE6\u60C5\uFF08stdout \u4EA4\u4ED8\u5757 + reportMarkdown / --md-out\uFF09\n Agent \u5FC5\u987B\u628A BEGIN_USER_DELIVERY_MARKDOWN\u2026END \u5168\u6587\u53D1\u7ED9\u7528\u6237\uFF08\u5148\u4E8E\u8865\u5EFA\uFF09\uFF1B\u6709\u7F3A\u5931\u65F6 exit 2\n Failed \u4E0D\u9002\u7528\uFF08\u7CFB\u5217\u672A\u521B\u5EFA\uFF09\uFF0C\u8BF7\u7528 ad batch get \u67E5\u770B reason/errors \u540E\u6539 JSON \u91CD\u63D0\n\n \u793A\u4F8B\uFF1A\n siluzan-tso ad batch diff --batch-id <taskId> --config-file ./campaign.json --json-out ./snap-campaign --md-out ./snap-campaign/campaign-create-status.md\n siluzan-tso ad batch diff --campaign-id <id> --config-file ./campaign.json"
|
|
121096
121124
|
).requiredOption("--config-file <path>", "\u63D0\u4EA4\u65F6\u4F7F\u7528\u7684 campaign-create JSON").option(
|
|
121097
121125
|
"--campaign-id <id>",
|
|
121098
121126
|
"Google \u5E7F\u544A\u7CFB\u5217 ID\uFF08\u53EF\u4ECE ad campaigns --json-out \u83B7\u53D6\uFF1B\u7701\u7565\u65F6\u6309\u7CFB\u5217\u540D\u5339\u914D\uFF09"
|
|
@@ -128604,7 +128632,6 @@ function createDefaultDiagnosisReportData() {
|
|
|
128604
128632
|
keywordCount: 0,
|
|
128605
128633
|
adCount: 0,
|
|
128606
128634
|
extensionCount: 0,
|
|
128607
|
-
negativeKeywordCount: 0,
|
|
128608
128635
|
countriesWithConversionsCount: 0
|
|
128609
128636
|
},
|
|
128610
128637
|
conversionGoals: { items: [] },
|
|
@@ -128937,7 +128964,7 @@ function buildStructureCounts(resourceRecord, campaignRows2, keywordRows, search
|
|
|
128937
128964
|
keywordCount,
|
|
128938
128965
|
adCount: num(resourceRecord?.adCount),
|
|
128939
128966
|
extensionCount: num(resourceRecord?.extensionCount),
|
|
128940
|
-
negativeKeywordCount
|
|
128967
|
+
// collect 未拉取否词明细,不输出 negativeKeywordCount(避免报告展示 0 误导)
|
|
128941
128968
|
countriesWithConversionsCount: num(resourceRecord?.countriesWithConversionsCount),
|
|
128942
128969
|
searchTermCount: searchRows.length
|
|
128943
128970
|
};
|
|
@@ -129098,6 +129125,7 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
129098
129125
|
loadSectionSnapshot(snapDir, "resource-counts", accountId, start, end)
|
|
129099
129126
|
);
|
|
129100
129127
|
const goldRecord = sectionRecord(loadSectionSnapshot(snapDir, "gold-account", accountId, start, end)) ?? {};
|
|
129128
|
+
delete goldRecord.adsNegativeQualified;
|
|
129101
129129
|
const campaignCurrent = sectionItems(
|
|
129102
129130
|
loadSectionSnapshot(snapDir, "campaigns", accountId, start, end)
|
|
129103
129131
|
);
|
|
@@ -129167,7 +129195,6 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
129167
129195
|
keywordCount: structureCounts.keywordCount,
|
|
129168
129196
|
adCount: structureCounts.adCount,
|
|
129169
129197
|
extensionCount: structureCounts.extensionCount,
|
|
129170
|
-
negativeKeywordCount: structureCounts.negativeKeywordCount,
|
|
129171
129198
|
countriesWithConversionsCount: structureCounts.countriesWithConversionsCount
|
|
129172
129199
|
};
|
|
129173
129200
|
data.conversionGoals = {
|
|
@@ -129902,7 +129929,7 @@ var NARRATIVE_CONSISTENCY_RULES = [
|
|
|
129902
129929
|
id: "negative-keyword-zero-as-core-issue",
|
|
129903
129930
|
textPattern: /否定(关键)?词.{0,40}(为\s*0|数量为\s*0|为0|缺少|没有)/,
|
|
129904
129931
|
isContradicted: () => true,
|
|
129905
|
-
hint: "\u7981\u6B62\u5C06\u300C\u5426\u5B9A\u5173\u952E\u8BCD\u6570\u91CF\u4E3A 0 / \u7F3A\u5C11\u5426\u8BCD\u300D\u5199\u5165 summary.keyIssues \u6216 diagnosisOverview.disadvantages\
|
|
129932
|
+
hint: "\u672C\u62A5\u544A collect \u672A\u62C9\u53D6\u5426\u8BCD\u6570\u636E\uFF0C\u7981\u6B62\u5C06\u300C\u5426\u5B9A\u5173\u952E\u8BCD\u6570\u91CF\u4E3A 0 / \u7F3A\u5C11\u5426\u8BCD\u300D\u5199\u5165 summary.keyIssues \u6216 diagnosisOverview.disadvantages\u3002\u6709\u641C\u7D22\u8BCD\u6D6A\u8D39\u65F6\u4EC5\u5728 \xA708 \u6309\u5177\u4F53\u641C\u7D22\u8BCD\u5199\u4F18\u5316\u5EFA\u8BAE\uFF0C\u52FF\u4EE5\u5426\u8BCD\u8BA1\u6570\u4E0B\u7ED3\u8BBA\u3002"
|
|
129906
129933
|
},
|
|
129907
129934
|
{
|
|
129908
129935
|
id: "landing-page-missing-as-core-issue",
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -40,10 +40,10 @@ siluzan-tso -h
|
|
|
40
40
|
|
|
41
41
|
- `entityId`(UUID)≠ `mediaCustomerId`(`list-accounts` 的 `ma.mediaCustomerId`:Google/TikTok/Bing 多为数字;**Yandex=`porg-…`**;Meta 常带 `act_`)。`stats`/`balance`/`accounts-digest`/`ad *` 的 `-a` **只传 mediaCustomerId**;空结果或 verbose 打出 403 时**先核验 ID**,禁止把 UUID/`entityId` 传给 `-a`,也**禁止**据此直接 `reauth`。
|
|
42
42
|
- **Google CID 特殊性**:UI 常写 `123-456-7890`(带连字符),平台 `mediaCustomerId` 为纯数字 `1234567890`。CLI 会自动去连字符;**勿**把带横杠 403 误判为 OAuth 失效。优先用 `list-accounts` 的纯数字 ID。
|
|
43
|
-
- **禁止臆测授权过期**:见 403/`HTTP 403`/拉数失败/「可能 OAuth 失效」时,**禁止**口头推断授权过期或直接 `reauth`。须先核验 ID(及 Google 连字符),再跑 `account check-access -a <mediaCustomerId
|
|
43
|
+
- **禁止臆测授权过期**:见 403/`HTTP 403`/拉数失败/「可能 OAuth 失效」时,**禁止**口头推断授权过期或直接 `reauth`。须先核验 ID(及 Google 连字符),再跑 `account check-access -a <mediaCustomerId>`,以返回的 `accessible` / `reauth_required` / `no_permission` 为准;仅当 `list-accounts` 输出含激活字段且可判定未激活时才跳过用其判断授权过期;细则见 `accounts-permissions.md`。
|
|
44
44
|
- **Google 广告命令名**:列表是 `ad campaigns`(不是 `ad-campaigns` / `campaign list`);`balance`/`stats` 须带 `-m Google`;单国地域用 `ad geo search … --json-out`(或 `geo resolve`)。
|
|
45
45
|
- **Google 广告类型边界**:CLI/Skill **仅支持** Google **搜索广告(Search)** 与 **Performance Max(PMax)** 的方案、创建与精细管理;**不支持展示广告(Display)**(含自适应展示广告 RDA、独立 Display 系列)。用户要做展示广告时须明确告知不支持,可改推 Search / PMax;**禁止**用 `campaign-create` / `ad-create` 伪装创建 Display。
|
|
46
|
-
-
|
|
46
|
+
- **创建完成后交付(硬性)**:`ad batch diff` 的 stdout 含 `BEGIN_USER_DELIVERY_MARKDOWN`…`END_USER_DELIVERY_MARKDOWN`——**立刻**把中间全文原样发给用户(可先于补建);禁止只摘要、禁止只说「创建成功/详情已交付/未发现缺失」、禁止等全部补建结束再交付。
|
|
47
47
|
- `list-accounts` 无余额/消耗;列全部用 `--page-size 999`。
|
|
48
48
|
- 多户余额用 `balance-scan`(P2),多户消耗用 `accounts-digest`(P3);禁止外层 for-loop 逐户拉数。
|
|
49
49
|
- `stats` 的 `spend` = **区间合计**,不是日消耗。
|
package/dist/skill/_meta.json
CHANGED
|
@@ -181,9 +181,9 @@ siluzan-tso stats -m <媒体类型> [选项]
|
|
|
181
181
|
|
|
182
182
|
1. 用户若已给出账户号(如 Yandex `porg-kqquuxx6`),`-a` **必须原样用该 mediaCustomerId**;先 `list-accounts -m <媒体> -k <mediaCustomerId>` 核验存在即可。
|
|
183
183
|
2. **禁止**把 `ma.entityId`、`externalMediaAccountTokenId` 或会话里其它 UUID 传给 `-a`(会空结果,verbose 常打出被吞的 `HTTP 403`,**不等于** OAuth 过期)。
|
|
184
|
-
3. Google
|
|
184
|
+
3. Google:仅当 `list-accounts` **输出中出现** `scopeActivatedSources` 且可判定未激活时,才可向用户说明需先激活套餐;**若无该字段,禁止谈套餐激活**。空结果时按 CLI 报错/字段说明,**禁止**用非 CLI / 自拼请求等方式绕过。
|
|
185
185
|
4. 仅当 `list-accounts` 显示 `invalidOAuthToken=true`(或授权状态列为失效),且用户确认后,才走 `account reauth --id <entityId> --i-confirm --commit "…"`(见 `accounts-permissions.md`)。
|
|
186
|
-
5. `list-accounts` 显示 `Linked` + `hasToken:1` + `invalidOAuthToken=false
|
|
186
|
+
5. `list-accounts` 显示 `Linked` + `hasToken:1` + `invalidOAuthToken=false`(若有激活字段则须已激活)时,**禁止**因 stats/balance 空结果自行 `reauth`/解绑。
|
|
187
187
|
|
|
188
188
|
**示例:**
|
|
189
189
|
|
|
@@ -81,12 +81,12 @@ siluzan-tso list-accounts -m Google --page 2 --page-size 999 --json-out ./snap-p
|
|
|
81
81
|
| `ma.mediaCustomerName` | 账户名称(表格「账户名称」) |
|
|
82
82
|
| `ma.mediaAccountState` 等 | 平台开户/审核态(如 Approved / Linked);**不是** OAuth 是否可用 |
|
|
83
83
|
| **`ma.invalidOAuthToken`** | **OAuth 是否失效**:`true`=失效,`false`=正常。**表格必有「授权状态」列**(✅ 正常 / ⚠️ 失效),与此字段一一对应;判失效、筛 `-s invalid`、走 `reauth` 均看它 |
|
|
84
|
-
| **`ma.scopeActivatedSources
|
|
84
|
+
| **`ma.scopeActivatedSources`**(可选) | **仅当本次 `list-accounts` 输出中出现该字段时才可读**:非空且存在未过期条目(看 `expireAt`)= 已激活;空数组或全部过期 = 未激活。出现时 Google 表格才有「套餐激活」列。**若 JSON/表格中无此字段/列:禁止向用户谈套餐是否激活,禁止臆造未激活/已激活** |
|
|
85
85
|
| `ma.TTADInfo.status` 等 | 媒体侧投放/审核细态(TikTok 表格「审核状态」等);**勿**当成 OAuth 授权状态 |
|
|
86
86
|
|
|
87
87
|
> **Agent**:用户问「哪些授权失效 / OAuth 状态」时,读盘看 `items[].ma.invalidOAuthToken`,表格看「授权状态」列;**不要**用 `mediaAccountState` 或审核状态列代替。
|
|
88
|
-
> 用户问「哪些买了套餐 /
|
|
89
|
-
> **Google
|
|
88
|
+
> 用户问「哪些买了套餐 / 是否激活套餐」时:**仅当**输出含 `ma.scopeActivatedSources`(或 Google 表格有「套餐激活」列)才可据此回答;**缺失时直接说明当前环境无法查询套餐激活状态**,不要用 `mediaAccountState` / 授权状态代替,也不要去猜。
|
|
89
|
+
> **Google 单户**:若输出中能确认套餐**已激活**,可用 `account check-access -a <mediaCustomerId>` 再确认网关侧授权是否可用;若输出无激活字段,仍可直接跑 `check-access`(以返回 `status` 为准),**不要**先编造「未激活」。见 `accounts-permissions.md` § check-access。
|
|
90
90
|
|
|
91
91
|
---
|
|
92
92
|
|
|
@@ -35,23 +35,23 @@ siluzan-tso account me --check-phone 15130150466 --json-out ./snap-me
|
|
|
35
35
|
|
|
36
36
|
校验当前丝路赞凭据是否对指定 **Google** 广告账户有访问权限。应在拉数/诊断前调用,避免误用他户 ID。
|
|
37
37
|
|
|
38
|
-
> **硬约束**:**禁止**凭 403、空结果或经验臆测「授权/OAuth 过期」。要对用户下「授权不可用 /
|
|
38
|
+
> **硬约束**:**禁止**凭 403、空结果或经验臆测「授权/OAuth 过期」。要对用户下「授权不可用 / 需重授权」结论前,**必须**先跑本命令,以 CLI 返回的 `status` 为准;**禁止**跳过本命令直接 `reauth` 或口头推断。
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
**套餐激活字段(可选前提)**:若 `list-accounts` 输出中**出现** `ma.scopeActivatedSources`(或 Google「套餐激活」列),须先确认有未过期条目再据此谈「授权过期」;**输出中无该字段/列时:跳过套餐判断,直接跑本命令**,且**禁止**向用户解释套餐是否激活。
|
|
41
41
|
|
|
42
|
-
| 结果 |
|
|
43
|
-
| ---- |
|
|
42
|
+
| 结果 | 含义 |
|
|
43
|
+
| ---- | ---- |
|
|
44
44
|
| `accessible`(200 / `true`) | 授权可用,可继续拉数/操作 |
|
|
45
45
|
| `reauth_required`(200 / `false`) | 已绑定但 Google OAuth 不可用 → 走重授权 |
|
|
46
46
|
| `no_permission`(403 / 账户 ID) | 网关不可访问;可与 `list-accounts` 的 `invalidOAuthToken` 交叉确认是否授权失效或不在本账号下 |
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
**注意**:当输出能确认套餐**未激活**时,不要用本命令判断授权过期(未激活户仍可能返回 `accessible`)。无激活字段时不适用本条。
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
# 1)
|
|
51
|
+
# 1) 可选:list-accounts 核验账户;仅当输出含 scopeActivatedSources 时才看套餐
|
|
52
52
|
siluzan-tso list-accounts -m Google -k <mediaCustomerId> --json-out ./snap
|
|
53
53
|
|
|
54
|
-
# 2)
|
|
54
|
+
# 2) 查网关访问 / 授权是否可用
|
|
55
55
|
siluzan-tso account check-access -a <mediaCustomerId>
|
|
56
56
|
siluzan-tso account check-access -a 4256317784 --json-out ./snap-access
|
|
57
57
|
```
|
|
@@ -64,7 +64,7 @@ siluzan-tso account check-access -a 4256317784 --json-out ./snap-access
|
|
|
64
64
|
| 403 | `token不能为空` | 未绑定 Google 媒体 | `google_not_bound` → Agent 优先平台授权;备选 `account auth -m Google` |
|
|
65
65
|
| 401 | 空 | 丝路赞 Token 失效 | `siluzan_token_invalid` → 重新 login |
|
|
66
66
|
|
|
67
|
-
> 与 `list-accounts -k` 互补:`list-accounts` 查「是否在列表 /
|
|
67
|
+
> 与 `list-accounts -k` 互补:`list-accounts` 查「是否在列表 / `invalidOAuthToken`」(以及**若存在**则含套餐激活);本接口查「Google 网关是否允许当前凭据访问该 mediaCustomerId」。列表批量筛失效仍优先看 `invalidOAuthToken`;单户深查用本命令。
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
- `entityId`(UUID,分享/delink/账单/`reauth`)≠ `mediaCustomerId`(`balance`/`stats`/`accounts-digest`/`ad` 的 `-a`)。**Yandex 的 mediaCustomerId 形如 `porg-…`,不是 UUID。**
|
|
21
21
|
- MetaAd OAuth 户的 `mediaCustomerId` **须带 `act_` 前缀**。
|
|
22
22
|
- **Google CID**:广告后台展示常为 `XXX-XXX-XXXX`(连字符),`list-accounts` / 网关要的是**纯数字**(无横杠)。`stats`/`balance`/`ad *`/`google-analysis` 的 `-a` 可带连字符(CLI 会去掉);若仍见 `HTTP 403:123-456-7890` 这类**回显带横杠 ID**,优先改成纯数字重试,**不要**直接当 OAuth 失效去 `reauth`。
|
|
23
|
-
- **禁止臆测授权过期**:403 / 拉数失败时**禁止**口头说「可能授权过期」。须 ID 核验后,对 Google
|
|
23
|
+
- **禁止臆测授权过期**:403 / 拉数失败时**禁止**口头说「可能授权过期」。须 ID 核验后,对 Google 执行 `account check-access -a <mediaCustomerId>`,以返回 `status` 为准(见 [`accounts-permissions.md`](accounts-permissions.md));仅当 `list-accounts` 输出含激活字段且可判定未激活时,勿用其判断授权过期;非 Google 看 `invalidOAuthToken`。
|
|
24
24
|
- `stats`/`balance` 空结果 + verbose `HTTP 403`:先确认 `-a` 是否为 `ma.mediaCustomerId`(且 Google 已去连字符);**禁止**把 `entityId` / tokenId 当 `-a`;未跑 `account check-access`(或未见 `invalidOAuthToken=true`)**禁止** `reauth`。
|
|
25
25
|
- 多账户余额预警用 `balance-scan`(P2),多账户消耗汇总用 `accounts-digest`(P3);**禁止**外层 for-loop 逐户 `balance`/`stats`。
|
|
26
26
|
- `stats` 默认 `spend` = **区间合计**,不是日消耗;日均看 `balance-scan.dailySpend` 或合计÷天数。
|
|
@@ -127,8 +127,8 @@
|
|
|
127
127
|
- **账户状态 ≠ 系列状态**:`stats` / `balance` / `list-accounts` 的 `status` 只表示账户是否可用;系列状态必须来自 `ad campaigns`。
|
|
128
128
|
- **数据时效性**:涉及「今天/当天/今日消耗」「实时消耗排行」前,必读 `references/analytics/account-analytics.md` 顶部「数据时效性」表。TikTok / Yandex / BingV2 / Kwai 是 `accountsoverview` 同步昨天数据,**不能查今天**。
|
|
129
129
|
- **先查账户再操作**(拉数 / 改账户 / 报告 / **创建广告**):`list-accounts -m [mediaType] -k [mediaCustomerId]`;用户给出的 `mediaCustomerId` 必须 `-k` 核验,无结果则告知用户并停止,**禁止**翻页 grep 自行换 ID(会导致报告错户);拉数、脚本、报告文件名全链路用同一 ID(以 stdout `accountId` 为准)。
|
|
130
|
-
- **禁止臆测授权过期(硬约束)**:任何 403、空结果、「可能授权/OAuth 过期」话术,**禁止**凭感觉下结论或直接 `reauth`。Google
|
|
131
|
-
- **一律走 CLI,禁止自拼网关请求**:查余额 / 拉数 / 写操作只用 `siluzan-tso …`。**禁止**用 curl、自写脚本或改请求头直连 TSO/Google 网关「另辟蹊径」取数;`balance` 等无数据时按 CLI/`list-accounts`
|
|
130
|
+
- **禁止臆测授权过期(硬约束)**:任何 403、空结果、「可能授权/OAuth 过期」话术,**禁止**凭感觉下结论或直接 `reauth`。Google:**必须**执行 `account check-access -a <mediaCustomerId>`,仅当结果为 `reauth_required`(或列表 `invalidOAuthToken=true` 与之交叉确认)才谈重授权;`no_permission` 也可能是账户不在当前丝路赞账号下。若 `list-accounts` **输出含** `scopeActivatedSources` 且可判定未激活,则勿用 check-access 判断授权过期;**无该字段时禁止谈套餐激活**。非 Google 媒体以 `list-accounts` 的 `invalidOAuthToken` 为准,同样禁止臆测。详见 `accounts-permissions.md`。
|
|
131
|
+
- **一律走 CLI,禁止自拼网关请求**:查余额 / 拉数 / 写操作只用 `siluzan-tso …`。**禁止**用 curl、自写脚本或改请求头直连 TSO/Google 网关「另辟蹊径」取数;`balance` 等无数据时按 CLI/`list-accounts` **实际出现的字段**向用户说明(如授权失效;仅当输出含激活字段时才可谈套餐),**禁止**尝试任何绕过平台门禁的取数方式。
|
|
132
132
|
- **W3 仅出方案例外(覆盖上条)**:用户只要「投放方案 / 规划 / 表格 / 先别创建·开户·投钱」,或未给账户且未要求创建/发布时——**禁止**把「请先提供 Google 广告账户」当作第一步;按 `google-ads-campaign-plan.md` §「仅出方案 vs 创建」落盘 JSON 后 **写代码**投影完整审查稿(默认 MD;用户指定则 Excel 等;`account`=`[PENDING_ACCOUNT]`),跳过 `list-accounts` / `geo resolve` / validate / create。**禁止**只交概览表。用户确认要创建后再要账户并续跑创建流水线。
|
|
133
133
|
- **W3 审查稿(搜索与 PMax)**:JSON 落盘后、创建前,必须 **写代码**读取 JSON,按 `google-ads-launch-plan-template.md`(搜索)或 `google-ads-pmax-launch-plan-template.md`(PMax)生成完整审查文件交给用户;须含全部关键词/RSA 或全部 PMax 文案与附加资产。**禁止**用「方案总结」条数勾选代替。用户要求其他格式时改脚本输出,数据仍只从 JSON 来。
|
|
134
134
|
- **不猜测账户 ID**:`entityId`(UUID,仅 delink/share/reauth/账单)≠ `mediaCustomerId`(`stats`/`balance`/`accounts-digest`/`ad` 的 `-a`)。两者均来自 `list-accounts` 的 `ma.*`。用户已给出媒体账户号时(Google 数字 CID、**Yandex `porg-…`**、Meta `act_…` 等)→ `-a` **原样使用**,再用 `-k` 核验;**禁止**改成 `entityId` / tokenId / 会话里其它 UUID。**禁止**把 `entityId` 传给 `stats -a` / `balance -a` / `accounts-digest -a`。
|
|
@@ -150,10 +150,11 @@
|
|
|
150
150
|
- **禁止**只贴一行 CLI `✅`/`❌` 或整段 stdout 当交付;**禁止**写命令成功后静默结束。
|
|
151
151
|
- **广告创建(W3)另有加强**:见下条与 `workflows.md` W3——创建完成后必须输出**每个系列**的详情,不能只报「任务已提交 / 创建完成」。
|
|
152
152
|
- **Google 广告创建完成后必出系列详情报告**(用户确认计划并执行 `campaign-create` / `pmax-create` 之后):
|
|
153
|
-
-
|
|
154
|
-
- **交付物必须是 Markdown
|
|
153
|
+
- 流水线:`batch get` 至终态 →(搜索)**每次** `batch diff` 后**立刻交付** → 再自动补建 → 补建后可再 diff 并再交付更新版。
|
|
154
|
+
- **交付物必须是 Markdown 文档正文**:`ad batch diff` stdout 中 `BEGIN_USER_DELIVERY_MARKDOWN` 与 `END_USER_DELIVERY_MARKDOWN` 之间的全文(即 `reportMarkdown`)**原样**作为对用户消息发出;亦可 Read `reportMarkdownFile`。报告含概览、数量汇总、按广告组展开的关键词/RSA 状态表、仍未创建项。
|
|
155
|
+
- **交付优先于补建**:不得以「先补扩展/稍后再统一读 reportMarkdown」推迟对用户发详情;假称「详情已交付」却只贴汇总表 = 违规。
|
|
155
156
|
- 多系列:每个系列各跑一次 diff,**各发一份** Markdown(或同一回复里多份 `#` 一级标题分节)。
|
|
156
|
-
- **禁止**只说「已创建成功 / 未发现缺失」、**禁止**只贴 `counts
|
|
157
|
+
- **禁止**只说「已创建成功 / 详情已交付 / 未发现缺失」、**禁止**只贴 `counts`/系列 ID 摘要表;代改过用户方案时另加修改表(见 `google-ads-plan-source-fidelity.md`)。
|
|
157
158
|
- **不确定时读文档**:先读对应 references 或用 `-h`,不要猜参数。
|
|
158
159
|
- **跨账号 / 企业管家手机号**:用户消息中出现**中国大陆 11 位手机号**(常见语境:「企业管家」「管家账户」「账号 xxx」)且意图是查**该手机号名下**的账户数据时,**必须先**执行 `siluzan-tso account me --check-phone <手机号> --json-out ./snap-me`。**禁止**在未校验通过前用当前凭据拉他户数据。
|
|
159
160
|
- `matched: true`(或 CLI exit 0)→ 按原工作流继续(如 P3 `accounts-digest` 查 TOP 消耗)。
|
|
@@ -277,7 +278,7 @@
|
|
|
277
278
|
|
|
278
279
|
- **400**:参数错误,查看对应 reference 或 `-h`
|
|
279
280
|
- **401 / OAuth 失效**:仅当 `list-accounts` 的 `invalidOAuthToken=true`(或表格「授权状态」为失效)且用户确认后——Siluzan Agent **优先**用平台重新授权工具(如 `present_reauth`);备选 `account reauth -m <媒体> --id <entityId> --i-confirm --commit "…"`(内置 delink→OAuth,见 W9 / `accounts-permissions.md`)。走 CLI 时**必须把 stdout 中的完整授权 URL 原样贴给用户**,禁止只说「链接已生成」,也**禁止**自行改写/补全该 URL。解绑后若列表已无该户,恢复用平台授权工具或 `account auth -m <媒体>`。**丝路赞登录凭据失效** → `send-login-code` + `login --phone --code`,见 `references/core/setup.md`
|
|
280
|
-
- **403(拉数空结果 / ad 网关)**:① **优先核验 `-a` 是否为 `ma.mediaCustomerId`**(勿传 `entityId`/UUID;Google 注意连字符 CID;Yandex 形如 `porg-…`);②
|
|
281
|
+
- **403(拉数空结果 / ad 网关)**:① **优先核验 `-a` 是否为 `ma.mediaCustomerId`**(勿传 `entityId`/UUID;Google 注意连字符 CID;Yandex 形如 `porg-…`);② 仅当 `list-accounts` **输出含** `scopeActivatedSources` 且可判定未激活时,才可说明需先激活;**无该字段则禁止谈套餐**;**禁止**非 CLI 绕过取数;③ **禁止臆测授权过期**:**必须**跑 `account check-access -a <mediaCustomerId>`,以 `status` 为准后再决定是否 `reauth`;**禁止**仅凭 403 文案对用户说「授权过期」。
|
|
281
282
|
- **500**:服务可能正在部署/升级,建议反馈 Siluzan 相关人员
|
|
282
283
|
|
|
283
284
|
---
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
2. `ad geo resolve -a <id> --from-file ./locations.json --json-out ./snap-geo`,把 id 写回 JSON。
|
|
84
84
|
3. `ad campaign-validate`;**有不合规 → 询问「您自己改还是我帮您改?」**(见 `google-ads-plan-source-fidelity.md`)→ **写代码投影完整审查稿** → 用户确认 → `campaign-create` → `batch get` / `batch diff` / 自动补扩展 → **必出系列创建详情报告**;若 Agent 代改过 → 详情中**另附**修改表(创建清单 + 从 xxx→xxx + 原因)。
|
|
85
85
|
- **步骤(Search 一体化创建,无现成方案文件)**:
|
|
86
|
-
0. **最小清单**(详见 `google-ads-campaign-plan.md` §创建前最小命令清单):`list-accounts -m Google -k …`
|
|
86
|
+
0. **最小清单**(详见 `google-ads-campaign-plan.md` §创建前最小命令清单):`list-accounts -m Google -k …` → `account check-access` → geo → validate → 审查稿 → create → `batch get`(看 `agentWorkflow`)→ **仅有 campaignId 时** `batch diff`。命令是 `ad campaigns`(禁 `ad-campaigns`/`campaign list`);geo/ad 失败禁臆测授权过期;仅当列表输出含激活字段且未激活时才先处理激活。
|
|
87
87
|
1. 地域:多国 `ad geo resolve --json-out`;单国 `ad geo search -a <id> -q "United States" --json-out`(读 `picked`/`targetedLocations`;仍禁止编造)。
|
|
88
88
|
2. 门禁:`ad campaign-validate --config-file ./campaign.json --json-out …`(必跑;STRUCTURED_SNIPPET Key 须合法英文标头;ACCELERATED 预算看 warnings)。
|
|
89
89
|
3. **写代码**按 `google-ads-launch-plan-template.md` 从 JSON 投影完整审查稿 → 用户确认。
|
|
@@ -68,8 +68,9 @@
|
|
|
68
68
|
| 8 | 用户确认后 **`ad campaign-create`** | `references/google-ads/google-ads-write.md` |
|
|
69
69
|
| 9 | 每隔5s 获取创建结果 | `ad batch get --id <taskId> --config-file ./campaign.json` |
|
|
70
70
|
| 10 | 成功或部分成功后 **`ad batch diff`** 对照 JSON 与账户实况 | |
|
|
71
|
-
| 11 |
|
|
72
|
-
| 12 |
|
|
71
|
+
| 11 | **立刻交付创建详情**:把 diff stdout 中 `BEGIN_USER_DELIVERY_MARKDOWN`…`END` 全文原样发给用户(先于补建;禁止只贴汇总表) | `agent-conventions.md` §四 |
|
|
72
|
+
| 12 | **自动补建缺失项**(见下文):扩展/地域等执行 `remediateCommand`;补建后再 diff 时可再发更新版详情。**勿**仅反问用户是否补建 | `references/google-ads/google-ads-batch.md` § batch diff 后自动补建 |
|
|
73
|
+
| 13 | 代改过方案时**另附**修改表(从 xxx → xxx + 原因) | **`rules/google-ads-plan-source-fidelity.md`** § 创建完成报告 |
|
|
73
74
|
|
|
74
75
|
多系列:每系列一个 JSON;可选 `campaign-manifest.json`(`role: brand|competitor|generic`)仅作文件组织参考。
|
|
75
76
|
|
|
@@ -159,12 +160,12 @@ validate 与 create **共用** `runCampaignCreateValidation`:词面规范化 +
|
|
|
159
160
|
| ---- | ---- |
|
|
160
161
|
| 1 | `ad batch get --id <taskId> --config-file ./campaign.json --json-out ./snap-campaign` 直至终端态(Creating 时每 5s 轮询;**读落盘 `agentWorkflow.nextCommand`**,勿只看人读提示) |
|
|
161
162
|
| 2 | `Successfully` / `HasFailed`:执行 `agentWorkflow.nextCommand`(即 `ad batch diff … --json-out`);**Failed** 勿 diff |
|
|
162
|
-
| 3 |
|
|
163
|
-
| 4 |
|
|
164
|
-
| 5 |
|
|
165
|
-
| 6 |
|
|
166
|
-
| 7 |
|
|
167
|
-
| 8 |
|
|
163
|
+
| 3 | **立刻交付**:把本次 diff stdout 中 `BEGIN_USER_DELIVERY_MARKDOWN`…`END_USER_DELIVERY_MARKDOWN` 全文原样发给用户(即 `reportMarkdown`)。**禁止**只贴系列 ID/counts 摘要,**禁止**等补建结束再交付 |
|
|
164
|
+
| 4 | 读落盘 `ok` / `missing[]`;`layer=location` → `ad geo add`;`layer=extension` → 执行 `remediateCommand` |
|
|
165
|
+
| 5 | 无 `remediateCommand` 时,按 JSON 路径映射 `ad extension *` / `adgroup-create` / `keyword-create` / `ad-create` / `keyword-negative-create` |
|
|
166
|
+
| 6 | 有缺失时 CLI **exit 2**;补建后再 `ad batch diff`,直到 `ok===true`;每次 diff 后若状态有变可再发更新版详情 |
|
|
167
|
+
| 7 | 可简短补充「已自动补上 N 个投放国家 / M 条 Sitelink」(**不能代替**步骤 3 的 Markdown 全文) |
|
|
168
|
+
| 8 | 仅当补建命令也失败时,才向用户说明原因并给改写方案;代改方案另附修改表见 `google-ads-plan-source-fidelity.md` |
|
|
168
169
|
|
|
169
170
|
**Agent 易漏点**:`--json-out` 时人读「下一步」不会打印——**必须以落盘 `agentWorkflow` 为准**;`campaign-create` 落盘同样带 `agentWorkflow.nextCommand`(首轮 `batch get`)。
|
|
170
171
|
|
|
@@ -182,11 +182,11 @@ siluzan-tso ad batch diff --batch-id <taskId> --config-file ./campaign.json --js
|
|
|
182
182
|
BatchJob 常漏 **附加信息**(Sitelink)与 **投放地域**;系列/组/词/RSA 往往已成功。用户确认创建时已认可 JSON → Agent **须直接补建**,**禁止**仅汇报「未创建,需要我现在补上吗?」。
|
|
183
183
|
|
|
184
184
|
1. `ad campaign-create` / `ad batch get` 的 `--json-out` 落盘含 **`agentWorkflow`**:读 `nextCommand` / `shouldRunBatchDiff` / `agentHint`(人读提示在 `--json-out` 早退时不可见)。
|
|
185
|
-
2. 跑 `ad batch diff
|
|
186
|
-
3.
|
|
187
|
-
4.
|
|
188
|
-
5.
|
|
189
|
-
6.
|
|
185
|
+
2. 跑 `ad batch diff`;stdout 含 `BEGIN_USER_DELIVERY_MARKDOWN`…`END`——**立刻原样发给用户**(先于补建)。
|
|
186
|
+
3. 对 `missing[]` 中带 `remediateCommand` 的项**直接执行**(`location` → `ad geo add`;`extension` → `ad extension *`)。
|
|
187
|
+
4. 扩展字段映射:`Properties.Text` + `DestinationUrl` → `ad extension sitelink`;`CALLOUT` → `callout`;`CALL` → `call`;`STRUCTURED_SNIPPET` → `snippet`。
|
|
188
|
+
5. 有缺失时 CLI **exit 2**;补建后再跑一次 `ad batch diff`,直到 `ok===true`;可再发更新版详情。
|
|
189
|
+
6. 可简短补充已补挂条数(**不能代替**步骤 2 的 Markdown 全文)。**禁止**只说「已创建成功 / 详情已交付」或只复述「未发现缺失」。见 `agent-conventions.md` §四。
|
|
190
190
|
|
|
191
191
|
完整流水线见 `references/google-ads/google-ads-campaign-plan.md` § batch diff 后自动补建。
|
|
192
192
|
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
- **广告类型**:仅 Search + PMax;**不支持 Display**(见上文「支持的广告类型」)。
|
|
31
31
|
- **命令名**:系列列表是 `ad campaigns`(别名 `campaign-list`),**禁止** `ad-campaigns` / `campaign list`。`balance`/`stats` 须 `-m Google`。
|
|
32
32
|
- **Google 客户 ID(CID)带连字符**:UI / 用户口述常为 `123-456-7890`,平台 `mediaCustomerId` 与 Google 网关路径需要 `1234567890`。`ad campaigns` / `ad groups` / `ad list` 等 `-a` 与 JSON 顶层 `account` **可带连字符**(CLI 自动去掉)。若错误为 `HTTP 403:123-456-7890`(回显带横杠),先换纯数字重试,**禁止**据此直接判断 OAuth 过期或 `reauth`。
|
|
33
|
-
- **禁止臆测授权过期**:`ad *` / geo / 拉数出现 403/500 时,**禁止**对用户说「授权可能过期」。须核验 ID
|
|
33
|
+
- **禁止臆测授权过期**:`ad *` / geo / 拉数出现 403/500 时,**禁止**对用户说「授权可能过期」。须核验 ID 后执行 `account check-access -a <mediaCustomerId>`,仅当 `reauth_required`(或与 `invalidOAuthToken=true` 交叉确认)才走重授权;无激活字段时禁止谈套餐。见 [`accounts-permissions.md`](../accounts/accounts-permissions.md)。
|
|
34
34
|
- **预算投放**:`BudgetBudgetDeliveryMethodV2` 默认用 `STANDARD`;`ACCELERATED` 多数账户会被 Google 拒(validate 警告)。
|
|
35
35
|
- **STRUCTURED_SNIPPET**:`StructuredSnippetHeaderValue.Key` 须为合法英文标头(`ad extension snippet-headers`);`Features` 等非法值 validate 会拦(建议 `Amenities`)。
|
|
36
36
|
- **batch get**:读 `agentWorkflow`——无 `campaignId` 的 Failed/HasFailed **禁止**跑 `batch diff`,按 `agentHint` 改 JSON 重提。
|
|
37
|
-
- **batch diff 交付**:把 `
|
|
37
|
+
- **batch diff 交付**:把 stdout 中 `BEGIN_USER_DELIVERY_MARKDOWN`…`END`(或 `reportMarkdownFile`)**全文以 Markdown 发给用户**(先于补建);**禁止**只说「未发现缺失 / 详情已交付」。
|
|
38
38
|
- `-a` 必须是 `list-accounts -m Google` 的 `ma.mediaCustomerId`,**禁止**传 `entityId`(UUID)。
|
|
39
39
|
|
|
40
40
|
## 金额单位(全局重要)
|
|
@@ -68,7 +68,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
68
68
|
- 若环比列全为 `null`,检查落盘目录是否存在上一周期文件(如 `campaigns-<id>_20260503-20260602.json`);不存在则**重新执行 collect**(勿用手动拼装或 Python 脚本绕过 CLI)。
|
|
69
69
|
|
|
70
70
|
- **render 自动合并(默认开启)**:若同目录存在 `google-ads-diagnosis-collect.json`,且 Agent 改坏了 `campaigns` / `geographic` / `keywords` 的 `items`(缺 `title`/`currentCost` 或环比写成字符串)或整体覆盖丢弃了 `landingPageAnalysis.desktop`/`mobile`,CLI **自动从 collect.reportData 恢复**,保留 Agent 的 `analysis`/`suggestions`。可用 `--no-merge-collect` 关闭;`--collect <file>` 指定 collect 路径。
|
|
71
|
-
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages`
|
|
71
|
+
- **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与事实字段矛盾,或出现「否词相关 / 着陆页测速缺失」禁写项、预算/创意建议千篇一律、§07 写成关键词洞察时同样 **exit 1**。
|
|
72
72
|
|
|
73
73
|
- **禁止**在 `collect` 阶段生成或写入 `analysis` / `suggestions` / `diagnosisOverview` / `summary` 等建议性文案。
|
|
74
74
|
- **禁止**跳过 Agent 直接 `render` collect 产物(`render` 会校验全部叙事 / 建议字段;调试可加 `--lenient`)。
|
|
@@ -144,7 +144,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
144
144
|
- 结论涉及「转化跟踪/GA 关联」→ 核对 `goldAccount.gaConfigured` / `goldAccount.conversionTrackingQualified`(按第 4 条 `true`=已达标)。
|
|
145
145
|
- 结论涉及「着陆页测速/性能」→ 先看 `landingPageAnalysis.source`:`api` 才可用 desktop/mobile 的 score/FCP;`simple` 只能写简易诊断信号(`simpleDiagnosis`),**禁止**把 fetchMs 当 FCP 或编造性能指数;`none` 写「数据未获取」。
|
|
146
146
|
- **禁止写入 keyIssues / disadvantages(render 硬拦截)**:
|
|
147
|
-
- 「否定关键词数量为 0 /
|
|
147
|
+
- 「否定关键词数量为 0 / 缺少否词过滤」——本报告 **collect 未拉取否词数据**,结构表与黄金账户**不展示否词项**;禁止据此下结论。有搜索词浪费时仅在 §08 按具体搜索词写。
|
|
148
148
|
- 「着陆页性能数据缺失 / 无法评估加载速度」——测速未获取是采集降级,**不是**投放核心问题;只在 §07 `analysis` 说明即可。
|
|
149
149
|
- `render` 会对已知矛盾与上述禁写模式做**硬校验**,命中直接 `exit 1`——须按提示改写,**禁止**删字段绕过。
|
|
150
150
|
|
|
@@ -243,10 +243,9 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
243
243
|
| 有效关键字 (Effective Keywords) | |
|
|
244
244
|
| 有效广告 (Effective Ads) | |
|
|
245
245
|
| 附加链接 (Sitelinks) | |
|
|
246
|
-
| 否定关键字 (Negative Keywords) | |
|
|
247
246
|
| 有效国家 (Effective Countries) | |
|
|
248
247
|
|
|
249
|
-
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`
|
|
248
|
+
**对应字段**:`structure.campaignCount`、`adGroupCount`、`keywordCount`、`adCount`、`extensionCount`、`countriesWithConversionsCount`(**不含**否词计数;collect 未拉否词)
|
|
250
249
|
|
|
251
250
|
### 3.3 指标检测
|
|
252
251
|
|
|
@@ -329,10 +328,11 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
329
328
|
| 附加链接 | | |
|
|
330
329
|
| 附加宣传信息 | | |
|
|
331
330
|
| 附加电话信息 | | |
|
|
332
|
-
| 否定词添加 | | |
|
|
333
331
|
| 受众群体设置 | | |
|
|
334
332
|
| 出价策略 | | |
|
|
335
333
|
|
|
334
|
+
> 黄金账户表**不含**「否定词添加」(`adsNegativeQualified`):collect 未拉取否词数据,render 会剥离该字段。
|
|
335
|
+
|
|
336
336
|
**得分**:`goldAccountScore`;**未达标项数**:若有 `goldAccountUnqualifiedCount` 可注明。
|
|
337
337
|
|
|
338
338
|
---
|
|
@@ -498,7 +498,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
498
498
|
### 12.1 核心问题总结
|
|
499
499
|
|
|
500
500
|
- `summary.keyIssues`:逐条列出(或写「暂无核心问题」)
|
|
501
|
-
-
|
|
501
|
+
- **不要写**:否词数量/缺少否词(本报告无否词数据);着陆页测速数据缺失(见撰写硬约束第 5 条)
|
|
502
502
|
|
|
503
503
|
### 12.2 优先级优化路线图
|
|
504
504
|
|