siluzan-tso-cli 1.1.39 → 1.1.40-beta.2
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 +2 -1
- package/dist/index.js +926 -194
- package/dist/skill/SKILL.md +4 -3
- package/dist/skill/_meta.json +2 -2
- 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 +72 -68
- package/dist/skill/references/accounts/open-account-google-ui.md +30 -27
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/analytics/website-diagnosis-guide.md +2 -0
- package/dist/skill/references/core/agent-conventions.md +5 -3
- package/dist/skill/references/core/intent-routing.md +10 -7
- package/dist/skill/references/core/playbooks.md +2 -1
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/workflows.md +7 -6
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/references/operations/forewarning.md +2 -0
- package/dist/skill/references/operations/guard.md +94 -0
- package/dist/skill/references/operations/hosted-automation-self-control.md +35 -15
- package/dist/skill/references/operations/hosted-automation-user-catalog.md +5 -5
- package/dist/skill/references/report-templates/bing-period-report.md +3 -3
- package/dist/skill/references/report-templates/google-period-report.md +1 -1
- package/dist/skill/references/report-templates/meta-account-diagnosis-report.md +1 -1
- package/dist/skill/references/report-templates/meta-period-report.md +2 -2
- package/dist/skill/references/report-templates/tiktok-period-report.md +1 -1
- package/dist/skill/report-templates/bing-period-report.md +3 -3
- package/dist/skill/report-templates/google-period-report.md +1 -1
- package/dist/skill/report-templates/meta-account-diagnosis-report.md +1 -1
- package/dist/skill/report-templates/meta-period-report.md +2 -2
- package/dist/skill/report-templates/tiktok-period-report.md +1 -1
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/eval/cases/guard-budget-circuit-all-google.scenario.json +25 -0
- package/eval/cases/guard-zero-conv-empty-spend.scenario.json +21 -0
- package/eval/cases/ir-p8-meets-google-ads-requirements-with-url.scenario.json +39 -0
- package/eval/stub-fixtures/guard-budget-circuit.json +36 -0
- package/eval/stub-fixtures/guard-zero-conv.json +41 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3937,7 +3937,7 @@ var DEFAULT_API_BASE;
|
|
|
3937
3937
|
var init_defaults = __esm({
|
|
3938
3938
|
"src/config/defaults.ts"() {
|
|
3939
3939
|
"use strict";
|
|
3940
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
3940
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
3941
3941
|
}
|
|
3942
3942
|
});
|
|
3943
3943
|
|
|
@@ -102283,15 +102283,17 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102283
102283
|
costPerConversion: num2(currentPeriod.costPerConversion)
|
|
102284
102284
|
} : null);
|
|
102285
102285
|
if (currentKpiSource) {
|
|
102286
|
-
if (
|
|
102287
|
-
if (
|
|
102288
|
-
if (
|
|
102289
|
-
if (
|
|
102290
|
-
if (
|
|
102291
|
-
if (
|
|
102292
|
-
if (
|
|
102293
|
-
|
|
102294
|
-
|
|
102286
|
+
if (currentKpiSource.cost != null) kpis.cost = currentKpiSource.cost;
|
|
102287
|
+
if (currentKpiSource.impressions != null) kpis.impressions = currentKpiSource.impressions;
|
|
102288
|
+
if (currentKpiSource.clicks != null) kpis.clicks = currentKpiSource.clicks;
|
|
102289
|
+
if (currentKpiSource.conversions != null) kpis.conversions = currentKpiSource.conversions;
|
|
102290
|
+
if (currentKpiSource.ctr != null) kpis.ctr = currentKpiSource.ctr;
|
|
102291
|
+
if (currentKpiSource.averageCpc != null) kpis.averageCpc = currentKpiSource.averageCpc;
|
|
102292
|
+
if (currentKpiSource.costPerConversion != null) {
|
|
102293
|
+
kpis.costPerConversion = currentKpiSource.costPerConversion;
|
|
102294
|
+
}
|
|
102295
|
+
}
|
|
102296
|
+
if (previousPeriod) {
|
|
102295
102297
|
kpis.previousPeriod = {
|
|
102296
102298
|
cost: num2(previousPeriod.spend),
|
|
102297
102299
|
impressions: num2(previousPeriod.impressions),
|
|
@@ -102303,7 +102305,7 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102303
102305
|
};
|
|
102304
102306
|
}
|
|
102305
102307
|
const charts = { ...payload.charts ?? {} };
|
|
102306
|
-
|
|
102308
|
+
{
|
|
102307
102309
|
const dailyRows = items(sectionMap.get("daily-metrics"));
|
|
102308
102310
|
if (dailyRows.length > 0) {
|
|
102309
102311
|
const sorted = [...dailyRows].sort(
|
|
@@ -102318,7 +102320,7 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102318
102320
|
}
|
|
102319
102321
|
}
|
|
102320
102322
|
const tables = { ...payload.tables ?? {} };
|
|
102321
|
-
|
|
102323
|
+
{
|
|
102322
102324
|
const summary = record(sectionMap.get("dimension-summary"));
|
|
102323
102325
|
if (summary) {
|
|
102324
102326
|
tables.dimensionSummary = {
|
|
@@ -102335,19 +102337,19 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102335
102337
|
};
|
|
102336
102338
|
}
|
|
102337
102339
|
}
|
|
102338
|
-
if (
|
|
102340
|
+
if (campaignRows2.length > 0) {
|
|
102339
102341
|
tables.campaigns = campaignRows2.map((r) => ({
|
|
102340
102342
|
...pickMetricRow(r, ["campaignName", "campaignStatusDisplay", "channelTypeV2"]),
|
|
102341
102343
|
budgetAmountYuan: r.budgetAmountYuan ?? null
|
|
102342
102344
|
}));
|
|
102343
102345
|
}
|
|
102344
|
-
|
|
102346
|
+
{
|
|
102345
102347
|
const rows = items(sectionMap.get("devices"));
|
|
102346
102348
|
if (rows.length > 0) {
|
|
102347
102349
|
tables.devices = rows.map((r) => pickMetricRow(r, ["deviceType"]));
|
|
102348
102350
|
}
|
|
102349
102351
|
}
|
|
102350
|
-
|
|
102352
|
+
{
|
|
102351
102353
|
const rows = items(sectionMap.get("geographic"));
|
|
102352
102354
|
if (rows.length > 0) {
|
|
102353
102355
|
tables.geographic = rows.map(
|
|
@@ -102355,7 +102357,7 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102355
102357
|
);
|
|
102356
102358
|
}
|
|
102357
102359
|
}
|
|
102358
|
-
|
|
102360
|
+
{
|
|
102359
102361
|
const rows = items(sectionMap.get("keywords"));
|
|
102360
102362
|
if (rows.length > 0) {
|
|
102361
102363
|
tables.keywords = rows.map(
|
|
@@ -103814,7 +103816,7 @@ function resolveSectionList(sections, exclude) {
|
|
|
103814
103816
|
const base = include.length > 0 ? SECTIONS.filter((s) => include.includes(s.name)) : SECTIONS;
|
|
103815
103817
|
return base.filter((s) => !drop.has(s.name));
|
|
103816
103818
|
}
|
|
103817
|
-
async function
|
|
103819
|
+
async function runWithConcurrency2(tasks, concurrency) {
|
|
103818
103820
|
const results = new Array(tasks.length);
|
|
103819
103821
|
let cursor = 0;
|
|
103820
103822
|
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
@@ -103897,7 +103899,7 @@ async function runAllSections(opts) {
|
|
|
103897
103899
|
const cliVersion = getCurrentVersion2();
|
|
103898
103900
|
const overallT0 = performance4.now();
|
|
103899
103901
|
const tasks = targets.map((def) => () => fetchAndWriteSection(def, opts, config, id, cliVersion));
|
|
103900
|
-
let results = await
|
|
103902
|
+
let results = await runWithConcurrency2(tasks, concurrency);
|
|
103901
103903
|
const failedIndices = results.map((r, i) => r.ok ? -1 : i).filter((i) => i >= 0);
|
|
103902
103904
|
if (failedIndices.length > 0) {
|
|
103903
103905
|
console.error(`
|
|
@@ -107055,6 +107057,747 @@ function register9(program2) {
|
|
|
107055
107057
|
// src/index.ts
|
|
107056
107058
|
init_accounts_digest2();
|
|
107057
107059
|
|
|
107060
|
+
// src/commands/guard/budget-circuit.ts
|
|
107061
|
+
init_cli_json_snapshot();
|
|
107062
|
+
|
|
107063
|
+
// src/commands/guard/shared.ts
|
|
107064
|
+
init_auth();
|
|
107065
|
+
init_list_fetch();
|
|
107066
|
+
|
|
107067
|
+
// src/commands/ad/_shared.ts
|
|
107068
|
+
init_auth();
|
|
107069
|
+
async function findItemInList(listUrl, config, id, verbose) {
|
|
107070
|
+
const res = await apiFetch2(listUrl, config, {}, verbose);
|
|
107071
|
+
const item = (res.data ?? []).find((x) => x["id"] === id);
|
|
107072
|
+
if (!item) {
|
|
107073
|
+
throw new Error(`\u672A\u5728\u5217\u8868\u4E2D\u627E\u5230 id="${id}" \u7684\u6761\u76EE`);
|
|
107074
|
+
}
|
|
107075
|
+
return item;
|
|
107076
|
+
}
|
|
107077
|
+
function toGoogleDate(dateStr, offsetDays) {
|
|
107078
|
+
if (dateStr) return dateStr.replace(/-/g, "/");
|
|
107079
|
+
const d = /* @__PURE__ */ new Date();
|
|
107080
|
+
d.setDate(d.getDate() + offsetDays);
|
|
107081
|
+
return d.toISOString().slice(0, 10).replace(/-/g, "/");
|
|
107082
|
+
}
|
|
107083
|
+
function toDisplayMoney(raw) {
|
|
107084
|
+
if (raw == null) return null;
|
|
107085
|
+
const n = Number(raw);
|
|
107086
|
+
if (!Number.isFinite(n)) return null;
|
|
107087
|
+
return n / 100;
|
|
107088
|
+
}
|
|
107089
|
+
function toCentAmount(displayValue) {
|
|
107090
|
+
if (!Number.isFinite(displayValue)) {
|
|
107091
|
+
throw new Error(`toCentAmount: \u8F93\u5165\u5FC5\u987B\u662F\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${displayValue}`);
|
|
107092
|
+
}
|
|
107093
|
+
return Math.round(displayValue * 100);
|
|
107094
|
+
}
|
|
107095
|
+
var CAMPAIGN_BATCH_MONEY_KEYS = /* @__PURE__ */ new Set([
|
|
107096
|
+
"Budget",
|
|
107097
|
+
"MaxCPCAmount",
|
|
107098
|
+
"MaxCpmAmount",
|
|
107099
|
+
"MaxCPVAmount",
|
|
107100
|
+
"TargetCpa_BidingAmount",
|
|
107101
|
+
"TargetSpend_BidCeilingAmount",
|
|
107102
|
+
"TargetCpaAmount",
|
|
107103
|
+
"MaxCPC"
|
|
107104
|
+
]);
|
|
107105
|
+
function convertBatchMoneyTreeFromYuan(value) {
|
|
107106
|
+
return convertBatchMoneyTreeFromYuanInner(value);
|
|
107107
|
+
}
|
|
107108
|
+
function convertBatchMoneyTreeFromYuanInner(value) {
|
|
107109
|
+
if (Array.isArray(value)) {
|
|
107110
|
+
return value.map(convertBatchMoneyTreeFromYuanInner);
|
|
107111
|
+
}
|
|
107112
|
+
if (value && typeof value === "object") {
|
|
107113
|
+
const out = {};
|
|
107114
|
+
for (const [key, val] of Object.entries(value)) {
|
|
107115
|
+
if (typeof val === "number" && CAMPAIGN_BATCH_MONEY_KEYS.has(key)) {
|
|
107116
|
+
out[key] = toCentAmount(val);
|
|
107117
|
+
} else {
|
|
107118
|
+
out[key] = convertBatchMoneyTreeFromYuanInner(val);
|
|
107119
|
+
}
|
|
107120
|
+
}
|
|
107121
|
+
return out;
|
|
107122
|
+
}
|
|
107123
|
+
return value;
|
|
107124
|
+
}
|
|
107125
|
+
function adgroupListUrl(googleApiUrl, account, startDate, endDate) {
|
|
107126
|
+
const params = new URLSearchParams();
|
|
107127
|
+
params.set("startDate", toGoogleDate(startDate, -30));
|
|
107128
|
+
params.set("endDate", toGoogleDate(endDate, 0));
|
|
107129
|
+
return `${googleApiUrl}/adgroupnmanagement/v2/list/${account}?${params}`;
|
|
107130
|
+
}
|
|
107131
|
+
function requireGoogleApi(config) {
|
|
107132
|
+
if (!config.googleApiUrl) {
|
|
107133
|
+
console.error(
|
|
107134
|
+
"\n\u274C \u672A\u627E\u5230 Google API \u5730\u5740\u3002\n Google API \u5730\u5740\u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_GOOGLE_API \u8986\u76D6\u3002\n"
|
|
107135
|
+
);
|
|
107136
|
+
process.exit(1);
|
|
107137
|
+
}
|
|
107138
|
+
return config.googleApiUrl;
|
|
107139
|
+
}
|
|
107140
|
+
|
|
107141
|
+
// src/commands/guard/shared.ts
|
|
107142
|
+
init_cli_table();
|
|
107143
|
+
var GUARD_ACCOUNT_CONCURRENCY = 4;
|
|
107144
|
+
async function resolveGuardConfig(opts) {
|
|
107145
|
+
let config = loadConfig(opts.token);
|
|
107146
|
+
if (opts.refreshDp) {
|
|
107147
|
+
config = await refreshDataPermission(config);
|
|
107148
|
+
}
|
|
107149
|
+
return config;
|
|
107150
|
+
}
|
|
107151
|
+
function assertGoogleOnly(media) {
|
|
107152
|
+
if (media !== "Google") {
|
|
107153
|
+
console.error(
|
|
107154
|
+
`
|
|
107155
|
+
\u274C guard \u7194\u65AD\u5199\u76EE\u524D\u4EC5\u652F\u6301 Google\uFF08\u5F53\u524D\uFF1A${media}\uFF09\u3002
|
|
107156
|
+
\u975E Google \u5A92\u4F53\u672C CLI \u65E0\u7CFB\u5217/\u7EC4/\u521B\u610F\u6682\u505C\u5199\u80FD\u529B\uFF1B\u8BF7\u6539\u7528 -m Google\u3002
|
|
107157
|
+
`
|
|
107158
|
+
);
|
|
107159
|
+
process.exit(1);
|
|
107160
|
+
}
|
|
107161
|
+
}
|
|
107162
|
+
async function resolveGuardAccounts(opts, config) {
|
|
107163
|
+
const filterIds = (opts.accounts ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
107164
|
+
if (filterIds.length > 0) {
|
|
107165
|
+
process.stderr.write(
|
|
107166
|
+
`\u23F3 [guard] \u5B50\u96C6\u6A21\u5F0F\uFF1A\u5BF9 -a \u6307\u5B9A\u7684 ${filterIds.length} \u4E2A\u8D26\u6237\u626B\u63CF\u3002
|
|
107167
|
+
`
|
|
107168
|
+
);
|
|
107169
|
+
return filterIds.map((id) => ({ mediaCustomerId: id, name: null }));
|
|
107170
|
+
}
|
|
107171
|
+
const pageSize = Math.max(1, Math.min(500, opts.pageSize ?? 200));
|
|
107172
|
+
const maxPages = Math.max(1, Math.min(200, opts.maxPages ?? 20));
|
|
107173
|
+
const res = await fetchAccountsByMedia("Google", config, {
|
|
107174
|
+
pageSize,
|
|
107175
|
+
maxPages,
|
|
107176
|
+
verbose: opts.verbose
|
|
107177
|
+
});
|
|
107178
|
+
return res.items.map((item) => ({
|
|
107179
|
+
mediaCustomerId: String(item.ma?.mediaCustomerId ?? ""),
|
|
107180
|
+
name: item.ma?.mediaCustomerName ?? null
|
|
107181
|
+
})).filter((a) => a.mediaCustomerId);
|
|
107182
|
+
}
|
|
107183
|
+
async function runWithConcurrency(tasks, concurrency) {
|
|
107184
|
+
const results = new Array(tasks.length);
|
|
107185
|
+
let cursor = 0;
|
|
107186
|
+
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length || 1))).fill(0).map(async () => {
|
|
107187
|
+
while (true) {
|
|
107188
|
+
const i = cursor++;
|
|
107189
|
+
if (i >= tasks.length) return;
|
|
107190
|
+
results[i] = await tasks[i]();
|
|
107191
|
+
}
|
|
107192
|
+
});
|
|
107193
|
+
await Promise.all(workers);
|
|
107194
|
+
return results;
|
|
107195
|
+
}
|
|
107196
|
+
async function fetchCampaignsForDay(config, accountId, date, verbose) {
|
|
107197
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107198
|
+
const params = new URLSearchParams();
|
|
107199
|
+
params.set("startDate", toGoogleDate(date, 0));
|
|
107200
|
+
params.set("endDate", toGoogleDate(date, 0));
|
|
107201
|
+
const url = `${googleApiUrl}/campaignmanagement/v2/list/${accountId}?${params}`;
|
|
107202
|
+
const data = await apiFetch2(url, config, {}, verbose);
|
|
107203
|
+
return (data.data ?? []).map((item) => ({
|
|
107204
|
+
id: String(item["id"] ?? ""),
|
|
107205
|
+
name: String(item["name"] ?? ""),
|
|
107206
|
+
statusV2: String(item["statusV2"] ?? ""),
|
|
107207
|
+
budget: toDisplayMoney(item["budget"]),
|
|
107208
|
+
spend: item["spend"] != null && Number.isFinite(Number(item["spend"])) ? Number(item["spend"]) : 0,
|
|
107209
|
+
conversions: item["conversions"] != null && Number.isFinite(Number(item["conversions"])) ? Number(item["conversions"]) : null
|
|
107210
|
+
})).filter((r) => r.id);
|
|
107211
|
+
}
|
|
107212
|
+
async function fetchAdGroupsForDay(config, accountId, date, verbose) {
|
|
107213
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107214
|
+
const params = new URLSearchParams();
|
|
107215
|
+
params.set("startDate", toGoogleDate(date, 0));
|
|
107216
|
+
params.set("endDate", toGoogleDate(date, 0));
|
|
107217
|
+
const url = `${googleApiUrl}/adgroupnmanagement/v2/list/${accountId}?${params}`;
|
|
107218
|
+
const data = await apiFetch2(url, config, {}, verbose);
|
|
107219
|
+
return (data.data ?? []).map((item) => ({
|
|
107220
|
+
id: String(item["id"] ?? ""),
|
|
107221
|
+
name: String(item["name"] ?? ""),
|
|
107222
|
+
campaignName: String(item["campaignName"] ?? ""),
|
|
107223
|
+
statusV2: String(item["statusV2"] ?? ""),
|
|
107224
|
+
spend: item["spend"] != null && Number.isFinite(Number(item["spend"])) ? Number(item["spend"]) : 0,
|
|
107225
|
+
conversions: item["conversions"] != null && Number.isFinite(Number(item["conversions"])) ? Number(item["conversions"]) : null,
|
|
107226
|
+
targetCpaAmountYuan: toDisplayMoney(item["targetCpaAmount"])
|
|
107227
|
+
})).filter((r) => r.id);
|
|
107228
|
+
}
|
|
107229
|
+
async function fetchAdsForDay(config, accountId, date, verbose) {
|
|
107230
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107231
|
+
const params = new URLSearchParams();
|
|
107232
|
+
params.set("startDate", toGoogleDate(date, 0));
|
|
107233
|
+
params.set("endDate", toGoogleDate(date, 0));
|
|
107234
|
+
const url = `${googleApiUrl}/admanagement/v2/list/${accountId}?${params}`;
|
|
107235
|
+
const data = await apiFetch2(url, config, {}, verbose);
|
|
107236
|
+
return (data.data ?? []).map((item) => {
|
|
107237
|
+
const rawTitle = item["headlines"]?.[0] ?? item["adTitle"] ?? item["headlinePart1"] ?? item["name"] ?? "";
|
|
107238
|
+
return {
|
|
107239
|
+
id: String(item["id"] ?? ""),
|
|
107240
|
+
name: String(rawTitle),
|
|
107241
|
+
campaign: String(item["campaign"] ?? ""),
|
|
107242
|
+
adGroup: String(item["adGroup"] ?? ""),
|
|
107243
|
+
statusV2: String(item["statusV2"] ?? ""),
|
|
107244
|
+
spend: item["spend"] != null && Number.isFinite(Number(item["spend"])) ? Number(item["spend"]) : 0,
|
|
107245
|
+
conversions: item["conversions"] != null && Number.isFinite(Number(item["conversions"])) ? Number(item["conversions"]) : null
|
|
107246
|
+
};
|
|
107247
|
+
}).filter((r) => r.id);
|
|
107248
|
+
}
|
|
107249
|
+
async function pauseCampaign(config, accountId, campaignId, verbose) {
|
|
107250
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107251
|
+
const detailUrl = `${googleApiUrl}/campaignmanagement/campaign/${accountId}/${campaignId}`;
|
|
107252
|
+
const res = await apiFetch2(detailUrl, config, {}, verbose);
|
|
107253
|
+
const campaign = res.data ?? res;
|
|
107254
|
+
const body = { ...campaign, statusV2: "Paused" };
|
|
107255
|
+
await apiFetch2(detailUrl, config, { method: "PUT", body: JSON.stringify(body) }, verbose);
|
|
107256
|
+
}
|
|
107257
|
+
async function pauseAdGroup(config, accountId, adGroupId, date, verbose) {
|
|
107258
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107259
|
+
const listUrl = adgroupListUrl(googleApiUrl, accountId, date, date);
|
|
107260
|
+
const adgroup = await findItemInList(
|
|
107261
|
+
listUrl,
|
|
107262
|
+
config,
|
|
107263
|
+
adGroupId,
|
|
107264
|
+
verbose
|
|
107265
|
+
);
|
|
107266
|
+
const putUrl = `${googleApiUrl}/adgroupnmanagement/adgroup/${accountId}/${adGroupId}`;
|
|
107267
|
+
await apiFetch2(
|
|
107268
|
+
putUrl,
|
|
107269
|
+
config,
|
|
107270
|
+
{ method: "PUT", body: JSON.stringify({ ...adgroup, statusV2: "Paused" }) },
|
|
107271
|
+
verbose
|
|
107272
|
+
);
|
|
107273
|
+
}
|
|
107274
|
+
async function pauseAd(config, accountId, adId, date, verbose) {
|
|
107275
|
+
const googleApiUrl = requireGoogleApi(config);
|
|
107276
|
+
const params = new URLSearchParams();
|
|
107277
|
+
params.set("startDate", toGoogleDate(date, 0));
|
|
107278
|
+
params.set("endDate", toGoogleDate(date, 0));
|
|
107279
|
+
const listUrl = `${googleApiUrl}/admanagement/v2/list/${accountId}?${params}`;
|
|
107280
|
+
const ad = await findItemInList(listUrl, config, adId, verbose);
|
|
107281
|
+
const putUrl = `${googleApiUrl}/admanagement/campaign/${accountId}/${adId}`;
|
|
107282
|
+
await apiFetch2(
|
|
107283
|
+
putUrl,
|
|
107284
|
+
config,
|
|
107285
|
+
{ method: "PUT", body: JSON.stringify({ ...ad, statusV2: "Paused" }) },
|
|
107286
|
+
verbose
|
|
107287
|
+
);
|
|
107288
|
+
}
|
|
107289
|
+
function printHitsTable(title, rows, cols) {
|
|
107290
|
+
console.log(`
|
|
107291
|
+
${title}
|
|
107292
|
+
`);
|
|
107293
|
+
if (rows.length === 0) {
|
|
107294
|
+
console.log(" \uFF08\u65E0\u547D\u4E2D\uFF09\n");
|
|
107295
|
+
return;
|
|
107296
|
+
}
|
|
107297
|
+
printCliTable(rows, cols);
|
|
107298
|
+
console.log();
|
|
107299
|
+
}
|
|
107300
|
+
|
|
107301
|
+
// src/commands/guard/rules.ts
|
|
107302
|
+
function moneyGte(leftYuan, rightYuan) {
|
|
107303
|
+
return Math.round(leftYuan * 100) >= Math.round(rightYuan * 100);
|
|
107304
|
+
}
|
|
107305
|
+
function isBudgetCircuitHit(spend, budgetYuan, ratio) {
|
|
107306
|
+
if (spend == null || budgetYuan == null) return false;
|
|
107307
|
+
if (!Number.isFinite(spend) || !Number.isFinite(budgetYuan) || !Number.isFinite(ratio)) {
|
|
107308
|
+
return false;
|
|
107309
|
+
}
|
|
107310
|
+
if (budgetYuan <= 0 || ratio <= 0) return false;
|
|
107311
|
+
return moneyGte(spend, budgetYuan * ratio);
|
|
107312
|
+
}
|
|
107313
|
+
function isZeroConvHit(spend, conversions, targetCpaYuan, multiple) {
|
|
107314
|
+
if (spend == null || targetCpaYuan == null) return false;
|
|
107315
|
+
if (!Number.isFinite(spend) || !Number.isFinite(targetCpaYuan) || !Number.isFinite(multiple)) {
|
|
107316
|
+
return false;
|
|
107317
|
+
}
|
|
107318
|
+
if (targetCpaYuan <= 0 || multiple <= 0) return false;
|
|
107319
|
+
const conv = conversions == null || !Number.isFinite(conversions) ? 0 : conversions;
|
|
107320
|
+
if (conv !== 0) return false;
|
|
107321
|
+
return moneyGte(spend, targetCpaYuan * multiple);
|
|
107322
|
+
}
|
|
107323
|
+
function shanghaiToday(now = /* @__PURE__ */ new Date()) {
|
|
107324
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
107325
|
+
timeZone: "Asia/Shanghai",
|
|
107326
|
+
year: "numeric",
|
|
107327
|
+
month: "2-digit",
|
|
107328
|
+
day: "2-digit"
|
|
107329
|
+
}).format(now);
|
|
107330
|
+
}
|
|
107331
|
+
function isEnabledStatus(statusV2) {
|
|
107332
|
+
return String(statusV2 ?? "").toLowerCase() === "enabled";
|
|
107333
|
+
}
|
|
107334
|
+
|
|
107335
|
+
// src/commands/guard/budget-circuit.ts
|
|
107336
|
+
async function runBudgetCircuit(opts) {
|
|
107337
|
+
assertGoogleOnly(opts.media);
|
|
107338
|
+
const config = await resolveGuardConfig(opts);
|
|
107339
|
+
const date = opts.date?.trim() || shanghaiToday();
|
|
107340
|
+
const ratio = opts.ratio ?? 1.1;
|
|
107341
|
+
if (!Number.isFinite(ratio) || ratio <= 0) {
|
|
107342
|
+
console.error("\n\u274C --ratio \u5FC5\u987B\u4E3A\u6B63\u6570\uFF08\u4F8B\u5982 1.1\uFF09\n");
|
|
107343
|
+
process.exit(1);
|
|
107344
|
+
}
|
|
107345
|
+
const statusFilter = opts.status === void 0 ? "Enabled" : opts.status;
|
|
107346
|
+
const filterAll = statusFilter === "" || statusFilter === "*";
|
|
107347
|
+
const apply = Boolean(opts.apply);
|
|
107348
|
+
const accounts = await resolveGuardAccounts(opts, config);
|
|
107349
|
+
if (accounts.length === 0) {
|
|
107350
|
+
console.error("\n\u274C \u672A\u627E\u5230\u53EF\u626B\u63CF\u7684 Google \u8D26\u6237\u3002\n");
|
|
107351
|
+
process.exit(1);
|
|
107352
|
+
}
|
|
107353
|
+
process.stderr.write(
|
|
107354
|
+
`\u23F3 [guard budget-circuit] ${accounts.length} \u6237 \xB7 \u65E5\u671F ${date} \xB7 ratio=${ratio}${apply ? " \xB7 APPLY" : " \xB7 dry-run"}
|
|
107355
|
+
`
|
|
107356
|
+
);
|
|
107357
|
+
const accountResults = await runWithConcurrency(
|
|
107358
|
+
accounts.map((acc) => async () => {
|
|
107359
|
+
try {
|
|
107360
|
+
const campaigns = await fetchCampaignsForDay(
|
|
107361
|
+
config,
|
|
107362
|
+
acc.mediaCustomerId,
|
|
107363
|
+
date,
|
|
107364
|
+
opts.verbose
|
|
107365
|
+
);
|
|
107366
|
+
const hits2 = [];
|
|
107367
|
+
let checked = 0;
|
|
107368
|
+
for (const c of campaigns) {
|
|
107369
|
+
if (!filterAll) {
|
|
107370
|
+
if (statusFilter.toLowerCase() === "enabled") {
|
|
107371
|
+
if (!isEnabledStatus(c.statusV2)) continue;
|
|
107372
|
+
} else if (String(c.statusV2) !== statusFilter) {
|
|
107373
|
+
continue;
|
|
107374
|
+
}
|
|
107375
|
+
}
|
|
107376
|
+
checked++;
|
|
107377
|
+
if (!isBudgetCircuitHit(c.spend, c.budget, ratio)) continue;
|
|
107378
|
+
const budget = c.budget;
|
|
107379
|
+
const hit = {
|
|
107380
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107381
|
+
accountName: acc.name,
|
|
107382
|
+
campaignId: c.id,
|
|
107383
|
+
campaignName: c.name,
|
|
107384
|
+
statusV2: c.statusV2,
|
|
107385
|
+
spend: c.spend,
|
|
107386
|
+
budget,
|
|
107387
|
+
ratio,
|
|
107388
|
+
threshold: budget * ratio,
|
|
107389
|
+
applied: false
|
|
107390
|
+
};
|
|
107391
|
+
if (apply) {
|
|
107392
|
+
try {
|
|
107393
|
+
await pauseCampaign(config, acc.mediaCustomerId, c.id, opts.verbose);
|
|
107394
|
+
hit.applied = true;
|
|
107395
|
+
hit.statusV2 = "Paused";
|
|
107396
|
+
} catch (err) {
|
|
107397
|
+
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107398
|
+
}
|
|
107399
|
+
}
|
|
107400
|
+
hits2.push(hit);
|
|
107401
|
+
}
|
|
107402
|
+
return {
|
|
107403
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107404
|
+
accountName: acc.name,
|
|
107405
|
+
checked,
|
|
107406
|
+
hits: hits2
|
|
107407
|
+
};
|
|
107408
|
+
} catch (err) {
|
|
107409
|
+
return {
|
|
107410
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107411
|
+
accountName: acc.name,
|
|
107412
|
+
checked: 0,
|
|
107413
|
+
hits: [],
|
|
107414
|
+
error: err instanceof Error ? err.message : String(err)
|
|
107415
|
+
};
|
|
107416
|
+
}
|
|
107417
|
+
}),
|
|
107418
|
+
GUARD_ACCOUNT_CONCURRENCY
|
|
107419
|
+
);
|
|
107420
|
+
const hits = accountResults.flatMap((r) => r.hits);
|
|
107421
|
+
const errors = accountResults.filter((r) => r.error).map((r) => ({
|
|
107422
|
+
mediaCustomerId: r.mediaCustomerId,
|
|
107423
|
+
accountName: r.accountName,
|
|
107424
|
+
error: r.error
|
|
107425
|
+
}));
|
|
107426
|
+
const paused = hits.filter((h) => h.applied);
|
|
107427
|
+
const checkedCampaigns = accountResults.reduce((n, r) => n + r.checked, 0);
|
|
107428
|
+
const payload = {
|
|
107429
|
+
meta: {
|
|
107430
|
+
media: "Google",
|
|
107431
|
+
date,
|
|
107432
|
+
ratio,
|
|
107433
|
+
statusFilter: filterAll ? "*" : statusFilter,
|
|
107434
|
+
apply,
|
|
107435
|
+
note: "\u975E Google \u5A92\u4F53\u672C CLI \u65E0\u7CFB\u5217\u7194\u65AD\u5199\u80FD\u529B\uFF1B\u672C\u547D\u4EE4\u4EC5\u626B\u63CF Google\u3002"
|
|
107436
|
+
},
|
|
107437
|
+
summary: {
|
|
107438
|
+
label: "\u8D85\u9884\u7B97\u7194\u65AD",
|
|
107439
|
+
accountCount: accounts.length,
|
|
107440
|
+
checkedCampaigns,
|
|
107441
|
+
hitCount: hits.length,
|
|
107442
|
+
pausedCount: paused.length,
|
|
107443
|
+
errorCount: errors.length,
|
|
107444
|
+
mode: apply ? "apply" : "dry-run"
|
|
107445
|
+
},
|
|
107446
|
+
hits,
|
|
107447
|
+
paused,
|
|
107448
|
+
errors
|
|
107449
|
+
};
|
|
107450
|
+
if (await emitCliJsonOrSnapshot(opts, {
|
|
107451
|
+
section: "guard-budget-circuit",
|
|
107452
|
+
commandLabel: "guard budget-circuit",
|
|
107453
|
+
payload
|
|
107454
|
+
})) {
|
|
107455
|
+
}
|
|
107456
|
+
const title = `\u8D85\u9884\u7B97\u7194\u65AD\uFF08${apply ? "\u5DF2\u5C1D\u8BD5\u6682\u505C" : "dry-run"}\uFF09 \xB7 ${date} \xB7 ratio=${ratio} \xB7 \u547D\u4E2D ${hits.length}/${checkedCampaigns}`;
|
|
107457
|
+
printHitsTable(
|
|
107458
|
+
title,
|
|
107459
|
+
hits.map((h) => ({
|
|
107460
|
+
account: h.mediaCustomerId,
|
|
107461
|
+
campaign: h.campaignName.slice(0, 36),
|
|
107462
|
+
spend: h.spend.toFixed(2),
|
|
107463
|
+
budget: h.budget.toFixed(2),
|
|
107464
|
+
threshold: h.threshold.toFixed(2),
|
|
107465
|
+
applied: h.applied ? "Paused" : h.applyError ? `ERR:${h.applyError.slice(0, 20)}` : "\u2014"
|
|
107466
|
+
})),
|
|
107467
|
+
[
|
|
107468
|
+
{ key: "account", header: "\u8D26\u6237ID" },
|
|
107469
|
+
{ key: "campaign", header: "\u7CFB\u5217" },
|
|
107470
|
+
{ key: "spend", header: "\u5F53\u65E5\u82B1\u8D39" },
|
|
107471
|
+
{ key: "budget", header: "\u65E5\u9884\u7B97" },
|
|
107472
|
+
{ key: "threshold", header: "\u9608\u503C" },
|
|
107473
|
+
{ key: "applied", header: "\u6682\u505C" }
|
|
107474
|
+
]
|
|
107475
|
+
);
|
|
107476
|
+
if (errors.length > 0) {
|
|
107477
|
+
console.error(`\u26A0\uFE0F ${errors.length} \u4E2A\u8D26\u6237\u62C9\u6570\u5931\u8D25\uFF08\u8BE6\u89C1 json-out errors[]\uFF09`);
|
|
107478
|
+
for (const e of errors.slice(0, 5)) {
|
|
107479
|
+
console.error(` \u2022 ${e.mediaCustomerId}: ${e.error}`);
|
|
107480
|
+
}
|
|
107481
|
+
}
|
|
107482
|
+
if (!apply && hits.length > 0) {
|
|
107483
|
+
console.log(
|
|
107484
|
+
'\u63D0\u793A\uFF1A\u4EE5\u4E0A\u4E3A dry-run\u3002\u786E\u8BA4\u540E\u8FFD\u52A0 --apply --commit "budget-circuit <date>" \u6267\u884C\u6682\u505C\u3002\n'
|
|
107485
|
+
);
|
|
107486
|
+
} else if (apply) {
|
|
107487
|
+
console.log(
|
|
107488
|
+
`\u2705 apply \u5B8C\u6210\uFF1A\u547D\u4E2D ${hits.length}\uFF0C\u6210\u529F\u6682\u505C ${paused.length}${hits.length - paused.length > 0 ? `\uFF0C\u5931\u8D25 ${hits.length - paused.length}` : ""}\u3002
|
|
107489
|
+
`
|
|
107490
|
+
);
|
|
107491
|
+
} else {
|
|
107492
|
+
console.log("\u2705 \u4ECA\u65E5\u65E0\u7CFB\u5217\u89E6\u53D1\u8D85\u9884\u7B97\u7194\u65AD\u3002\n");
|
|
107493
|
+
}
|
|
107494
|
+
}
|
|
107495
|
+
|
|
107496
|
+
// src/commands/guard/zero-conv.ts
|
|
107497
|
+
init_cli_json_snapshot();
|
|
107498
|
+
function parseLevel(raw) {
|
|
107499
|
+
const v = (raw ?? "adgroup").toLowerCase();
|
|
107500
|
+
if (v === "adgroup" || v === "ad" || v === "both") return v;
|
|
107501
|
+
console.error("\n\u274C --level \u987B\u4E3A adgroup | ad | both\n");
|
|
107502
|
+
process.exit(1);
|
|
107503
|
+
}
|
|
107504
|
+
async function runZeroConv(opts) {
|
|
107505
|
+
assertGoogleOnly(opts.media);
|
|
107506
|
+
const config = await resolveGuardConfig(opts);
|
|
107507
|
+
const date = opts.date?.trim() || shanghaiToday();
|
|
107508
|
+
const multiple = opts.cpaMultiple ?? 3;
|
|
107509
|
+
if (!Number.isFinite(multiple) || multiple <= 0) {
|
|
107510
|
+
console.error("\n\u274C --cpa-multiple \u5FC5\u987B\u4E3A\u6B63\u6570\uFF08\u4F8B\u5982 3\uFF09\n");
|
|
107511
|
+
process.exit(1);
|
|
107512
|
+
}
|
|
107513
|
+
const level = parseLevel(opts.level);
|
|
107514
|
+
const fallback = opts.fallbackTargetCpa != null && Number.isFinite(opts.fallbackTargetCpa) ? opts.fallbackTargetCpa : null;
|
|
107515
|
+
const onlyEnabled = opts.onlyEnabled !== false;
|
|
107516
|
+
const apply = Boolean(opts.apply);
|
|
107517
|
+
if ((level === "ad" || level === "both") && fallback == null) {
|
|
107518
|
+
process.stderr.write(
|
|
107519
|
+
"\u26A0\uFE0F [guard zero-conv] \u521B\u610F\u7EF4\u65E0\u7EC4\u7EA7 targetCpa \u5B57\u6BB5\uFF0C\u672A\u4F20 --fallback-target-cpa \u65F6\u521B\u610F\u547D\u4E2D\u53EF\u80FD\u4E3A 0\uFF08\u4F1A\u8BB0\u5165 skipped\uFF09\u3002\n"
|
|
107520
|
+
);
|
|
107521
|
+
}
|
|
107522
|
+
const accounts = await resolveGuardAccounts(opts, config);
|
|
107523
|
+
if (accounts.length === 0) {
|
|
107524
|
+
console.error("\n\u274C \u672A\u627E\u5230\u53EF\u626B\u63CF\u7684 Google \u8D26\u6237\u3002\n");
|
|
107525
|
+
process.exit(1);
|
|
107526
|
+
}
|
|
107527
|
+
process.stderr.write(
|
|
107528
|
+
`\u23F3 [guard zero-conv] ${accounts.length} \u6237 \xB7 ${date} \xB7 \xD7${multiple} \xB7 level=${level}${apply ? " \xB7 APPLY" : " \xB7 dry-run"}
|
|
107529
|
+
`
|
|
107530
|
+
);
|
|
107531
|
+
const accountResults = await runWithConcurrency(
|
|
107532
|
+
accounts.map((acc) => async () => {
|
|
107533
|
+
try {
|
|
107534
|
+
const hits2 = [];
|
|
107535
|
+
const skipped2 = [];
|
|
107536
|
+
let checked2 = 0;
|
|
107537
|
+
if (level === "adgroup" || level === "both") {
|
|
107538
|
+
const groups = await fetchAdGroupsForDay(
|
|
107539
|
+
config,
|
|
107540
|
+
acc.mediaCustomerId,
|
|
107541
|
+
date,
|
|
107542
|
+
opts.verbose
|
|
107543
|
+
);
|
|
107544
|
+
for (const g of groups) {
|
|
107545
|
+
if (onlyEnabled && !isEnabledStatus(g.statusV2)) continue;
|
|
107546
|
+
checked2++;
|
|
107547
|
+
const target = g.targetCpaAmountYuan ?? fallback;
|
|
107548
|
+
if (target == null) {
|
|
107549
|
+
skipped2.push({
|
|
107550
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107551
|
+
level: "adgroup",
|
|
107552
|
+
objectId: g.id,
|
|
107553
|
+
objectName: g.name,
|
|
107554
|
+
reason: "missing_target_cpa"
|
|
107555
|
+
});
|
|
107556
|
+
continue;
|
|
107557
|
+
}
|
|
107558
|
+
if (!isZeroConvHit(g.spend, g.conversions, target, multiple)) continue;
|
|
107559
|
+
const hit = {
|
|
107560
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107561
|
+
accountName: acc.name,
|
|
107562
|
+
level: "adgroup",
|
|
107563
|
+
objectId: g.id,
|
|
107564
|
+
objectName: g.name,
|
|
107565
|
+
parentName: g.campaignName,
|
|
107566
|
+
statusV2: g.statusV2,
|
|
107567
|
+
spend: g.spend,
|
|
107568
|
+
conversions: g.conversions ?? 0,
|
|
107569
|
+
targetCpaYuan: target,
|
|
107570
|
+
multiple,
|
|
107571
|
+
threshold: target * multiple,
|
|
107572
|
+
applied: false
|
|
107573
|
+
};
|
|
107574
|
+
if (apply) {
|
|
107575
|
+
try {
|
|
107576
|
+
await pauseAdGroup(config, acc.mediaCustomerId, g.id, date, opts.verbose);
|
|
107577
|
+
hit.applied = true;
|
|
107578
|
+
hit.statusV2 = "Paused";
|
|
107579
|
+
} catch (err) {
|
|
107580
|
+
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107581
|
+
}
|
|
107582
|
+
}
|
|
107583
|
+
hits2.push(hit);
|
|
107584
|
+
}
|
|
107585
|
+
}
|
|
107586
|
+
if (level === "ad" || level === "both") {
|
|
107587
|
+
const ads = await fetchAdsForDay(config, acc.mediaCustomerId, date, opts.verbose);
|
|
107588
|
+
for (const ad of ads) {
|
|
107589
|
+
if (onlyEnabled && !isEnabledStatus(ad.statusV2)) continue;
|
|
107590
|
+
checked2++;
|
|
107591
|
+
if (fallback == null) {
|
|
107592
|
+
skipped2.push({
|
|
107593
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107594
|
+
level: "ad",
|
|
107595
|
+
objectId: ad.id,
|
|
107596
|
+
objectName: ad.name,
|
|
107597
|
+
reason: "missing_fallback_target_cpa"
|
|
107598
|
+
});
|
|
107599
|
+
continue;
|
|
107600
|
+
}
|
|
107601
|
+
if (!isZeroConvHit(ad.spend, ad.conversions, fallback, multiple)) continue;
|
|
107602
|
+
const hit = {
|
|
107603
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107604
|
+
accountName: acc.name,
|
|
107605
|
+
level: "ad",
|
|
107606
|
+
objectId: ad.id,
|
|
107607
|
+
objectName: ad.name,
|
|
107608
|
+
parentName: `${ad.campaign} / ${ad.adGroup}`,
|
|
107609
|
+
statusV2: ad.statusV2,
|
|
107610
|
+
spend: ad.spend,
|
|
107611
|
+
conversions: ad.conversions ?? 0,
|
|
107612
|
+
targetCpaYuan: fallback,
|
|
107613
|
+
multiple,
|
|
107614
|
+
threshold: fallback * multiple,
|
|
107615
|
+
applied: false
|
|
107616
|
+
};
|
|
107617
|
+
if (apply) {
|
|
107618
|
+
try {
|
|
107619
|
+
await pauseAd(config, acc.mediaCustomerId, ad.id, date, opts.verbose);
|
|
107620
|
+
hit.applied = true;
|
|
107621
|
+
hit.statusV2 = "Paused";
|
|
107622
|
+
} catch (err) {
|
|
107623
|
+
hit.applyError = err instanceof Error ? err.message : String(err);
|
|
107624
|
+
}
|
|
107625
|
+
}
|
|
107626
|
+
hits2.push(hit);
|
|
107627
|
+
}
|
|
107628
|
+
}
|
|
107629
|
+
return {
|
|
107630
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107631
|
+
accountName: acc.name,
|
|
107632
|
+
checked: checked2,
|
|
107633
|
+
hits: hits2,
|
|
107634
|
+
skipped: skipped2
|
|
107635
|
+
};
|
|
107636
|
+
} catch (err) {
|
|
107637
|
+
return {
|
|
107638
|
+
mediaCustomerId: acc.mediaCustomerId,
|
|
107639
|
+
accountName: acc.name,
|
|
107640
|
+
checked: 0,
|
|
107641
|
+
hits: [],
|
|
107642
|
+
skipped: [],
|
|
107643
|
+
error: err instanceof Error ? err.message : String(err)
|
|
107644
|
+
};
|
|
107645
|
+
}
|
|
107646
|
+
}),
|
|
107647
|
+
GUARD_ACCOUNT_CONCURRENCY
|
|
107648
|
+
);
|
|
107649
|
+
const hits = accountResults.flatMap((r) => r.hits);
|
|
107650
|
+
const skipped = accountResults.flatMap((r) => r.skipped);
|
|
107651
|
+
const errors = accountResults.filter((r) => r.error).map((r) => ({
|
|
107652
|
+
mediaCustomerId: r.mediaCustomerId,
|
|
107653
|
+
accountName: r.accountName,
|
|
107654
|
+
error: r.error
|
|
107655
|
+
}));
|
|
107656
|
+
const paused = hits.filter((h) => h.applied);
|
|
107657
|
+
const checked = accountResults.reduce((n, r) => n + r.checked, 0);
|
|
107658
|
+
const payload = {
|
|
107659
|
+
meta: {
|
|
107660
|
+
media: "Google",
|
|
107661
|
+
date,
|
|
107662
|
+
cpaMultiple: multiple,
|
|
107663
|
+
level,
|
|
107664
|
+
fallbackTargetCpa: fallback,
|
|
107665
|
+
apply,
|
|
107666
|
+
note: "\u975E Google \u5A92\u4F53\u672C CLI \u65E0\u7EC4/\u521B\u610F\u7194\u65AD\u5199\u80FD\u529B\uFF1B\u672C\u547D\u4EE4\u4EC5\u626B\u63CF Google\u3002P1\u300C\u7A7A\u8017\u7194\u65AD\u300D\u901A\u77E5\u7531\u5BBF\u4E3B\u53D1\u9001\u3002"
|
|
107667
|
+
},
|
|
107668
|
+
summary: {
|
|
107669
|
+
label: "\u7A7A\u8017\u7194\u65AD",
|
|
107670
|
+
accountCount: accounts.length,
|
|
107671
|
+
checkedObjects: checked,
|
|
107672
|
+
hitCount: hits.length,
|
|
107673
|
+
pausedCount: paused.length,
|
|
107674
|
+
skippedCount: skipped.length,
|
|
107675
|
+
errorCount: errors.length,
|
|
107676
|
+
mode: apply ? "apply" : "dry-run"
|
|
107677
|
+
},
|
|
107678
|
+
hits,
|
|
107679
|
+
paused,
|
|
107680
|
+
skipped,
|
|
107681
|
+
errors
|
|
107682
|
+
};
|
|
107683
|
+
await emitCliJsonOrSnapshot(opts, {
|
|
107684
|
+
section: "guard-zero-conv",
|
|
107685
|
+
commandLabel: "guard zero-conv",
|
|
107686
|
+
payload
|
|
107687
|
+
});
|
|
107688
|
+
const title = `\u7A7A\u8017\u7194\u65AD\uFF08${apply ? "\u5DF2\u5C1D\u8BD5\u6682\u505C" : "dry-run"}\uFF09 \xB7 ${date} \xB7 \xD7${multiple} \xB7 \u547D\u4E2D ${hits.length}/${checked}`;
|
|
107689
|
+
printHitsTable(
|
|
107690
|
+
title,
|
|
107691
|
+
hits.map((h) => ({
|
|
107692
|
+
account: h.mediaCustomerId,
|
|
107693
|
+
level: h.level,
|
|
107694
|
+
name: h.objectName.slice(0, 32),
|
|
107695
|
+
spend: h.spend.toFixed(2),
|
|
107696
|
+
target: h.targetCpaYuan.toFixed(2),
|
|
107697
|
+
threshold: h.threshold.toFixed(2),
|
|
107698
|
+
applied: h.applied ? "Paused" : h.applyError ? `ERR` : "\u2014"
|
|
107699
|
+
})),
|
|
107700
|
+
[
|
|
107701
|
+
{ key: "account", header: "\u8D26\u6237ID" },
|
|
107702
|
+
{ key: "level", header: "\u5C42\u7EA7" },
|
|
107703
|
+
{ key: "name", header: "\u5BF9\u8C61" },
|
|
107704
|
+
{ key: "spend", header: "\u5F53\u65E5\u82B1\u8D39" },
|
|
107705
|
+
{ key: "target", header: "\u76EE\u6807CPA" },
|
|
107706
|
+
{ key: "threshold", header: "\u9608\u503C" },
|
|
107707
|
+
{ key: "applied", header: "\u6682\u505C" }
|
|
107708
|
+
]
|
|
107709
|
+
);
|
|
107710
|
+
if (errors.length > 0) {
|
|
107711
|
+
console.error(`\u26A0\uFE0F ${errors.length} \u4E2A\u8D26\u6237\u62C9\u6570\u5931\u8D25\uFF08\u8BE6\u89C1 json-out errors[]\uFF09`);
|
|
107712
|
+
}
|
|
107713
|
+
if (!apply && hits.length > 0) {
|
|
107714
|
+
console.log(
|
|
107715
|
+
'\u63D0\u793A\uFF1A\u4EE5\u4E0A\u4E3A dry-run\u3002\u786E\u8BA4\u540E\u8FFD\u52A0 --apply --commit "zero-conv <date>" \u6267\u884C\u6682\u505C\u3002\n'
|
|
107716
|
+
);
|
|
107717
|
+
} else if (apply) {
|
|
107718
|
+
console.log(
|
|
107719
|
+
`\u2705 apply \u5B8C\u6210\uFF1A\u547D\u4E2D ${hits.length}\uFF0C\u6210\u529F\u6682\u505C ${paused.length}${hits.length - paused.length > 0 ? `\uFF0C\u5931\u8D25 ${hits.length - paused.length}` : ""}\u3002
|
|
107720
|
+
`
|
|
107721
|
+
);
|
|
107722
|
+
} else {
|
|
107723
|
+
console.log("\u2705 \u4ECA\u65E5\u65E0\u5BF9\u8C61\u89E6\u53D1\u7A7A\u8017\u7194\u65AD\u3002\n");
|
|
107724
|
+
}
|
|
107725
|
+
}
|
|
107726
|
+
|
|
107727
|
+
// src/commands/guard/_register.ts
|
|
107728
|
+
function register11(program2) {
|
|
107729
|
+
const guard = program2.command("guard").description(
|
|
107730
|
+
"Google \u6295\u653E\u81EA\u63A7\u7194\u65AD\uFF1A\u5168\u6237\uFF08\u6216 -a \u5B50\u96C6\uFF09\u626B\u63CF\u5F53\u65E5\u8D85\u9884\u7B97/\u7A7A\u8017\u547D\u4E2D\uFF0C\u9ED8\u8BA4 dry-run\uFF1B--apply \u65F6\u6682\u505C\u547D\u4E2D\u5BF9\u8C61\uFF08\u987B\u5168\u5C40 --commit\uFF09\u3002\u975E Google \u5A92\u4F53\u4E0D\u652F\u6301\u3002"
|
|
107731
|
+
);
|
|
107732
|
+
guard.command("budget-circuit").description(
|
|
107733
|
+
"\u5355\u65E5\u9884\u7B97\u7194\u65AD\uFF1A\u5F53\u65E5\u7CFB\u5217 spend \u2265 \u65E5\u9884\u7B97 \xD7 ratio \u65F6\u5217\u51FA\uFF08\u53EF\u9009\u6682\u505C\uFF09\u3002\u66FF\u4EE3\u300Clist-accounts \xD7 N + \u9010\u6237 ad campaigns + \u811A\u672C\u300D\u3002"
|
|
107734
|
+
).requiredOption("-m, --media <type>", "\u76EE\u524D\u4EC5\u652F\u6301 Google").option(
|
|
107735
|
+
"-a, --accounts <ids>",
|
|
107736
|
+
"\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u540D\u4E0B\u5168\u90E8 Google \u8D26\u6237"
|
|
107737
|
+
).option("--date <YYYY-MM-DD>", "\u7EDF\u8BA1\u65E5\uFF08Asia/Shanghai \u9ED8\u8BA4\u4ECA\u5929\uFF09\uFF1B\u5F3A\u5236 start=end=\u8BE5\u65E5").option("--ratio <n>", "\u9608\u503C\u7CFB\u6570\uFF1Aspend >= budget * ratio\uFF08\u9ED8\u8BA4 1.1\uFF09", (v) => parseFloat(v)).option(
|
|
107738
|
+
"--status <statusV2>",
|
|
107739
|
+
"\u53EA\u68C0\u67E5\u8BE5\u72B6\u6001\u7684\u7CFB\u5217\uFF08\u9ED8\u8BA4 Enabled\uFF1B\u4F20 * \u8868\u793A\u4E0D\u8FC7\u6EE4\uFF09",
|
|
107740
|
+
"Enabled"
|
|
107741
|
+
).option("--apply", "\u5BF9\u547D\u4E2D\u7CFB\u5217\u6267\u884C Paused\uFF08\u987B\u914D\u5408\u5168\u5C40 --commit\uFF09", false).option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF09").option(
|
|
107742
|
+
"--json-out <path>",
|
|
107743
|
+
"\u843D\u76D8\u76EE\u5F55\u6216 *.json\uFF1Bstdout \u4E00\u884C\u6458\u8981\uFF1B\u4EBA\u7C7B\u53EF\u8BFB\u8868\u59CB\u7EC8\u6253\u5370",
|
|
107744
|
+
void 0
|
|
107745
|
+
).option("--refresh-dp", "\u5F3A\u5236\u91CD\u62C9 Datapermission", false).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF", false).action(
|
|
107746
|
+
async (opts) => {
|
|
107747
|
+
await runBudgetCircuit({
|
|
107748
|
+
media: opts.media,
|
|
107749
|
+
accounts: opts.accounts,
|
|
107750
|
+
date: opts.date,
|
|
107751
|
+
ratio: opts.ratio,
|
|
107752
|
+
status: opts.status,
|
|
107753
|
+
apply: opts.apply,
|
|
107754
|
+
pageSize: opts.pageSize,
|
|
107755
|
+
maxPages: opts.maxPages,
|
|
107756
|
+
token: opts.token,
|
|
107757
|
+
jsonOut: opts.jsonOut,
|
|
107758
|
+
refreshDp: opts.refreshDp,
|
|
107759
|
+
verbose: opts.verbose
|
|
107760
|
+
});
|
|
107761
|
+
}
|
|
107762
|
+
);
|
|
107763
|
+
guard.command("zero-conv").description(
|
|
107764
|
+
"\u7A7A\u8017\u7194\u65AD\uFF1A\u5F53\u65E5 spend \u2265 \u76EE\u6807 CPA \xD7 N \u4E14\u8F6C\u5316\u4E3A 0 \u65F6\u5217\u51FA\u7EC4/\u521B\u610F\uFF08\u53EF\u9009\u6682\u505C\uFF09\u3002\u7ED3\u679C summary.label=\u300C\u7A7A\u8017\u7194\u65AD\u300D\uFF1BP1 \u901A\u77E5\u7531\u5BBF\u4E3B\u53D1\u9001\u3002"
|
|
107765
|
+
).requiredOption("-m, --media <type>", "\u76EE\u524D\u4EC5\u652F\u6301 Google").option(
|
|
107766
|
+
"-a, --accounts <ids>",
|
|
107767
|
+
"\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u540D\u4E0B\u5168\u90E8 Google \u8D26\u6237"
|
|
107768
|
+
).option("--date <YYYY-MM-DD>", "\u7EDF\u8BA1\u65E5\uFF08Asia/Shanghai \u9ED8\u8BA4\u4ECA\u5929\uFF09").option(
|
|
107769
|
+
"--cpa-multiple <n>",
|
|
107770
|
+
"\u500D\u6570 N\uFF1Aspend >= targetCpa \xD7 N\uFF08\u9ED8\u8BA4 3\uFF09",
|
|
107771
|
+
(v) => parseFloat(v)
|
|
107772
|
+
).option(
|
|
107773
|
+
"--level <level>",
|
|
107774
|
+
"\u626B\u63CF\u5C42\u7EA7\uFF1Aadgroup | ad | both\uFF08\u9ED8\u8BA4 adgroup\uFF09",
|
|
107775
|
+
"adgroup"
|
|
107776
|
+
).option(
|
|
107777
|
+
"--fallback-target-cpa <yuan>",
|
|
107778
|
+
"\u7EC4\u65E0 targetCpa\uFF08\u6216\u521B\u610F\u7EF4\uFF09\u65F6\u4F7F\u7528\u7684\u76EE\u6807 CPA\uFF08\u5143\uFF09",
|
|
107779
|
+
(v) => parseFloat(v)
|
|
107780
|
+
).option("--apply", "\u5BF9\u547D\u4E2D\u5BF9\u8C61\u6267\u884C Paused\uFF08\u987B\u914D\u5408\u5168\u5C40 --commit\uFF09", false).option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF09").option("--json-out <path>", "\u843D\u76D8\u76EE\u5F55\u6216 *.json", void 0).option("--refresh-dp", "\u5F3A\u5236\u91CD\u62C9 Datapermission", false).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF", false).action(
|
|
107781
|
+
async (opts) => {
|
|
107782
|
+
await runZeroConv({
|
|
107783
|
+
media: opts.media,
|
|
107784
|
+
accounts: opts.accounts,
|
|
107785
|
+
date: opts.date,
|
|
107786
|
+
cpaMultiple: opts.cpaMultiple,
|
|
107787
|
+
level: opts.level,
|
|
107788
|
+
fallbackTargetCpa: opts.fallbackTargetCpa,
|
|
107789
|
+
apply: opts.apply,
|
|
107790
|
+
pageSize: opts.pageSize,
|
|
107791
|
+
maxPages: opts.maxPages,
|
|
107792
|
+
token: opts.token,
|
|
107793
|
+
jsonOut: opts.jsonOut,
|
|
107794
|
+
refreshDp: opts.refreshDp,
|
|
107795
|
+
verbose: opts.verbose
|
|
107796
|
+
});
|
|
107797
|
+
}
|
|
107798
|
+
);
|
|
107799
|
+
}
|
|
107800
|
+
|
|
107058
107801
|
// src/commands/stats.ts
|
|
107059
107802
|
init_auth();
|
|
107060
107803
|
init_cli_json_snapshot();
|
|
@@ -107307,7 +108050,7 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
|
|
|
107307
108050
|
printCliTable(rows, cols);
|
|
107308
108051
|
console.log();
|
|
107309
108052
|
}
|
|
107310
|
-
function
|
|
108053
|
+
function register12(program2) {
|
|
107311
108054
|
program2.command("stats").description(
|
|
107312
108055
|
"\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\u533A\u95F4\u5408\u8BA1\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF0C\u65E5\u5386\u6309 UTC+8\uFF1B\u8981\u6309\u65E5\u660E\u7EC6\u52A0 --by-day\uFF09"
|
|
107313
108056
|
).requiredOption(
|
|
@@ -107426,7 +108169,7 @@ async function runAccountHistory(opts) {
|
|
|
107426
108169
|
}
|
|
107427
108170
|
console.log();
|
|
107428
108171
|
}
|
|
107429
|
-
function
|
|
108172
|
+
function register13(program2) {
|
|
107430
108173
|
program2.command("account-history").description("\u67E5\u8BE2\u5F00\u6237\u7533\u8BF7\u5386\u53F2\u8BB0\u5F55").option("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | MetaAd | BingV2 | Kwai").option("-s, --status <status>", "\u7533\u8BF7\u72B6\u6001\u5173\u952E\u5B57").option("-k, --keyword <text>", "\u641C\u7D22\u5173\u952E\u5B57\uFF08\u8D26\u6237\u540D/ID\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09", parseInt).option("-t, --token <token>", "Auth Token").option(
|
|
107431
108174
|
"--json-out <path>",
|
|
107432
108175
|
"\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
|
|
@@ -108268,7 +109011,7 @@ async function runReportPushReceiveEmails(opts) {
|
|
|
108268
109011
|
var splitCsv = (v) => v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
108269
109012
|
|
|
108270
109013
|
// src/commands/report/register.ts
|
|
108271
|
-
function
|
|
109014
|
+
function register14(program2) {
|
|
108272
109015
|
const reportCmd = program2.command("report").description("\u4F18\u5316\u62A5\u544A\u4E0E\u63A8\u9001\u7BA1\u7406");
|
|
108273
109016
|
reportCmd.command("list").description("\u67E5\u8BE2\u4F18\u5316\u62A5\u544A\u5217\u8868").requiredOption("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok").option("-t, --type <type>", "\u62A5\u544A\u7C7B\u578B\uFF08\u5982 Daily / Hourly\uFF09").option("-s, --status <ready>", "\u751F\u6210\u72B6\u6001\uFF08true/false\uFF09").option("-k, --keyword <text>", "\u62A5\u544A\u540D\u79F0\u5173\u952E\u5B57").option("--start <date>", "\u5F00\u59CB\u65E5\u671F").option("--end <date>", "\u7ED3\u675F\u65E5\u671F").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("--token <token>", "Auth Token").option(
|
|
108274
109017
|
"--json-out <path>",
|
|
@@ -108596,7 +109339,7 @@ async function runTransferList(opts) {
|
|
|
108596
109339
|
printCliTable(rows, cols);
|
|
108597
109340
|
console.log();
|
|
108598
109341
|
}
|
|
108599
|
-
function
|
|
109342
|
+
function register15(program2) {
|
|
108600
109343
|
const transferCmd = program2.command("transfer").description("\u5A92\u4F53\u8D26\u6237\u8F6C\u8D26\uFF1A\u63D0\u4EA4\u8F6C\u8D26\u7533\u8BF7\u6216\u67E5\u8BE2\u8F6C\u8D26\u8BB0\u5F55");
|
|
108601
109344
|
transferCmd.command("create").description("\u63D0\u4EA4\u8D26\u6237\u95F4\u8F6C\u8D26\u7533\u8BF7\uFF08Google / TikTok / MetaAd / BingV2\uFF09").requiredOption("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | MetaAd | BingV2").requiredOption("--out <id>", "\u8F6C\u51FA\u8D26\u6237 mediaCustomerId\uFF08\u6765\u81EA list-accounts\uFF09").requiredOption("--in <id>", "\u8F6C\u5165\u8D26\u6237 mediaCustomerId\uFF08\u6765\u81EA list-accounts\uFF09").requiredOption("--amount <amount>", "\u8F6C\u8D26\u91D1\u989D\uFF08\u4E0E\u8D26\u6237\u8D27\u5E01\u5355\u4F4D\u4E00\u81F4\uFF09").option("--customer-name <name>", "\u5BA2\u6237\u540D\u79F0\uFF08\u5907\u6CE8\uFF0C\u53EF\u9009\uFF09").option("-t, --token <token>", "Auth Token").option(
|
|
108602
109345
|
"--json-out <path>",
|
|
@@ -109041,7 +109784,7 @@ async function runInvoiceApply(opts) {
|
|
|
109041
109784
|
}
|
|
109042
109785
|
|
|
109043
109786
|
// src/commands/invoice/_register.ts
|
|
109044
|
-
function
|
|
109787
|
+
function register16(program2) {
|
|
109045
109788
|
const invoiceCmd = program2.command("invoice").description("\u5F00\u7968\u8BB0\u5F55\u4E0E\u5F00\u7968\u7533\u8BF7\uFF0C\u4E0D\u652F\u6301\u8D26\u6237\u6FC0\u6D3B\u5145\u503C\u8BA2\u5355\u7684\u5F00\u7968\uFF0C\u5982\u9700\u5F00\u7968\u8BF7\u8054\u7CFB\u7EBF\u4E0B\u8FD0\u8425");
|
|
109046
109789
|
invoiceCmd.command("list").description("\u67E5\u8BE2\u5F00\u7968\u7533\u8BF7\u8BB0\u5F55").option("-k, --keyword <text>", "\u53D1\u7968\u53F7\u6216\u5173\u952E\u5B57").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option(
|
|
109047
109790
|
"--json-out <path>",
|
|
@@ -109312,7 +110055,7 @@ async function runInvoiceInfoDelete(opts) {
|
|
|
109312
110055
|
\u2705 \u53D1\u7968\u62AC\u5934\u5DF2\u5220\u9664\uFF08ID: ${opts.id}\uFF09
|
|
109313
110056
|
`);
|
|
109314
110057
|
}
|
|
109315
|
-
function
|
|
110058
|
+
function register17(program2) {
|
|
109316
110059
|
const invoiceInfoCmd = program2.command("invoice-info").description("\u53D1\u7968\u62AC\u5934\u7BA1\u7406\uFF08\u5BF9\u5E94\u300C\u8BBE\u7F6E \u2192 \u53D1\u7968\u62AC\u5934\u300D\u9875\u9762\uFF09");
|
|
109317
110060
|
invoiceInfoCmd.command("list").description("\u67E5\u8BE2\u5DF2\u4FDD\u5B58\u7684\u53D1\u7968\u62AC\u5934\u5217\u8868").option("-k, --keyword <text>", "\u6309\u516C\u53F8\u540D\u79F0\u641C\u7D22").option("--invoice-type <type>", "\u6309\u53D1\u7968\u7C7B\u578B\u7B5B\u9009\uFF1API | VATI | VATSI").option("--page <n>", "\u9875\u7801", (v) => parseInt(v), 1).option("--page-size <n>", "\u6BCF\u9875\u6761\u6570", (v) => parseInt(v), 20).option("-t, --token <token>", "Auth Token").option(
|
|
109318
110061
|
"--json-out <path>",
|
|
@@ -109660,7 +110403,7 @@ async function runOptimizeChildren(opts) {
|
|
|
109660
110403
|
}
|
|
109661
110404
|
|
|
109662
110405
|
// src/commands/optimize/_register.ts
|
|
109663
|
-
function
|
|
110406
|
+
function register18(program2) {
|
|
109664
110407
|
const optimizeCmd = program2.command("optimize").description("AI \u5E7F\u544A\u4F18\u5316\uFF08Google\uFF09");
|
|
109665
110408
|
optimizeCmd.command("list").description("\u67E5\u8BE2\u8D26\u6237\u7EA7\u4F18\u5316\u4E3B\u5217\u8868\uFF08\u5BF9\u5E94\u9875\u9762 /advertising/intelligentOptimization\uFF09").option("-a, --account <id>", "\u8D26\u6237 mediaCustomerId\uFF08\u7559\u7A7A\u67E5\u5168\u90E8\uFF09").option(
|
|
109666
110409
|
"--match-media-customer-id <id>",
|
|
@@ -109720,13 +110463,31 @@ function register17(program2) {
|
|
|
109720
110463
|
}
|
|
109721
110464
|
|
|
109722
110465
|
// src/commands/forewarning/_shared.ts
|
|
110466
|
+
init_dist();
|
|
109723
110467
|
var VALID_MEDIA_TYPES7 = ["Google", "TikTok"];
|
|
110468
|
+
function skipForewarningInAgentEnv(commandLabel = "siluzan-tso forewarning") {
|
|
110469
|
+
if (!isSiluzanAgentEnv()) return false;
|
|
110470
|
+
console.log(
|
|
110471
|
+
`
|
|
110472
|
+
\u2139\uFE0F \u68C0\u6D4B\u5230 Siluzan Agent \u73AF\u5883\uFF08IS_SILUZAN_AGENT_ENV=true\uFF09\u3002
|
|
110473
|
+
\`${commandLabel}\` \u5728 Agent \u6C99\u7BB1\u4E2D\u4E0D\u53EF\u7528\uFF0C\u5DF2\u8DF3\u8FC7\uFF08\u4E0D\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\uFF09\u3002
|
|
110474
|
+
|
|
110475
|
+
\u8BF7\u6539\u4E3A\uFF1A\u521B\u5EFA\u81EA\u52A8\u5316\u4EFB\u52A1\uFF0C\u5728\u4EFB\u52A1\u4E2D\u8C03\u7528 siluzan-tso \u672C Skill
|
|
110476
|
+
\uFF08\u62C9\u6570 / guard / \u5199\u547D\u4EE4\u7B49\uFF09\u5B8C\u6210\u7528\u6237\u7684\u9884\u8B66\u4E0E\u5DE1\u68C0\u9700\u6C42\u3002
|
|
110477
|
+
|
|
110478
|
+
\u5FC5\u8BFB\uFF1Areferences/operations/hosted-automation-user-catalog.md
|
|
110479
|
+
\uFF08\u9884\u7B97\u7194\u65AD / \u5F02\u5E38\u76D1\u63A7 / \u81EA\u52A8\u4F18\u5316\uFF1B\u8868\u5185\u6BCF\u884C\u53EA Read \u4E00\u4E2A SOP\uFF09
|
|
110480
|
+
`
|
|
110481
|
+
);
|
|
110482
|
+
return true;
|
|
110483
|
+
}
|
|
109724
110484
|
|
|
109725
110485
|
// src/commands/forewarning/list.ts
|
|
109726
110486
|
init_auth();
|
|
109727
110487
|
init_cli_json_snapshot();
|
|
109728
110488
|
init_cli_table();
|
|
109729
110489
|
async function runForewarningList(opts) {
|
|
110490
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning list")) return;
|
|
109730
110491
|
if (!VALID_MEDIA_TYPES7.includes(opts.media)) {
|
|
109731
110492
|
console.error(
|
|
109732
110493
|
`
|
|
@@ -109809,6 +110570,7 @@ init_auth();
|
|
|
109809
110570
|
init_cli_json_snapshot();
|
|
109810
110571
|
init_cli_table();
|
|
109811
110572
|
async function runForewarningRecords(opts) {
|
|
110573
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning records")) return;
|
|
109812
110574
|
if (!VALID_MEDIA_TYPES7.includes(opts.media)) {
|
|
109813
110575
|
console.error(`
|
|
109814
110576
|
\u274C \u4E0D\u652F\u6301\u7684\u5A92\u4F53\u7C7B\u578B\uFF1A${opts.media}
|
|
@@ -109884,6 +110646,7 @@ async function runForewarningRecords(opts) {
|
|
|
109884
110646
|
// src/commands/forewarning/actions.ts
|
|
109885
110647
|
init_auth();
|
|
109886
110648
|
async function runForewarningStart(opts) {
|
|
110649
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning start")) return;
|
|
109887
110650
|
const config = loadConfig(opts.token);
|
|
109888
110651
|
const url = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}/${opts.id}/start`;
|
|
109889
110652
|
try {
|
|
@@ -109897,6 +110660,7 @@ async function runForewarningStart(opts) {
|
|
|
109897
110660
|
console.log("\n\u2705 \u9884\u8B66\u89C4\u5219\u5DF2\u542F\u52A8\n");
|
|
109898
110661
|
}
|
|
109899
110662
|
async function runForewarningStop(opts) {
|
|
110663
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning stop")) return;
|
|
109900
110664
|
const config = loadConfig(opts.token);
|
|
109901
110665
|
const url = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}/${opts.id}/stop`;
|
|
109902
110666
|
try {
|
|
@@ -109910,6 +110674,7 @@ async function runForewarningStop(opts) {
|
|
|
109910
110674
|
console.log("\n\u2705 \u9884\u8B66\u89C4\u5219\u5DF2\u505C\u6B62\n");
|
|
109911
110675
|
}
|
|
109912
110676
|
async function runForewarningDelete(opts) {
|
|
110677
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning delete")) return;
|
|
109913
110678
|
const config = loadConfig(opts.token);
|
|
109914
110679
|
const url = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}/${opts.id}`;
|
|
109915
110680
|
try {
|
|
@@ -109923,6 +110688,7 @@ async function runForewarningDelete(opts) {
|
|
|
109923
110688
|
console.log("\n\u2705 \u9884\u8B66\u89C4\u5219\u5DF2\u5220\u9664\n");
|
|
109924
110689
|
}
|
|
109925
110690
|
async function runForewarningGet(opts) {
|
|
110691
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning get")) return;
|
|
109926
110692
|
const config = loadConfig(opts.token);
|
|
109927
110693
|
const url = `${config.apiBaseUrl}/query/smart-strategy/settings/${opts.media}/${opts.id}`;
|
|
109928
110694
|
let data;
|
|
@@ -109946,6 +110712,7 @@ import QRCode from "qrcode";
|
|
|
109946
110712
|
import open2 from "open";
|
|
109947
110713
|
init_cli_table();
|
|
109948
110714
|
async function runForewarningNotifyAccounts(opts) {
|
|
110715
|
+
if (skipForewarningInAgentEnv("siluzan-tso forewarning notify-accounts")) return;
|
|
109949
110716
|
const config = loadConfig(opts.token);
|
|
109950
110717
|
const listUrl = `${config.apiBaseUrl}/query/notice-account/getAccount`;
|
|
109951
110718
|
let accounts;
|
|
@@ -110066,6 +110833,11 @@ function buildRuleBody(opts) {
|
|
|
110066
110833
|
};
|
|
110067
110834
|
}
|
|
110068
110835
|
async function runForewarningCreate(opts) {
|
|
110836
|
+
if (skipForewarningInAgentEnv(
|
|
110837
|
+
opts.id ? "siluzan-tso forewarning update" : "siluzan-tso forewarning create"
|
|
110838
|
+
)) {
|
|
110839
|
+
return;
|
|
110840
|
+
}
|
|
110069
110841
|
if (!VALID_MEDIA_TYPES7.includes(opts.media)) {
|
|
110070
110842
|
console.error(
|
|
110071
110843
|
`
|
|
@@ -110106,7 +110878,7 @@ async function runForewarningCreate(opts) {
|
|
|
110106
110878
|
}
|
|
110107
110879
|
|
|
110108
110880
|
// src/commands/forewarning/_register.ts
|
|
110109
|
-
function
|
|
110881
|
+
function register19(program2) {
|
|
110110
110882
|
const forewarningCmd = program2.command("forewarning").description("\u667A\u80FD\u9884\u8B66\u89C4\u5219\u4E0E\u9884\u8B66\u8BB0\u5F55\u7BA1\u7406");
|
|
110111
110883
|
forewarningCmd.command("list").description("\u67E5\u8BE2\u9884\u8B66\u89C4\u5219\u5217\u8868").requiredOption("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok").option("-a, --account <id>", "\u8D26\u6237 ID \u7B5B\u9009").option("-k, --keyword <text>", "\u89C4\u5219\u540D\u79F0\u5173\u952E\u5B57").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option(
|
|
110112
110884
|
"--json-out <path>",
|
|
@@ -110398,7 +111170,7 @@ Meta \u7EBF\u7D22\u8868\u5355\uFF08\u8D26\u6237 ${opts.account}\uFF0C\u7B2C 1 \u
|
|
|
110398
111170
|
console.log();
|
|
110399
111171
|
}
|
|
110400
111172
|
}
|
|
110401
|
-
function
|
|
111173
|
+
function register20(program2) {
|
|
110402
111174
|
program2.command("clue").description("\u67E5\u8BE2\u5E7F\u544A\u7EBF\u7D22\u8868\u5355\u6570\u636E\uFF08TikTok / Meta\uFF09").option("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1ATikTok | Meta", "TikTok").requiredOption("-a, --account <id>", "\u5E7F\u544A\u8D26\u6237 mediaCustomerId").option("--region <region>", "TikTok \u533A\u57DF\uFF1Aeu | us | other | ALL\uFF08\u9ED8\u8BA4 ALL\uFF09").option("--start <date>", "Meta \u5F00\u59CB\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").option("--end <date>", "Meta \u7ED3\u675F\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").option(
|
|
110403
111175
|
"--json-out <path>",
|
|
110404
111176
|
"\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
|
|
@@ -110417,80 +111189,6 @@ function register19(program2) {
|
|
|
110417
111189
|
});
|
|
110418
111190
|
}
|
|
110419
111191
|
|
|
110420
|
-
// src/commands/ad/_shared.ts
|
|
110421
|
-
init_auth();
|
|
110422
|
-
async function findItemInList(listUrl, config, id, verbose) {
|
|
110423
|
-
const res = await apiFetch2(listUrl, config, {}, verbose);
|
|
110424
|
-
const item = (res.data ?? []).find((x) => x["id"] === id);
|
|
110425
|
-
if (!item) {
|
|
110426
|
-
throw new Error(`\u672A\u5728\u5217\u8868\u4E2D\u627E\u5230 id="${id}" \u7684\u6761\u76EE`);
|
|
110427
|
-
}
|
|
110428
|
-
return item;
|
|
110429
|
-
}
|
|
110430
|
-
function toGoogleDate(dateStr, offsetDays) {
|
|
110431
|
-
if (dateStr) return dateStr.replace(/-/g, "/");
|
|
110432
|
-
const d = /* @__PURE__ */ new Date();
|
|
110433
|
-
d.setDate(d.getDate() + offsetDays);
|
|
110434
|
-
return d.toISOString().slice(0, 10).replace(/-/g, "/");
|
|
110435
|
-
}
|
|
110436
|
-
function toDisplayMoney(raw) {
|
|
110437
|
-
if (raw == null) return null;
|
|
110438
|
-
const n = Number(raw);
|
|
110439
|
-
if (!Number.isFinite(n)) return null;
|
|
110440
|
-
return n / 100;
|
|
110441
|
-
}
|
|
110442
|
-
function toCentAmount(displayValue) {
|
|
110443
|
-
if (!Number.isFinite(displayValue)) {
|
|
110444
|
-
throw new Error(`toCentAmount: \u8F93\u5165\u5FC5\u987B\u662F\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${displayValue}`);
|
|
110445
|
-
}
|
|
110446
|
-
return Math.round(displayValue * 100);
|
|
110447
|
-
}
|
|
110448
|
-
var CAMPAIGN_BATCH_MONEY_KEYS = /* @__PURE__ */ new Set([
|
|
110449
|
-
"Budget",
|
|
110450
|
-
"MaxCPCAmount",
|
|
110451
|
-
"MaxCpmAmount",
|
|
110452
|
-
"MaxCPVAmount",
|
|
110453
|
-
"TargetCpa_BidingAmount",
|
|
110454
|
-
"TargetSpend_BidCeilingAmount",
|
|
110455
|
-
"TargetCpaAmount",
|
|
110456
|
-
"MaxCPC"
|
|
110457
|
-
]);
|
|
110458
|
-
function convertBatchMoneyTreeFromYuan(value) {
|
|
110459
|
-
return convertBatchMoneyTreeFromYuanInner(value);
|
|
110460
|
-
}
|
|
110461
|
-
function convertBatchMoneyTreeFromYuanInner(value) {
|
|
110462
|
-
if (Array.isArray(value)) {
|
|
110463
|
-
return value.map(convertBatchMoneyTreeFromYuanInner);
|
|
110464
|
-
}
|
|
110465
|
-
if (value && typeof value === "object") {
|
|
110466
|
-
const out = {};
|
|
110467
|
-
for (const [key, val] of Object.entries(value)) {
|
|
110468
|
-
if (typeof val === "number" && CAMPAIGN_BATCH_MONEY_KEYS.has(key)) {
|
|
110469
|
-
out[key] = toCentAmount(val);
|
|
110470
|
-
} else {
|
|
110471
|
-
out[key] = convertBatchMoneyTreeFromYuanInner(val);
|
|
110472
|
-
}
|
|
110473
|
-
}
|
|
110474
|
-
return out;
|
|
110475
|
-
}
|
|
110476
|
-
return value;
|
|
110477
|
-
}
|
|
110478
|
-
function adgroupListUrl(googleApiUrl, account, startDate, endDate) {
|
|
110479
|
-
const params = new URLSearchParams();
|
|
110480
|
-
params.set("startDate", toGoogleDate(startDate, -30));
|
|
110481
|
-
params.set("endDate", toGoogleDate(endDate, 0));
|
|
110482
|
-
return `${googleApiUrl}/adgroupnmanagement/v2/list/${account}?${params}`;
|
|
110483
|
-
}
|
|
110484
|
-
function requireGoogleApi(config) {
|
|
110485
|
-
if (!config.googleApiUrl) {
|
|
110486
|
-
console.error(
|
|
110487
|
-
"\n\u274C \u672A\u627E\u5230 Google API \u5730\u5740\u3002\n Google API \u5730\u5740\u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_GOOGLE_API \u8986\u76D6\u3002\n"
|
|
110488
|
-
);
|
|
110489
|
-
process.exit(1);
|
|
110490
|
-
}
|
|
110491
|
-
return config.googleApiUrl;
|
|
110492
|
-
}
|
|
110493
|
-
|
|
110494
111192
|
// src/commands/ad/campaign.ts
|
|
110495
111193
|
init_auth();
|
|
110496
111194
|
init_cli_json_snapshot();
|
|
@@ -119638,7 +120336,7 @@ function parseOptionalMatchType(raw) {
|
|
|
119638
120336
|
`);
|
|
119639
120337
|
process.exit(1);
|
|
119640
120338
|
}
|
|
119641
|
-
function
|
|
120339
|
+
function register21(program2) {
|
|
119642
120340
|
const adCmd = program2.command("ad").description(
|
|
119643
120341
|
"Google \u5E7F\u544A\u7BA1\u7406\uFF08Google API \u5730\u5740\u4ECE TSO API \u81EA\u52A8\u63A8\u5BFC\uFF0C\u53EF\u901A\u8FC7 SILUZAN_GOOGLE_API \u73AF\u5883\u53D8\u91CF\u8986\u76D6\uFF09\n \u542B\uFF1A\u7CFB\u5217/\u7EC4/\u521B\u610F/\u5173\u952E\u8BCD\u7B49\u5E38\u89C4\u5E7F\u544A\u6295\u653E\u4E0E\u7BA1\u7406\u80FD\u529B"
|
|
119644
120342
|
);
|
|
@@ -121311,7 +122009,7 @@ function attachBaseCliOptions(cmd) {
|
|
|
121311
122009
|
function splitKeywordSeeds(raw) {
|
|
121312
122010
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
121313
122011
|
}
|
|
121314
|
-
function
|
|
122012
|
+
function register22(program2) {
|
|
121315
122013
|
const keywordCmd = program2.command("keyword").description(
|
|
121316
122014
|
"Google \u5173\u952E\u5B57\u63A8\u8350\uFF08\u53EF\u9009 -a \u8D26\u6237 ID \u6309\u8D26\u6237\u5E01\u79CD\u51FA\u4EF7\uFF1B\u5426\u5219\u5171\u4EAB MCC/USD\uFF1B\u53EF --geo \u9650\u5B9A\u5E02\u573A\uFF09"
|
|
121317
122015
|
);
|
|
@@ -121780,7 +122478,7 @@ async function runRagList(options) {
|
|
|
121780
122478
|
];
|
|
121781
122479
|
console.log(lines.join("\n"));
|
|
121782
122480
|
}
|
|
121783
|
-
function
|
|
122481
|
+
function register23(program2) {
|
|
121784
122482
|
const ragCmd = program2.command("rag").description(
|
|
121785
122483
|
"RAG \u77E5\u8BC6\u5E93\u68C0\u7D22\uFF08\u534F\u52A9\u5E7F\u544A\u6295\u653E\u3001\u62D3\u8BCD\u3001\u8D26\u6237\u8BCA\u65AD\u4E0E\u62A5\u544A\uFF1B\u9ED8\u8BA4 belongToId=account/me \u7684 companyId\uFF09"
|
|
121786
122484
|
);
|
|
@@ -123231,7 +123929,7 @@ async function runAccountBmBind(opts) {
|
|
|
123231
123929
|
}
|
|
123232
123930
|
|
|
123233
123931
|
// src/commands/account-manage-register.ts
|
|
123234
|
-
function
|
|
123932
|
+
function register24(program2) {
|
|
123235
123933
|
const accountCmd = program2.command("account").description("\u5E7F\u544A\u8D26\u6237\u7BA1\u7406\uFF1AOAuth \u6DFB\u52A0\u6388\u6743\u3001\u89E3\u9664\u5173\u8054\uFF08\u89E3\u7ED1\uFF09\u3001Google MCC \u7ED1\u5B9A/\u89E3\u7ED1\u3001\u8D26\u53F7\u5206\u4EAB");
|
|
123236
123934
|
accountCmd.command("list", { hidden: true }).description("\uFF08\u517C\u5BB9\u522B\u540D\uFF09\u540C list-accounts").option(
|
|
123237
123935
|
"-m, --media <type>",
|
|
@@ -125061,7 +125759,7 @@ async function runOpenAccountMeta(opts) {
|
|
|
125061
125759
|
}
|
|
125062
125760
|
|
|
125063
125761
|
// src/commands/open-account-register.ts
|
|
125064
|
-
function
|
|
125762
|
+
function register25(program2) {
|
|
125065
125763
|
const openAccountCmd = program2.command("open-account").description("\u5F00\u6237\u7533\u8BF7\uFF08Google / TikTok / Yandex / Bing / Kwai / Meta \u5F00\u6237\u94FE\u63A5\uFF09");
|
|
125066
125764
|
openAccountCmd.command("meta").description(
|
|
125067
125765
|
"\u83B7\u53D6 Meta/Facebook \u5B98\u65B9\u5F00\u6237\u94FE\u63A5\uFF08GET MetaAccount/Management/GetOpenAccountLink\uFF0C\u4E0E\u7F51\u9875\u300C\u7533\u8BF7\u5F00\u6237\u300D\u4E00\u81F4\uFF09"
|
|
@@ -125285,7 +125983,7 @@ function register24(program2) {
|
|
|
125285
125983
|
}
|
|
125286
125984
|
|
|
125287
125985
|
// src/commands/diagnostic.ts
|
|
125288
|
-
function
|
|
125986
|
+
function register26(program2) {
|
|
125289
125987
|
program2.command("diagnostic").description("\u8BCA\u65AD\u5165\u53E3\u8BF4\u660E\uFF1AGoogle \u5E7F\u544A\u8D26\u6237\u8BCA\u65AD\u9875 vs \u7F51\u7AD9\u8BCA\u65AD CLI").action(() => {
|
|
125290
125988
|
console.log("\n\u8BCA\u65AD\u80FD\u529B\u8BF4\u660E\n");
|
|
125291
125989
|
console.log(" \u3010Google \u5E7F\u544A\u8D26\u6237\u8BCA\u65AD\u3011");
|
|
@@ -129055,12 +129753,12 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129055
129753
|
const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
|
|
129056
129754
|
const kpis = { ...payload.kpis ?? {} };
|
|
129057
129755
|
if (current) {
|
|
129058
|
-
if (
|
|
129059
|
-
if (
|
|
129060
|
-
if (
|
|
129061
|
-
if (
|
|
129062
|
-
if (
|
|
129063
|
-
if (
|
|
129756
|
+
if (current.spend != null) kpis.spend = current.spend;
|
|
129757
|
+
if (current.results != null) kpis.results = current.results;
|
|
129758
|
+
if (current.costPerResult != null) kpis.costPerResult = current.costPerResult;
|
|
129759
|
+
if (current.reach != null) kpis.reach = current.reach;
|
|
129760
|
+
if (current.impressions != null) kpis.impressions = current.impressions;
|
|
129761
|
+
if (current.frequency != null) kpis.frequency = current.frequency;
|
|
129064
129762
|
}
|
|
129065
129763
|
const meta = { ...payload.meta ?? {} };
|
|
129066
129764
|
if (!meta.accountName && accountName) meta.accountName = accountName;
|
|
@@ -129073,12 +129771,12 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129073
129771
|
if (!meta.resultType && current?.resultType) meta.resultType = String(current.resultType);
|
|
129074
129772
|
const charts = { ...payload.charts ?? {} };
|
|
129075
129773
|
const avgCpl = num5(kpis.costPerResult) ?? 0;
|
|
129076
|
-
|
|
129774
|
+
{
|
|
129077
129775
|
const platform = sectionMap.get("platform");
|
|
129078
129776
|
const networks = Array.isArray(platform?.networks) ? platform.networks : [];
|
|
129079
129777
|
if (networks.length) charts.platform = aggregatePlatform(networks);
|
|
129080
129778
|
}
|
|
129081
|
-
|
|
129779
|
+
{
|
|
129082
129780
|
const country = sectionMap.get("country");
|
|
129083
129781
|
const countries = Array.isArray(country?.countries) ? country.countries : [];
|
|
129084
129782
|
if (countries.length) {
|
|
@@ -129089,7 +129787,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129089
129787
|
};
|
|
129090
129788
|
}
|
|
129091
129789
|
}
|
|
129092
|
-
|
|
129790
|
+
{
|
|
129093
129791
|
const audience = sectionMap.get("audience");
|
|
129094
129792
|
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
129095
129793
|
if (audiences.length) {
|
|
@@ -129101,11 +129799,11 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129101
129799
|
};
|
|
129102
129800
|
}
|
|
129103
129801
|
}
|
|
129104
|
-
if (
|
|
129802
|
+
if (num5(kpis.reach) != null) {
|
|
129105
129803
|
charts.funnel = { reach: kpis.reach, results: kpis.results ?? 0 };
|
|
129106
129804
|
}
|
|
129107
129805
|
const tables = { ...payload.tables ?? {} };
|
|
129108
|
-
|
|
129806
|
+
{
|
|
129109
129807
|
const adSets = sectionMap.get("ad-sets");
|
|
129110
129808
|
const groups = Array.isArray(adSets?.adGroups) ? adSets.adGroups : [];
|
|
129111
129809
|
if (groups.length) {
|
|
@@ -129128,15 +129826,13 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129128
129826
|
}).sort((a, b) => b.spend - a.spend);
|
|
129129
129827
|
}
|
|
129130
129828
|
}
|
|
129131
|
-
|
|
129829
|
+
{
|
|
129132
129830
|
const audience = sectionMap.get("audience");
|
|
129133
129831
|
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
129134
129832
|
if (audiences.length) {
|
|
129135
129833
|
const rows = buildAudienceRows(audiences).sort((a, b) => a.costPerResult - b.costPerResult);
|
|
129136
|
-
|
|
129137
|
-
|
|
129138
|
-
if (!tables.audienceTop) tables.audienceTop = topN;
|
|
129139
|
-
if (!tables.audienceBottom) tables.audienceBottom = bottomN;
|
|
129834
|
+
tables.audienceTop = rows.slice(0, 10);
|
|
129835
|
+
tables.audienceBottom = [...rows].reverse().slice(0, 10);
|
|
129140
129836
|
}
|
|
129141
129837
|
}
|
|
129142
129838
|
const currency = typeof meta.currency === "string" ? meta.currency : "USD";
|
|
@@ -129851,17 +130547,26 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129851
130547
|
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
129852
130548
|
const kpis = { ...payload.kpis ?? {} };
|
|
129853
130549
|
if (currentPeriod) {
|
|
129854
|
-
|
|
129855
|
-
|
|
129856
|
-
|
|
129857
|
-
|
|
129858
|
-
|
|
129859
|
-
|
|
129860
|
-
|
|
129861
|
-
|
|
129862
|
-
|
|
129863
|
-
|
|
129864
|
-
|
|
130550
|
+
const spend = num6(currentPeriod.spend);
|
|
130551
|
+
const impressions = num6(currentPeriod.impressions);
|
|
130552
|
+
const clicks = num6(currentPeriod.clicks);
|
|
130553
|
+
const results = num6(currentPeriod.results);
|
|
130554
|
+
const costPerResult = num6(currentPeriod.costPerResult);
|
|
130555
|
+
const ctr = num6(currentPeriod.ctr);
|
|
130556
|
+
const cpc = num6(currentPeriod.cpc ?? currentPeriod.averageCpc);
|
|
130557
|
+
const reach = num6(currentPeriod.reach);
|
|
130558
|
+
const frequency = num6(currentPeriod.frequency);
|
|
130559
|
+
if (spend != null) kpis.spend = spend;
|
|
130560
|
+
if (impressions != null) kpis.impressions = impressions;
|
|
130561
|
+
if (clicks != null) kpis.clicks = clicks;
|
|
130562
|
+
if (results != null) kpis.results = results;
|
|
130563
|
+
if (costPerResult != null) kpis.costPerResult = costPerResult;
|
|
130564
|
+
if (ctr != null) kpis.ctr = ctr;
|
|
130565
|
+
if (cpc != null) kpis.cpc = cpc;
|
|
130566
|
+
if (reach != null) kpis.reach = reach;
|
|
130567
|
+
if (frequency != null) kpis.frequency = frequency;
|
|
130568
|
+
}
|
|
130569
|
+
if (previousPeriod) {
|
|
129865
130570
|
kpis.previousPeriod = {
|
|
129866
130571
|
spend: num6(previousPeriod.spend),
|
|
129867
130572
|
impressions: num6(previousPeriod.impressions),
|
|
@@ -129875,7 +130580,7 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129875
130580
|
};
|
|
129876
130581
|
}
|
|
129877
130582
|
const tables = { ...payload.tables ?? {} };
|
|
129878
|
-
|
|
130583
|
+
{
|
|
129879
130584
|
const rows = asRows(sectionMap.get("ad-sets")?.adGroups).map(
|
|
129880
130585
|
(r) => pickMetricExtras(r, [
|
|
129881
130586
|
"adGroupId",
|
|
@@ -129886,38 +130591,38 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129886
130591
|
);
|
|
129887
130592
|
if (rows.length > 0) tables.adSets = rows;
|
|
129888
130593
|
}
|
|
129889
|
-
|
|
130594
|
+
{
|
|
129890
130595
|
const rows = asRows(sectionMap.get("platform")?.networks).map(
|
|
129891
130596
|
(r) => pickMetricExtras(r, ["publisherPlatform", "platformPosition", "network"])
|
|
129892
130597
|
);
|
|
129893
130598
|
if (rows.length > 0) tables.platform = rows;
|
|
129894
130599
|
}
|
|
129895
|
-
|
|
130600
|
+
{
|
|
129896
130601
|
const rows = asRows(sectionMap.get("country")?.countries).map(
|
|
129897
130602
|
(r) => pickMetricExtras(r, ["countryOrRegion"])
|
|
129898
130603
|
);
|
|
129899
130604
|
if (rows.length > 0) tables.country = rows;
|
|
129900
130605
|
}
|
|
129901
|
-
|
|
130606
|
+
{
|
|
129902
130607
|
const rows = asRows(sectionMap.get("audience")?.audiences).map(
|
|
129903
130608
|
(r) => pickMetricExtras(r, ["age", "gender"])
|
|
129904
130609
|
);
|
|
129905
130610
|
if (rows.length > 0) tables.audience = rows;
|
|
129906
130611
|
}
|
|
129907
|
-
|
|
130612
|
+
{
|
|
129908
130613
|
const rows = asRows(sectionMap.get("creative")?.creatives).map(
|
|
129909
130614
|
(r) => pickMetricExtras(r, ["adId", "adName", "creativeType", "title"])
|
|
129910
130615
|
);
|
|
129911
130616
|
if (rows.length > 0) tables.creative = rows;
|
|
129912
130617
|
}
|
|
129913
|
-
|
|
130618
|
+
{
|
|
129914
130619
|
const mat = sectionMap.get("material");
|
|
129915
130620
|
const rows = asRows(mat?.materials).map(
|
|
129916
130621
|
(r) => pickMetricExtras(r, ["materialId", "materialName", "materialType"])
|
|
129917
130622
|
);
|
|
129918
130623
|
if (rows.length > 0) {
|
|
129919
130624
|
tables.material = rows;
|
|
129920
|
-
if (
|
|
130625
|
+
if (mat) {
|
|
129921
130626
|
tables.materialMeta = {
|
|
129922
130627
|
dataSource: mat.dataSource,
|
|
129923
130628
|
message: mat.message
|
|
@@ -130220,7 +130925,7 @@ function resolveSectionList2(sections, exclude) {
|
|
|
130220
130925
|
}
|
|
130221
130926
|
|
|
130222
130927
|
// src/commands/facebook-analysis/run-batch.ts
|
|
130223
|
-
async function
|
|
130928
|
+
async function runWithConcurrency3(tasks, concurrency) {
|
|
130224
130929
|
const results = new Array(tasks.length);
|
|
130225
130930
|
let cursor = 0;
|
|
130226
130931
|
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
@@ -130284,7 +130989,7 @@ async function runAllFacebookSections(opts) {
|
|
|
130284
130989
|
}
|
|
130285
130990
|
}
|
|
130286
130991
|
);
|
|
130287
|
-
const results = await
|
|
130992
|
+
const results = await runWithConcurrency3(tasks, concurrency);
|
|
130288
130993
|
const succeeded = results.filter((r) => r.ok).length;
|
|
130289
130994
|
const failed = results.length - succeeded;
|
|
130290
130995
|
const absoluteSnapshotDir = path35.resolve(opts.jsonOut);
|
|
@@ -130796,7 +131501,7 @@ init_auth();
|
|
|
130796
131501
|
import * as path36 from "path";
|
|
130797
131502
|
import { performance as performance6 } from "perf_hooks";
|
|
130798
131503
|
init_version();
|
|
130799
|
-
async function
|
|
131504
|
+
async function runWithConcurrency4(tasks, concurrency) {
|
|
130800
131505
|
const results = new Array(tasks.length);
|
|
130801
131506
|
let cursor = 0;
|
|
130802
131507
|
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
@@ -130864,7 +131569,7 @@ async function runAllBingSections(opts) {
|
|
|
130864
131569
|
};
|
|
130865
131570
|
}
|
|
130866
131571
|
});
|
|
130867
|
-
const results = await
|
|
131572
|
+
const results = await runWithConcurrency4(tasks, concurrency);
|
|
130868
131573
|
const succeeded = results.filter((r) => r.ok).length;
|
|
130869
131574
|
const failed = results.length - succeeded;
|
|
130870
131575
|
const absoluteSnapshotDir = path36.resolve(opts.jsonOut);
|
|
@@ -131128,25 +131833,27 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131128
131833
|
costPerConversion: num8(currentPeriod.costPerConversion)
|
|
131129
131834
|
} : null);
|
|
131130
131835
|
if (currentKpiSource) {
|
|
131131
|
-
if (
|
|
131132
|
-
if (
|
|
131133
|
-
if (
|
|
131134
|
-
if (
|
|
131135
|
-
if (
|
|
131136
|
-
if (
|
|
131137
|
-
if (
|
|
131138
|
-
|
|
131139
|
-
|
|
131140
|
-
|
|
131141
|
-
|
|
131142
|
-
|
|
131143
|
-
|
|
131144
|
-
|
|
131145
|
-
|
|
131146
|
-
|
|
131147
|
-
kpis.
|
|
131148
|
-
|
|
131149
|
-
|
|
131836
|
+
if (currentKpiSource.spend != null) kpis.spend = currentKpiSource.spend;
|
|
131837
|
+
if (currentKpiSource.impressions != null) kpis.impressions = currentKpiSource.impressions;
|
|
131838
|
+
if (currentKpiSource.clicks != null) kpis.clicks = currentKpiSource.clicks;
|
|
131839
|
+
if (currentKpiSource.conversions != null) kpis.conversions = currentKpiSource.conversions;
|
|
131840
|
+
if (currentKpiSource.ctr != null) kpis.ctr = currentKpiSource.ctr;
|
|
131841
|
+
if (currentKpiSource.averageCpc != null) kpis.averageCpc = currentKpiSource.averageCpc;
|
|
131842
|
+
if (currentKpiSource.costPerConversion != null) {
|
|
131843
|
+
kpis.costPerConversion = currentKpiSource.costPerConversion;
|
|
131844
|
+
}
|
|
131845
|
+
}
|
|
131846
|
+
if (overview) {
|
|
131847
|
+
const avgDaily = num8(overview.averageDailyCost);
|
|
131848
|
+
if (avgDaily != null) kpis.averageDailyCost = avgDaily;
|
|
131849
|
+
const bal = num8(overview.balance);
|
|
131850
|
+
if (bal != null) kpis.balance = bal;
|
|
131851
|
+
const rem = num8(overview.remainingAccountBudget);
|
|
131852
|
+
if (rem != null) kpis.remainingAccountBudget = rem;
|
|
131853
|
+
const opt = num8(overview.optimizationScore);
|
|
131854
|
+
if (opt != null) kpis.optimizationScore = opt;
|
|
131855
|
+
}
|
|
131856
|
+
if (previousPeriod) {
|
|
131150
131857
|
kpis.previousPeriod = {
|
|
131151
131858
|
spend: num8(previousPeriod.spend),
|
|
131152
131859
|
impressions: num8(previousPeriod.impressions),
|
|
@@ -131158,35 +131865,33 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131158
131865
|
};
|
|
131159
131866
|
}
|
|
131160
131867
|
const tables = { ...payload.tables ?? {} };
|
|
131161
|
-
|
|
131868
|
+
{
|
|
131162
131869
|
const rows = mapDeviceRows(sectionMap.get("device"));
|
|
131163
131870
|
if (rows.length > 0) tables.devices = rows;
|
|
131164
131871
|
}
|
|
131165
|
-
|
|
131872
|
+
{
|
|
131166
131873
|
const rows = mapGeographicRows(sectionMap.get("geographic"));
|
|
131167
131874
|
if (rows.length > 0) tables.geographic = rows;
|
|
131168
131875
|
}
|
|
131169
131876
|
const audienceMapped = mapAudienceRows(sectionMap.get("audience-merged"));
|
|
131170
|
-
if (
|
|
131171
|
-
|
|
131172
|
-
}
|
|
131173
|
-
if (!tables.audienceGender && audienceMapped.audienceGender.length > 0) {
|
|
131877
|
+
if (audienceMapped.audienceAge.length > 0) tables.audienceAge = audienceMapped.audienceAge;
|
|
131878
|
+
if (audienceMapped.audienceGender.length > 0) {
|
|
131174
131879
|
tables.audienceGender = audienceMapped.audienceGender;
|
|
131175
131880
|
}
|
|
131176
|
-
if (
|
|
131177
|
-
|
|
131881
|
+
if (campaignRows2.length > 0) tables.campaigns = campaignRows2;
|
|
131882
|
+
{
|
|
131178
131883
|
const rows = mapAdGroupRows(sectionMap.get("ad-groups"));
|
|
131179
131884
|
if (rows.length > 0) tables.adGroups = rows;
|
|
131180
131885
|
}
|
|
131181
|
-
|
|
131886
|
+
{
|
|
131182
131887
|
const rows = mapAdRows(sectionMap.get("ads"));
|
|
131183
131888
|
if (rows.length > 0) tables.ads = rows;
|
|
131184
131889
|
}
|
|
131185
|
-
|
|
131890
|
+
{
|
|
131186
131891
|
const rows = mapKeywordRows(sectionMap.get("keywords"));
|
|
131187
131892
|
if (rows.length > 0) tables.keywords = rows;
|
|
131188
131893
|
}
|
|
131189
|
-
|
|
131894
|
+
{
|
|
131190
131895
|
const rows = mapSearchTermRows(sectionMap.get("search-terms"));
|
|
131191
131896
|
if (rows.length > 0) tables.searchTerms = rows;
|
|
131192
131897
|
}
|
|
@@ -131666,7 +132371,7 @@ init_auth();
|
|
|
131666
132371
|
import * as path39 from "path";
|
|
131667
132372
|
import { performance as performance7 } from "perf_hooks";
|
|
131668
132373
|
init_version();
|
|
131669
|
-
async function
|
|
132374
|
+
async function runWithConcurrency5(tasks, concurrency) {
|
|
131670
132375
|
const results = new Array(tasks.length);
|
|
131671
132376
|
let cursor = 0;
|
|
131672
132377
|
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
@@ -131735,7 +132440,7 @@ async function runAllTikTokSections(opts) {
|
|
|
131735
132440
|
}
|
|
131736
132441
|
}
|
|
131737
132442
|
);
|
|
131738
|
-
const results = await
|
|
132443
|
+
const results = await runWithConcurrency5(tasks, concurrency);
|
|
131739
132444
|
const succeeded = results.filter((r) => r.ok).length;
|
|
131740
132445
|
const failed = results.length - succeeded;
|
|
131741
132446
|
const absoluteSnapshotDir = path39.resolve(opts.jsonOut);
|
|
@@ -131963,15 +132668,17 @@ async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131963
132668
|
costPerConversion: num9(currentPeriod.costPerConversion)
|
|
131964
132669
|
} : null);
|
|
131965
132670
|
if (currentKpiSource) {
|
|
131966
|
-
if (
|
|
131967
|
-
if (
|
|
131968
|
-
if (
|
|
131969
|
-
if (
|
|
131970
|
-
if (
|
|
131971
|
-
if (
|
|
131972
|
-
if (
|
|
131973
|
-
|
|
131974
|
-
|
|
132671
|
+
if (currentKpiSource.spend != null) kpis.spend = currentKpiSource.spend;
|
|
132672
|
+
if (currentKpiSource.impressions != null) kpis.impressions = currentKpiSource.impressions;
|
|
132673
|
+
if (currentKpiSource.clicks != null) kpis.clicks = currentKpiSource.clicks;
|
|
132674
|
+
if (currentKpiSource.conversions != null) kpis.conversions = currentKpiSource.conversions;
|
|
132675
|
+
if (currentKpiSource.ctr != null) kpis.ctr = currentKpiSource.ctr;
|
|
132676
|
+
if (currentKpiSource.averageCpc != null) kpis.averageCpc = currentKpiSource.averageCpc;
|
|
132677
|
+
if (currentKpiSource.costPerConversion != null) {
|
|
132678
|
+
kpis.costPerConversion = currentKpiSource.costPerConversion;
|
|
132679
|
+
}
|
|
132680
|
+
}
|
|
132681
|
+
if (previousPeriod) {
|
|
131975
132682
|
kpis.previousPeriod = {
|
|
131976
132683
|
spend: num9(previousPeriod.spend),
|
|
131977
132684
|
impressions: num9(previousPeriod.impressions),
|
|
@@ -131983,29 +132690,29 @@ async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131983
132690
|
};
|
|
131984
132691
|
}
|
|
131985
132692
|
const tables = { ...payload.tables ?? {} };
|
|
131986
|
-
if (
|
|
131987
|
-
|
|
132693
|
+
if (camps.length > 0) tables.campaigns = mapCampaignTable(camps);
|
|
132694
|
+
{
|
|
131988
132695
|
const rows = mapAdGroupTable(sectionMap.get("ad-groups"));
|
|
131989
132696
|
if (rows.length > 0) tables.adGroups = rows;
|
|
131990
132697
|
}
|
|
131991
|
-
|
|
132698
|
+
{
|
|
131992
132699
|
const rows = mapAdTable(sectionMap.get("ads"));
|
|
131993
132700
|
if (rows.length > 0) tables.ads = rows;
|
|
131994
132701
|
}
|
|
131995
|
-
|
|
132702
|
+
{
|
|
131996
132703
|
const rows = mapVideoTable(sectionMap.get("videos"));
|
|
131997
132704
|
if (rows.length > 0) tables.videos = rows;
|
|
131998
132705
|
}
|
|
131999
132706
|
const fromMerged = mapAudienceMerged(sectionMap.get("audience-merged"));
|
|
132000
|
-
|
|
132707
|
+
{
|
|
132001
132708
|
const rows = fromMerged.audienceGender.length > 0 ? fromMerged.audienceGender : mapAudienceList(sectionMap.get("audience-gender"), "gender", "gender");
|
|
132002
132709
|
if (rows.length > 0) tables.audienceGender = rows;
|
|
132003
132710
|
}
|
|
132004
|
-
|
|
132711
|
+
{
|
|
132005
132712
|
const rows = fromMerged.audienceAge.length > 0 ? fromMerged.audienceAge : mapAudienceList(sectionMap.get("audience-age"), "age", "ageRange");
|
|
132006
132713
|
if (rows.length > 0) tables.audienceAge = rows;
|
|
132007
132714
|
}
|
|
132008
|
-
|
|
132715
|
+
{
|
|
132009
132716
|
const rows = fromMerged.audienceInterest.length > 0 ? fromMerged.audienceInterest : mapAudienceList(
|
|
132010
132717
|
sectionMap.get("audience-interest-category"),
|
|
132011
132718
|
"interest_category",
|
|
@@ -132332,11 +133039,29 @@ function jsonOutMissingPath(args) {
|
|
|
132332
133039
|
}
|
|
132333
133040
|
return false;
|
|
132334
133041
|
}
|
|
133042
|
+
function adSubcommandHasMediaFlag(args) {
|
|
133043
|
+
if (args[0] !== "ad") return false;
|
|
133044
|
+
const sub = args[1];
|
|
133045
|
+
if (!sub || sub.startsWith("-")) return false;
|
|
133046
|
+
for (let i = 2; i < args.length; i++) {
|
|
133047
|
+
const a = args[i];
|
|
133048
|
+
if (a === "-m" || a === "--media" || a.startsWith("--media=")) return true;
|
|
133049
|
+
}
|
|
133050
|
+
return false;
|
|
133051
|
+
}
|
|
133052
|
+
function hasDateFromTo(args) {
|
|
133053
|
+
return args.some(
|
|
133054
|
+
(a) => a === "--date-from" || a === "--date-to" || a.startsWith("--date-from=") || a.startsWith("--date-to=")
|
|
133055
|
+
);
|
|
133056
|
+
}
|
|
132335
133057
|
function agentCompatFatalMessage(argv) {
|
|
132336
133058
|
const args = argv.slice(2);
|
|
132337
133059
|
if (args.includes("--period") || args.some((a) => a.startsWith("--period="))) {
|
|
132338
133060
|
return "\n\u274C \u6CA1\u6709 --period \u9009\u9879\u3002\u8BF7\u7528 --start/--end\uFF08\u6216\u517C\u5BB9\u522B\u540D --start-date/--end-date\uFF09\u6307\u5B9A YYYY-MM-DD \u533A\u95F4\u3002\n";
|
|
132339
133061
|
}
|
|
133062
|
+
if (hasDateFromTo(args)) {
|
|
133063
|
+
return "\n\u274C \u6CA1\u6709 `--date-from` / `--date-to`\u3002\u8BF7\u7528 `--start` / `--end`\uFF08YYYY-MM-DD\uFF09\u3002\n \u5355\u65E5\u9884\u7B97/\u7A7A\u8017\u7194\u65AD\u8BF7\u7528\uFF1Asiluzan-tso guard budget-circuit|zero-conv -m Google --date <\u5F53\u65E5> --json-out <dir>\n";
|
|
133064
|
+
}
|
|
132340
133065
|
if (jsonOutMissingPath(args)) {
|
|
132341
133066
|
return "\n\u274C `--json-out` \u5FC5\u987B\u5E26\u8DEF\u5F84\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\uFF09\uFF0CJSON \u843D\u76D8\u800C\u975E\u6253\u5370\u5230 stdout\uFF0C\u4E0D\u80FD\u7BA1\u9053\u7ED9 python/jq\u3002\n \u793A\u4F8B\uFF1Asiluzan-tso ad campaigns -a <id> --json-out ./snap\n \u7136\u540E\u7528 node/python \u8BFB ./snap \u4E0B writtenFiles\uFF08\u89C1 stdout \u6458\u8981\u7684 absoluteSnapshotDir\uFF09\u3002\n";
|
|
132342
133067
|
}
|
|
@@ -132344,6 +133069,12 @@ function agentCompatFatalMessage(argv) {
|
|
|
132344
133069
|
if (cmd === "google-ads") {
|
|
132345
133070
|
return "\n\u274C \u6CA1\u6709 `google-ads` \u547D\u540D\u7A7A\u95F4\u3002\u8BF7\u6539\u7528\uFF1A\n - \u8D26\u6237\u5206\u6790\u62C9\u6570\uFF1Asiluzan-tso google-analysis \u2026\n - \u5E7F\u544A\u7CFB\u5217/\u7EC4/\u521B\u610F/\u5173\u952E\u8BCD\uFF1Asiluzan-tso ad campaigns|groups|list|keywords \u2026\n \uFF08\u6CA1\u6709 campaign-list\uFF1B\u5217\u8868\u547D\u4EE4\u662F campaigns / groups / list / keywords\uFF09\n - \u5E7F\u544A\u8BCA\u65AD\u62A5\u544A\uFF1Asiluzan-tso google-ads-diagnosis \u2026\n";
|
|
132346
133071
|
}
|
|
133072
|
+
if (cmd === "adgroups" || cmd === "ad" && args[1] === "adgroups") {
|
|
133073
|
+
return "\n\u274C \u6CA1\u6709 `adgroups` \u547D\u4EE4\u3002\u8BF7\u7528\uFF1Asiluzan-tso ad groups -a <mediaCustomerId> --json-out <dir>\n";
|
|
133074
|
+
}
|
|
133075
|
+
if (adSubcommandHasMediaFlag(args)) {
|
|
133076
|
+
return "\n\u274C `ad \u2026` \u5B50\u547D\u4EE4\u6CA1\u6709 `-m/--media`\uFF0C\u8D26\u6237\u7528 `-a/--account <mediaCustomerId>`\u3002\n \u5355\u6237\uFF1Asiluzan-tso ad campaigns -a <id> --start <\u65E5> --end <\u65E5> --json-out ./snap\n \u5168\u6237\u5F53\u65E5\u8D85\u9884\u7B97/\u7A7A\u8017\u7194\u65AD\uFF1Asiluzan-tso guard budget-circuit|zero-conv -m Google --json-out ./snap\n";
|
|
133077
|
+
}
|
|
132347
133078
|
if (cmd === "list" && (args.length === 1 || args[1]?.startsWith("-"))) {
|
|
132348
133079
|
return "\n\u274C \u6CA1\u6709\u9876\u5C42 `list` \u547D\u4EE4\u3002\u67E5\u8BE2\u5E7F\u544A\u8D26\u6237\u5217\u8868\u8BF7\u7528\uFF1A\n siluzan-tso list-accounts [-m Google] [-k <id\u6216\u5173\u952E\u5B57>] --json-out <dir>\n";
|
|
132349
133080
|
}
|
|
@@ -132415,12 +133146,12 @@ var REGISTRARS = [
|
|
|
132415
133146
|
register11,
|
|
132416
133147
|
register12,
|
|
132417
133148
|
register13,
|
|
133149
|
+
register14,
|
|
132418
133150
|
registerGoogleAnalysisCommands,
|
|
132419
133151
|
registerGoogleAnalysisBatchCommands,
|
|
132420
133152
|
registerFacebookAnalysisCommands,
|
|
132421
133153
|
registerBingAnalysisCommands,
|
|
132422
133154
|
registerTikTokAnalysisCommands,
|
|
132423
|
-
register14,
|
|
132424
133155
|
register15,
|
|
132425
133156
|
register16,
|
|
132426
133157
|
register17,
|
|
@@ -132432,6 +133163,7 @@ var REGISTRARS = [
|
|
|
132432
133163
|
register23,
|
|
132433
133164
|
register24,
|
|
132434
133165
|
register25,
|
|
133166
|
+
register26,
|
|
132435
133167
|
registerWebsiteDiagnosisCommands,
|
|
132436
133168
|
registerMarketAnalysisCommands,
|
|
132437
133169
|
registerGoogleAdsDiagnosisCommands
|