siluzan-tso-cli 1.1.23 → 1.1.24-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 +2 -1
- package/dist/index.js +357 -45
- package/dist/skill/AGENTS.md +3 -1
- package/dist/skill/SKILL.md +21 -4
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +12 -0
- package/dist/skill/references/accounts/finance.md +4 -4
- package/dist/skill/references/analytics/account-analytics.md +42 -6
- package/dist/skill/references/analytics/facebook-analysis-guide.md +111 -0
- package/dist/skill/references/analytics/google-analysis-batch.md +12 -0
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +3 -3
- package/dist/skill/references/core/agent-conventions.md +8 -0
- package/dist/skill/references/core/playbooks.md +30 -4
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/skill-authoring.md +6 -2
- package/dist/skill/references/core/subagent-orchestration.md +148 -0
- package/dist/skill/references/core/workflows.md +1 -1
- package/dist/skill/report-templates/README.md +2 -1
- package/dist/skill/report-templates/REPORT-WORKFLOW.md +2 -2
- package/dist/skill/report-templates/google-inquiry-analysis.md +10 -0
- package/dist/skill/report-templates/meta-account-diagnosis-report.md +73 -0
- package/dist/skill/report-templates/meta-period-report.md +98 -14
- package/dist/skill/report-templates/okki-weekly-google-client.md +13 -0
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/dist/skill/snippets/handoff-p5-batch.md +45 -0
- package/dist/skill/snippets/handoff-p6-okki.md +51 -0
- package/dist/skill/snippets/handoff-p7-inquiry.md +43 -0
- package/eval/cases/facebook-analysis-google-section-aliases.scenario.json +20 -0
- package/eval/cases/facebook-analysis-not-google-keywords.scenario.json +20 -0
- package/eval/cases/facebook-analysis-period-default.scenario.json +30 -0
- package/eval/cases/p4-fb-meta-period-report.scenario.json +21 -0
- package/eval/stub-fixtures/facebook-analysis.json +19 -0
- package/eval/stub-fixtures/meta-overview.json +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板引用以下 CDN:`cdn.tailwindcss.com`、`cdnjs.cloudflare.co
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli@beta
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,6 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
> **注意**:当前为测试版(1.1.24-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
54
55
|
|
|
55
56
|
| 助手 | 建议 `--ai` |
|
|
56
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -3328,7 +3328,7 @@ var DEFAULT_API_BASE;
|
|
|
3328
3328
|
var init_defaults = __esm({
|
|
3329
3329
|
"src/config/defaults.ts"() {
|
|
3330
3330
|
"use strict";
|
|
3331
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
3331
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
3332
3332
|
}
|
|
3333
3333
|
});
|
|
3334
3334
|
|
|
@@ -4753,8 +4753,9 @@ var init_google_analysis = __esm({
|
|
|
4753
4753
|
"// \u65E7\u5B57\u6BB5 `budgetAmount`\uFF08\u5206\uFF09/ `*Micros`\uFF08\u5FAE\u5143\uFF09\u5DF2\u4E0D\u518D\u843D\u76D8\uFF0C**\u7981\u6B62**\u518D\u505A \xF7100 / \xF71_000_000 \u6362\u7B97\u3002"
|
|
4754
4754
|
];
|
|
4755
4755
|
GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS = [
|
|
4756
|
-
"// \u7ADE\u4E89\u6307\u6807\uFF1A`campaigns[].competitiveMetrics` \u4E3A
|
|
4757
|
-
"// \u884C\u9876 `searchImpressionShare` / `searchBudgetLostImpressionShare` / `searchRankLostImpressionShare` \
|
|
4756
|
+
"// \u7ADE\u4E89\u6307\u6807\uFF1A`campaigns[].competitiveMetrics` \u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0999` = 9.99%\uFF09\uFF0C\u542B Top/AbsoluteTop/Content/ClickShare \u7B49\uFF1B\u65E0\u6570\u636E\u65F6\u4E3A `null`\u3002",
|
|
4757
|
+
"// \u884C\u9876 `searchImpressionShare` / `searchBudgetLostImpressionShare` / `searchRankLostImpressionShare` \u843D\u76D8\u524D\u5DF2\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u4E0E `competitiveMetrics` \u540C\u540D\u9879\u4E00\u81F4\uFF09\uFF1B\u5C55\u793A\u4E3A % \u65F6 \xD7100\u3002",
|
|
4758
|
+
"// `keywords[]` \u884C\u9876 3 \u9879\u4EFD\u989D\u540C\u6837\u4E3A 0~1 \u5C0F\u6570\uFF08\u65E0 `competitiveMetrics` \u65F6\u7531\u767E\u5206\u6570 \xF7100\uFF09\u3002"
|
|
4758
4759
|
];
|
|
4759
4760
|
RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
|
|
4760
4761
|
"overview",
|
|
@@ -5009,6 +5010,61 @@ var init_sections = __esm({
|
|
|
5009
5010
|
}
|
|
5010
5011
|
});
|
|
5011
5012
|
|
|
5013
|
+
// src/commands/google-analysis/normalize-impression-shares.ts
|
|
5014
|
+
function normalizeShareValue(value, competitiveMetrics, field) {
|
|
5015
|
+
const cmVal = competitiveMetrics?.[field];
|
|
5016
|
+
if (typeof cmVal === "number" && Number.isFinite(cmVal)) {
|
|
5017
|
+
return cmVal;
|
|
5018
|
+
}
|
|
5019
|
+
if (Math.abs(value) > 1) {
|
|
5020
|
+
return value / 100;
|
|
5021
|
+
}
|
|
5022
|
+
return value;
|
|
5023
|
+
}
|
|
5024
|
+
function normalizeLegacyShareOnRow(row) {
|
|
5025
|
+
const rawCm = row.competitiveMetrics;
|
|
5026
|
+
const competitiveMetrics = rawCm !== null && typeof rawCm === "object" && !Array.isArray(rawCm) ? rawCm : null;
|
|
5027
|
+
for (const field of LEGACY_ROW_IMPRESSION_SHARE_FIELDS) {
|
|
5028
|
+
const v = row[field];
|
|
5029
|
+
if (typeof v !== "number" || !Number.isFinite(v)) continue;
|
|
5030
|
+
row[field] = normalizeShareValue(v, competitiveMetrics, field);
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
function normalizeRowsInArray(rows) {
|
|
5034
|
+
if (!Array.isArray(rows)) return;
|
|
5035
|
+
for (const row of rows) {
|
|
5036
|
+
if (row !== null && typeof row === "object" && !Array.isArray(row)) {
|
|
5037
|
+
normalizeLegacyShareOnRow(row);
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
function normalizeImpressionShareScales(payload, section) {
|
|
5042
|
+
if (!SECTIONS_WITH_LEGACY_ROW_SHARES.has(section)) return payload;
|
|
5043
|
+
if (payload === null || typeof payload !== "object") return payload;
|
|
5044
|
+
const root = payload;
|
|
5045
|
+
if (section === "campaigns") {
|
|
5046
|
+
normalizeRowsInArray(root.campaigns);
|
|
5047
|
+
} else if (section === "keywords") {
|
|
5048
|
+
normalizeRowsInArray(root.keywords);
|
|
5049
|
+
}
|
|
5050
|
+
return payload;
|
|
5051
|
+
}
|
|
5052
|
+
var LEGACY_ROW_IMPRESSION_SHARE_FIELDS, SECTIONS_WITH_LEGACY_ROW_SHARES;
|
|
5053
|
+
var init_normalize_impression_shares = __esm({
|
|
5054
|
+
"src/commands/google-analysis/normalize-impression-shares.ts"() {
|
|
5055
|
+
"use strict";
|
|
5056
|
+
LEGACY_ROW_IMPRESSION_SHARE_FIELDS = [
|
|
5057
|
+
"searchImpressionShare",
|
|
5058
|
+
"searchBudgetLostImpressionShare",
|
|
5059
|
+
"searchRankLostImpressionShare"
|
|
5060
|
+
];
|
|
5061
|
+
SECTIONS_WITH_LEGACY_ROW_SHARES = /* @__PURE__ */ new Set([
|
|
5062
|
+
"campaigns",
|
|
5063
|
+
"keywords"
|
|
5064
|
+
]);
|
|
5065
|
+
}
|
|
5066
|
+
});
|
|
5067
|
+
|
|
5012
5068
|
// src/commands/google-analysis/normalize-rates.ts
|
|
5013
5069
|
function divIfFiniteNumber(v) {
|
|
5014
5070
|
return typeof v === "number" && Number.isFinite(v) ? v / 100 : v;
|
|
@@ -100824,6 +100880,7 @@ async function fetchSectionPayload(def, opts, config, id) {
|
|
|
100824
100880
|
);
|
|
100825
100881
|
let payload = stripLegacyGoogleFieldsIfV2Present(data);
|
|
100826
100882
|
payload = normalizeRateScales(payload, def.name);
|
|
100883
|
+
payload = normalizeImpressionShareScales(payload, def.name);
|
|
100827
100884
|
payload = normalizeMoneyScales(payload, def.name);
|
|
100828
100885
|
if (def.name === "overview") {
|
|
100829
100886
|
payload = normalizeOverviewPayload(payload);
|
|
@@ -100871,6 +100928,7 @@ var init_fetch = __esm({
|
|
|
100871
100928
|
init_auth();
|
|
100872
100929
|
init_strip_legacy_google_fields();
|
|
100873
100930
|
init_sections();
|
|
100931
|
+
init_normalize_impression_shares();
|
|
100874
100932
|
init_normalize_rates();
|
|
100875
100933
|
init_normalize_money();
|
|
100876
100934
|
init_normalize_overview();
|
|
@@ -100905,14 +100963,14 @@ function computeBackoffMs(attempt, policy) {
|
|
|
100905
100963
|
return capped + jitter;
|
|
100906
100964
|
}
|
|
100907
100965
|
function sleep3(ms, signal) {
|
|
100908
|
-
return new Promise((
|
|
100966
|
+
return new Promise((resolve14, reject) => {
|
|
100909
100967
|
if (signal?.aborted) {
|
|
100910
100968
|
reject(new Error("retry sleep aborted"));
|
|
100911
100969
|
return;
|
|
100912
100970
|
}
|
|
100913
100971
|
const timer = setTimeout(() => {
|
|
100914
100972
|
signal?.removeEventListener("abort", onAbort);
|
|
100915
|
-
|
|
100973
|
+
resolve14();
|
|
100916
100974
|
}, ms);
|
|
100917
100975
|
const onAbort = () => {
|
|
100918
100976
|
clearTimeout(timer);
|
|
@@ -102514,6 +102572,7 @@ var init_google_analysis2 = __esm({
|
|
|
102514
102572
|
init_sections();
|
|
102515
102573
|
init_fetch();
|
|
102516
102574
|
init_normalize_rates();
|
|
102575
|
+
init_normalize_impression_shares();
|
|
102517
102576
|
init_translate_fields();
|
|
102518
102577
|
init_register_cli();
|
|
102519
102578
|
}
|
|
@@ -102531,7 +102590,7 @@ var init_google_analysis3 = __esm({
|
|
|
102531
102590
|
init_dist();
|
|
102532
102591
|
init_dist();
|
|
102533
102592
|
import * as fs14 from "fs";
|
|
102534
|
-
import * as
|
|
102593
|
+
import * as path22 from "path";
|
|
102535
102594
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
102536
102595
|
import { Command } from "commander";
|
|
102537
102596
|
|
|
@@ -103016,10 +103075,10 @@ function deriveWebUrl(apiBaseUrl) {
|
|
|
103016
103075
|
}
|
|
103017
103076
|
var TSO_UMI_ROUTE_PREFIX = "/v3umijs/tso";
|
|
103018
103077
|
function buildTsoPageWebUrl(webUrl, tsoSubRoute) {
|
|
103019
|
-
const
|
|
103020
|
-
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${
|
|
103078
|
+
const path23 = tsoSubRoute.replace(/^\/+/, "");
|
|
103079
|
+
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${path23}`;
|
|
103021
103080
|
const q = new URLSearchParams({ tso: umiPath });
|
|
103022
|
-
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${
|
|
103081
|
+
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${path23}?${q.toString()}`;
|
|
103023
103082
|
}
|
|
103024
103083
|
function cmdConfigShow() {
|
|
103025
103084
|
const shared = readSharedConfig();
|
|
@@ -110193,7 +110252,7 @@ function cloneKeywordBlockShell(block) {
|
|
|
110193
110252
|
delete shell["matchTypeV2"];
|
|
110194
110253
|
return shell;
|
|
110195
110254
|
}
|
|
110196
|
-
function splitKeywordsForBatchJobBlockIfMixed(block,
|
|
110255
|
+
function splitKeywordsForBatchJobBlockIfMixed(block, path23, warnings) {
|
|
110197
110256
|
const declaredUi = matchTypeV2ToUi(readBlockMatchTypeRaw(block));
|
|
110198
110257
|
const entries = collectKeywordEntriesFromBlock(block);
|
|
110199
110258
|
if (entries.length === 0) return [block];
|
|
@@ -110212,7 +110271,7 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path22, warnings) {
|
|
|
110212
110271
|
(ui) => matchTypeUiToV2(ui)
|
|
110213
110272
|
);
|
|
110214
110273
|
warnings.push(
|
|
110215
|
-
`${
|
|
110274
|
+
`${path23} \u542B\u591A\u79CD\u5339\u914D\u7C7B\u578B\uFF0C\u5DF2\u81EA\u52A8\u62C6\u5206\u4E3A ${groups.size} \u4E2A KeywordsForBatchJob \u5757\uFF08${labels.join("\u3001")}\uFF09`
|
|
110216
110275
|
);
|
|
110217
110276
|
const shell = cloneKeywordBlockShell(block);
|
|
110218
110277
|
const splitBlocks = [];
|
|
@@ -110232,16 +110291,16 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path22, warnings) {
|
|
|
110232
110291
|
}
|
|
110233
110292
|
return splitBlocks;
|
|
110234
110293
|
}
|
|
110235
|
-
function validateKeywordCore(core,
|
|
110294
|
+
function validateKeywordCore(core, path23, errors, lengthViolations) {
|
|
110236
110295
|
const trimmed = core.trim();
|
|
110237
110296
|
if (!trimmed) {
|
|
110238
|
-
errors.push(`${
|
|
110297
|
+
errors.push(`${path23} \u5173\u952E\u8BCD\u8BCD\u5E72\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
110239
110298
|
return false;
|
|
110240
110299
|
}
|
|
110241
110300
|
if (trimmed.length > GOOGLE_KEYWORD_MAX_CORE_LENGTH) {
|
|
110242
110301
|
if (lengthViolations) {
|
|
110243
110302
|
pushLengthViolation(lengthViolations, {
|
|
110244
|
-
path:
|
|
110303
|
+
path: path23,
|
|
110245
110304
|
field: "KeywordText",
|
|
110246
110305
|
kind: "keyword_core",
|
|
110247
110306
|
limit: GOOGLE_KEYWORD_MAX_CORE_LENGTH,
|
|
@@ -110251,13 +110310,13 @@ function validateKeywordCore(core, path22, errors, lengthViolations) {
|
|
|
110251
110310
|
});
|
|
110252
110311
|
}
|
|
110253
110312
|
errors.push(
|
|
110254
|
-
`${
|
|
110313
|
+
`${path23} \u5173\u952E\u8BCD\u8BCD\u5E72\u8D85\u8FC7 ${GOOGLE_KEYWORD_MAX_CORE_LENGTH} \u5B57\u7B26\uFF08\u5F53\u524D ${trimmed.length}\uFF09\uFF1A"${trimmed}"`
|
|
110255
110314
|
);
|
|
110256
110315
|
return false;
|
|
110257
110316
|
}
|
|
110258
110317
|
if (!VALID_CORE_REGEX.test(trimmed)) {
|
|
110259
110318
|
errors.push(
|
|
110260
|
-
`${
|
|
110319
|
+
`${path23} \u542B Google \u4E0D\u5141\u8BB8\u7684\u5B57\u7B26\uFF08\u8BCD\u5E72\u4EC5\u5141\u8BB8\u5B57\u6BCD/\u6570\u5B57/\u7A7A\u683C/\u8FDE\u5B57\u7B26/\u53E5\u70B9\uFF09\uFF1A"${trimmed.slice(0, 40)}${trimmed.length > 40 ? "\u2026" : ""}"`
|
|
110261
110320
|
);
|
|
110262
110321
|
return false;
|
|
110263
110322
|
}
|
|
@@ -110314,24 +110373,24 @@ function canonicalizeKeywordBatchBlock(block, resolvedMatchV2, normalizedTexts,
|
|
|
110314
110373
|
}
|
|
110315
110374
|
}
|
|
110316
110375
|
}
|
|
110317
|
-
function pushKeywordAutoFixWarning(warnings,
|
|
110376
|
+
function pushKeywordAutoFixWarning(warnings, path23, fieldLabel, trimmedRaw, formatted, declaredUi, beforeUi, matchType, inferredMatchType) {
|
|
110318
110377
|
if (inferredMatchType) {
|
|
110319
110378
|
warnings.push(
|
|
110320
|
-
`${
|
|
110379
|
+
`${path23}.${fieldLabel} \u672A\u6307\u5B9A MatchTypeV2\uFF0C\u5DF2\u6309\u8BCD\u9762\u63A8\u65AD\u4E3A ${matchTypeUiToV2(matchType)}`
|
|
110321
110380
|
);
|
|
110322
110381
|
return;
|
|
110323
110382
|
}
|
|
110324
110383
|
if (declaredUi && beforeUi !== declaredUi) {
|
|
110325
110384
|
warnings.push(
|
|
110326
|
-
`${
|
|
110385
|
+
`${path23}.${fieldLabel} MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u4E0E\u8BCD\u9762\u4E0D\u4E00\u81F4\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`
|
|
110327
110386
|
);
|
|
110328
110387
|
return;
|
|
110329
110388
|
}
|
|
110330
110389
|
if (formatted !== trimmedRaw) {
|
|
110331
|
-
warnings.push(`${
|
|
110390
|
+
warnings.push(`${path23}.${fieldLabel} \u5DF2\u81EA\u52A8\u4FEE\u590D\u8BCD\u9762\uFF1A${trimmedRaw} \u2192 ${formatted}`);
|
|
110332
110391
|
}
|
|
110333
110392
|
}
|
|
110334
|
-
function normalizeKeywordTextList(texts, matchTypeRaw,
|
|
110393
|
+
function normalizeKeywordTextList(texts, matchTypeRaw, path23, fieldLabel, errors, warnings, lengthViolations) {
|
|
110335
110394
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110336
110395
|
const normalized = [];
|
|
110337
110396
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -110339,7 +110398,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path22, fieldLabel, error
|
|
|
110339
110398
|
for (let k = 0; k < texts.length; k++) {
|
|
110340
110399
|
const raw = texts[k];
|
|
110341
110400
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
110342
|
-
errors.push(`${
|
|
110401
|
+
errors.push(`${path23}.${fieldLabel}[${k}] \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110343
110402
|
continue;
|
|
110344
110403
|
}
|
|
110345
110404
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110347,7 +110406,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path22, fieldLabel, error
|
|
|
110347
110406
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110348
110407
|
pushKeywordAutoFixWarning(
|
|
110349
110408
|
warnings,
|
|
110350
|
-
|
|
110409
|
+
path23,
|
|
110351
110410
|
fieldLabel,
|
|
110352
110411
|
trimmedRaw,
|
|
110353
110412
|
formatted,
|
|
@@ -110357,10 +110416,10 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path22, fieldLabel, error
|
|
|
110357
110416
|
inferredMatchType
|
|
110358
110417
|
);
|
|
110359
110418
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110360
|
-
if (!validateKeywordCore(core, `${
|
|
110419
|
+
if (!validateKeywordCore(core, `${path23}.${fieldLabel}[${k}]`, errors, lengthViolations)) continue;
|
|
110361
110420
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110362
110421
|
if (seen.has(dedupeKey)) {
|
|
110363
|
-
warnings.push(`${
|
|
110422
|
+
warnings.push(`${path23}.${fieldLabel}[${k}] \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110364
110423
|
continue;
|
|
110365
110424
|
}
|
|
110366
110425
|
seen.add(dedupeKey);
|
|
@@ -110369,12 +110428,12 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path22, fieldLabel, error
|
|
|
110369
110428
|
}
|
|
110370
110429
|
return { normalized, resolvedUi };
|
|
110371
110430
|
}
|
|
110372
|
-
function normalizeKeywordsForBatchJobBlock(block,
|
|
110431
|
+
function normalizeKeywordsForBatchJobBlock(block, path23, errors, warnings, lengthViolations) {
|
|
110373
110432
|
const matchTypeRaw = readBlockMatchTypeRaw(block);
|
|
110374
110433
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110375
110434
|
if (matchTypeRaw !== void 0 && declaredUi === null) {
|
|
110376
110435
|
errors.push(
|
|
110377
|
-
`${
|
|
110436
|
+
`${path23}.MatchTypeV2 \u65E0\u6548\uFF08${String(matchTypeRaw)}\uFF09\uFF0C\u5408\u6CD5\u503C\uFF1ABROAD | PHRASE | EXACT`
|
|
110378
110437
|
);
|
|
110379
110438
|
return;
|
|
110380
110439
|
}
|
|
@@ -110389,7 +110448,7 @@ function normalizeKeywordsForBatchJobBlock(block, path22, errors, warnings, leng
|
|
|
110389
110448
|
const result = normalizeKeywordTextList(
|
|
110390
110449
|
texts,
|
|
110391
110450
|
matchTypeRaw,
|
|
110392
|
-
|
|
110451
|
+
path23,
|
|
110393
110452
|
"KeywordText",
|
|
110394
110453
|
errors,
|
|
110395
110454
|
warnings,
|
|
@@ -110398,7 +110457,7 @@ function normalizeKeywordsForBatchJobBlock(block, path22, errors, warnings, leng
|
|
|
110398
110457
|
normalizedTexts = result.normalized;
|
|
110399
110458
|
if (result.resolvedUi) resolvedUi = result.resolvedUi;
|
|
110400
110459
|
if (normalizedTexts.length === 0 && texts.length > 0) {
|
|
110401
|
-
errors.push(`${
|
|
110460
|
+
errors.push(`${path23}.KeywordText \u7ECF\u6821\u9A8C\u540E\u65E0\u6709\u6548\u5173\u952E\u8BCD\uFF0C\u8BF7\u4FEE\u6B63\u8BCD\u9762\u6216 MatchTypeV2`);
|
|
110402
110461
|
}
|
|
110403
110462
|
}
|
|
110404
110463
|
if (hasItems && items) {
|
|
@@ -110406,12 +110465,12 @@ function normalizeKeywordsForBatchJobBlock(block, path22, errors, warnings, leng
|
|
|
110406
110465
|
for (let k = 0; k < items.length; k++) {
|
|
110407
110466
|
const item = items[k];
|
|
110408
110467
|
if (!item || typeof item !== "object") {
|
|
110409
|
-
errors.push(`${
|
|
110468
|
+
errors.push(`${path23}.Items[${k}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
110410
110469
|
continue;
|
|
110411
110470
|
}
|
|
110412
110471
|
const raw = readItemText(item);
|
|
110413
110472
|
if (raw === null || !raw.trim()) {
|
|
110414
|
-
errors.push(`${
|
|
110473
|
+
errors.push(`${path23}.Items[${k}].Text \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110415
110474
|
continue;
|
|
110416
110475
|
}
|
|
110417
110476
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110419,7 +110478,7 @@ function normalizeKeywordsForBatchJobBlock(block, path22, errors, warnings, leng
|
|
|
110419
110478
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110420
110479
|
pushKeywordAutoFixWarning(
|
|
110421
110480
|
warnings,
|
|
110422
|
-
|
|
110481
|
+
path23,
|
|
110423
110482
|
`Items[${k}].Text`,
|
|
110424
110483
|
trimmedRaw,
|
|
110425
110484
|
formatted,
|
|
@@ -110429,10 +110488,10 @@ function normalizeKeywordsForBatchJobBlock(block, path22, errors, warnings, leng
|
|
|
110429
110488
|
inferredMatchType
|
|
110430
110489
|
);
|
|
110431
110490
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110432
|
-
if (!validateKeywordCore(core, `${
|
|
110491
|
+
if (!validateKeywordCore(core, `${path23}.Items[${k}].Text`, errors, lengthViolations)) continue;
|
|
110433
110492
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110434
110493
|
if (seen.has(dedupeKey)) {
|
|
110435
|
-
warnings.push(`${
|
|
110494
|
+
warnings.push(`${path23}.Items[${k}].Text \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110436
110495
|
continue;
|
|
110437
110496
|
}
|
|
110438
110497
|
seen.add(dedupeKey);
|
|
@@ -113031,12 +113090,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113031
113090
|
for (let ki = 0; ki < texts.length; ki++) {
|
|
113032
113091
|
const t = texts[ki];
|
|
113033
113092
|
if (typeof t !== "string" || !t.trim()) continue;
|
|
113034
|
-
const
|
|
113093
|
+
const path23 = `${groupPath}.KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
113035
113094
|
const key = keywordKey(t, matchTypeV2);
|
|
113036
113095
|
if (!liveKwKeys.has(key)) {
|
|
113037
113096
|
missing.push({
|
|
113038
113097
|
layer: "keyword",
|
|
113039
|
-
path:
|
|
113098
|
+
path: path23,
|
|
113040
113099
|
adGroupName: groupName,
|
|
113041
113100
|
plannedContent: `\u8BCD\u9762: ${t} | \u5339\u914D: ${matchTypeV2}`,
|
|
113042
113101
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveKwInGroup.length} \u6761\u5173\u952E\u8BCD\uFF0C\u65E0\u952E ${key}`,
|
|
@@ -113054,12 +113113,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113054
113113
|
for (let ai = 0; ai < ads.length; ai++) {
|
|
113055
113114
|
const ad = asRecord(ads[ai]);
|
|
113056
113115
|
if (!ad) continue;
|
|
113057
|
-
const
|
|
113116
|
+
const path23 = `${groupPath}.AdsForBatchJob[${ai}]`;
|
|
113058
113117
|
const primary = pickString(ad["headlinePart1"], ad["AdTitle"]);
|
|
113059
113118
|
if (!primary) {
|
|
113060
113119
|
missing.push({
|
|
113061
113120
|
layer: "ad",
|
|
113062
|
-
path:
|
|
113121
|
+
path: path23,
|
|
113063
113122
|
adGroupName: groupName,
|
|
113064
113123
|
plannedContent: `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF0C\u65E0\u6CD5\u6BD4\u5BF9\uFF09`,
|
|
113065
113124
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761\u521B\u610F`,
|
|
@@ -113072,7 +113131,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113072
113131
|
if (!found) {
|
|
113073
113132
|
missing.push({
|
|
113074
113133
|
layer: "ad",
|
|
113075
|
-
path:
|
|
113134
|
+
path: path23,
|
|
113076
113135
|
adGroupName: groupName,
|
|
113077
113136
|
plannedContent: `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}`,
|
|
113078
113137
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761 RSA\uFF0C\u65E0\u6B64\u9996\u6807\u9898`,
|
|
@@ -114212,13 +114271,13 @@ function pmaxChannelTypesUrl(googleApiUrl) {
|
|
|
114212
114271
|
}
|
|
114213
114272
|
function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
|
|
114214
114273
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114215
|
-
const
|
|
114216
|
-
return campaignId ? `${
|
|
114274
|
+
const path23 = `${base}/accounts/${accountId}/campaign/pmax`;
|
|
114275
|
+
return campaignId ? `${path23}/${campaignId}` : path23;
|
|
114217
114276
|
}
|
|
114218
114277
|
function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
|
|
114219
114278
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114220
|
-
const
|
|
114221
|
-
return suffix ? `${
|
|
114279
|
+
const path23 = `${base}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
|
|
114280
|
+
return suffix ? `${path23}/${suffix.replace(/^\//, "")}` : path23;
|
|
114222
114281
|
}
|
|
114223
114282
|
function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
|
|
114224
114283
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
@@ -120900,13 +120959,265 @@ function register25(program2) {
|
|
|
120900
120959
|
// src/index.ts
|
|
120901
120960
|
init_google_analysis3();
|
|
120902
120961
|
init_google_analysis_batch();
|
|
120962
|
+
|
|
120963
|
+
// src/commands/facebook-analysis/sections.ts
|
|
120964
|
+
var FACEBOOK_SECTIONS = [
|
|
120965
|
+
{
|
|
120966
|
+
name: "overview",
|
|
120967
|
+
description: "\u603B\u89C8 OverviewSectionData\uFF08\u542B currentPeriod / previousPeriod \u73AF\u6BD4\uFF09",
|
|
120968
|
+
segment: "OverviewSectionData"
|
|
120969
|
+
},
|
|
120970
|
+
{
|
|
120971
|
+
name: "ad-sets",
|
|
120972
|
+
description: "\u5E7F\u544A\u7EC4 AdSetSectionData\uFF08Meta Ad Set\uFF0C\u5B57\u6BB5 adGroups\uFF09",
|
|
120973
|
+
segment: "AdSetSectionData"
|
|
120974
|
+
},
|
|
120975
|
+
{
|
|
120976
|
+
name: "platform",
|
|
120977
|
+
description: "\u6295\u653E\u5E73\u53F0 PlatformSectionData\uFF08facebook / instagram \u7B49\uFF09",
|
|
120978
|
+
segment: "PlatformSectionData"
|
|
120979
|
+
},
|
|
120980
|
+
{
|
|
120981
|
+
name: "country",
|
|
120982
|
+
description: "\u56FD\u5BB6 CountrySectionData\uFF08\u53EF\u6309 spend \u964D\u5E8F limit\uFF09",
|
|
120983
|
+
segment: "CountrySectionData",
|
|
120984
|
+
countryLimitOption: true
|
|
120985
|
+
},
|
|
120986
|
+
{
|
|
120987
|
+
name: "audience",
|
|
120988
|
+
description: "\u53D7\u4F17 AudienceSectionData\uFF08\u5E74\u9F84 \xD7 \u6027\u522B\uFF09",
|
|
120989
|
+
segment: "AudienceSectionData"
|
|
120990
|
+
},
|
|
120991
|
+
{
|
|
120992
|
+
name: "creative",
|
|
120993
|
+
description: "\u521B\u610F CreativeSectionData\uFF08\u9ED8\u8BA4\u521B\u610F\u62A5\u544A\uFF0C\u6240\u6709\u8D26\u6237\u53EF\u7528\uFF09",
|
|
120994
|
+
segment: "CreativeSectionData"
|
|
120995
|
+
},
|
|
120996
|
+
{
|
|
120997
|
+
name: "material",
|
|
120998
|
+
description: "\u7D20\u6750 MaterialSectionData\uFF08\u4EC5 Dynamic Creative\uFF1B\u6807\u51C6\u8D26\u6237\u5E38\u4E3A\u7A7A\uFF09",
|
|
120999
|
+
segment: "MaterialSectionData"
|
|
121000
|
+
}
|
|
121001
|
+
];
|
|
121002
|
+
var FACEBOOK_SECTION_NAMES = FACEBOOK_SECTIONS.map((s) => s.name);
|
|
121003
|
+
var FACEBOOK_SECTION_ALIASES = {
|
|
121004
|
+
campaigns: "ad-sets",
|
|
121005
|
+
"ad-groups": "ad-sets",
|
|
121006
|
+
geographic: "country",
|
|
121007
|
+
geo: "country",
|
|
121008
|
+
devices: "platform",
|
|
121009
|
+
network: "platform",
|
|
121010
|
+
networks: "platform",
|
|
121011
|
+
ads: "creative",
|
|
121012
|
+
materials: "material",
|
|
121013
|
+
"asset-images": "material",
|
|
121014
|
+
videos: "material"
|
|
121015
|
+
};
|
|
121016
|
+
|
|
121017
|
+
// src/commands/facebook-analysis/fetch.ts
|
|
121018
|
+
init_auth();
|
|
121019
|
+
function normalizeFacebookAccountId(raw) {
|
|
121020
|
+
const t = raw.trim();
|
|
121021
|
+
if (!t) {
|
|
121022
|
+
console.error("\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\u3002\n");
|
|
121023
|
+
process.exit(1);
|
|
121024
|
+
}
|
|
121025
|
+
const digits = t.startsWith("act_") ? t.slice(4) : t;
|
|
121026
|
+
if (!/^\d+$/.test(digits)) {
|
|
121027
|
+
console.error(
|
|
121028
|
+
"\n\u274C --account \u987B\u4E3A Facebook \u5E7F\u544A\u8D26\u6237 ID\uFF08\u6570\u5B57 mediaCustomerId\uFF0C\u6216 act_<\u6570\u5B57>\uFF0C\u4E0E list-accounts -m MetaAd \u4E00\u81F4\uFF09\u3002\n"
|
|
121029
|
+
);
|
|
121030
|
+
process.exit(1);
|
|
121031
|
+
}
|
|
121032
|
+
return { apiId: `act_${digits}`, manifestId: digits };
|
|
121033
|
+
}
|
|
121034
|
+
function resolveFacebookDateRange(start, end) {
|
|
121035
|
+
if (start && end) return { startDate: start, endDate: end };
|
|
121036
|
+
if (!start && !end) {
|
|
121037
|
+
const endD = /* @__PURE__ */ new Date();
|
|
121038
|
+
endD.setDate(endD.getDate() - 1);
|
|
121039
|
+
const startD = new Date(endD);
|
|
121040
|
+
startD.setDate(startD.getDate() - 6);
|
|
121041
|
+
const fmt2 = (d) => d.toISOString().slice(0, 10);
|
|
121042
|
+
return { startDate: fmt2(startD), endDate: fmt2(endD) };
|
|
121043
|
+
}
|
|
121044
|
+
console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
|
|
121045
|
+
process.exit(1);
|
|
121046
|
+
}
|
|
121047
|
+
function facebookReportingUrl(config, apiId, segment, query) {
|
|
121048
|
+
const q = query ? query.startsWith("?") ? query : `?${query}` : "";
|
|
121049
|
+
return `${config.apiBaseUrl}/reporting/media-account/FacebookAds/${encodeURIComponent(apiId)}/${segment}${q}`;
|
|
121050
|
+
}
|
|
121051
|
+
async function fetchFacebookSectionPayload(def, opts, config, apiId) {
|
|
121052
|
+
const { startDate, endDate } = resolveFacebookDateRange(opts.start, opts.end);
|
|
121053
|
+
const params = new URLSearchParams({ startDate, endDate });
|
|
121054
|
+
if (def.countryLimitOption && opts.limit !== void 0 && Number.isFinite(opts.limit)) {
|
|
121055
|
+
params.set("limit", String(Math.max(1, Math.floor(opts.limit))));
|
|
121056
|
+
}
|
|
121057
|
+
const url = facebookReportingUrl(config, apiId, def.segment, params.toString());
|
|
121058
|
+
return apiFetch2(url, config, {}, opts.verbose ?? false);
|
|
121059
|
+
}
|
|
121060
|
+
function endpointHintForFacebookSection(def, apiId) {
|
|
121061
|
+
return `GET \u2026/FacebookAds/${apiId}/${def.segment}`;
|
|
121062
|
+
}
|
|
121063
|
+
|
|
121064
|
+
// src/commands/facebook-analysis/run-batch.ts
|
|
121065
|
+
init_auth();
|
|
121066
|
+
import * as path21 from "path";
|
|
121067
|
+
import { performance as performance5 } from "perf_hooks";
|
|
121068
|
+
init_version();
|
|
121069
|
+
|
|
121070
|
+
// src/commands/facebook-analysis/resolve-sections.ts
|
|
121071
|
+
function normalizeSectionToken(raw) {
|
|
121072
|
+
const t = raw.trim();
|
|
121073
|
+
if (!t) return null;
|
|
121074
|
+
if (FACEBOOK_SECTION_NAMES.includes(t)) {
|
|
121075
|
+
return t;
|
|
121076
|
+
}
|
|
121077
|
+
return FACEBOOK_SECTION_ALIASES[t] ?? null;
|
|
121078
|
+
}
|
|
121079
|
+
function resolveSectionList2(sections, exclude) {
|
|
121080
|
+
const splitClean = (s) => (s ?? "").split(",").map((x) => x.trim()).filter(Boolean);
|
|
121081
|
+
const include = splitClean(sections);
|
|
121082
|
+
const dropRaw = splitClean(exclude);
|
|
121083
|
+
const unknown = [...include, ...dropRaw].filter((n) => normalizeSectionToken(n) === null);
|
|
121084
|
+
if (unknown.length > 0) {
|
|
121085
|
+
console.error(
|
|
121086
|
+
`
|
|
121087
|
+
\u274C \u672A\u77E5\u7684 section \u540D\u79F0\uFF1A${unknown.join(", ")}
|
|
121088
|
+
\u53EF\u9009\uFF1A${FACEBOOK_SECTION_NAMES.join(", ")}
|
|
121089
|
+
Google \u522B\u540D\uFF1A${Object.keys(FACEBOOK_SECTION_ALIASES).join(", ")}
|
|
121090
|
+
`
|
|
121091
|
+
);
|
|
121092
|
+
process.exit(1);
|
|
121093
|
+
}
|
|
121094
|
+
const includeCanonical = new Set(
|
|
121095
|
+
include.map((n) => normalizeSectionToken(n)).filter(Boolean)
|
|
121096
|
+
);
|
|
121097
|
+
const dropCanonical = new Set(
|
|
121098
|
+
dropRaw.map((n) => normalizeSectionToken(n)).filter(Boolean)
|
|
121099
|
+
);
|
|
121100
|
+
const base = include.length > 0 ? FACEBOOK_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...FACEBOOK_SECTIONS];
|
|
121101
|
+
return base.filter((s) => !dropCanonical.has(s.name));
|
|
121102
|
+
}
|
|
121103
|
+
|
|
121104
|
+
// src/commands/facebook-analysis/run-batch.ts
|
|
121105
|
+
async function runWithConcurrency2(tasks, concurrency) {
|
|
121106
|
+
const results = new Array(tasks.length);
|
|
121107
|
+
let cursor = 0;
|
|
121108
|
+
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
121109
|
+
while (true) {
|
|
121110
|
+
const i = cursor++;
|
|
121111
|
+
if (i >= tasks.length) return;
|
|
121112
|
+
results[i] = await tasks[i]();
|
|
121113
|
+
}
|
|
121114
|
+
});
|
|
121115
|
+
await Promise.all(workers);
|
|
121116
|
+
return results;
|
|
121117
|
+
}
|
|
121118
|
+
async function runAllFacebookSections(opts) {
|
|
121119
|
+
const { apiId, manifestId } = normalizeFacebookAccountId(opts.account);
|
|
121120
|
+
const config = loadConfig(opts.token);
|
|
121121
|
+
if (!opts.jsonOut?.trim()) {
|
|
121122
|
+
console.error("\n\u274C \u5FC5\u987B\u4F20 --json-out <\u76EE\u5F55>\uFF08\u5404\u7EF4\u5EA6\u843D\u76D8\u540E\u7531 report-manifest \u7D22\u5F15\uFF09\u3002\n");
|
|
121123
|
+
process.exit(1);
|
|
121124
|
+
}
|
|
121125
|
+
const targets = resolveSectionList2(opts.sections, opts.exclude);
|
|
121126
|
+
if (targets.length === 0) {
|
|
121127
|
+
console.error("\n\u274C \u6CA1\u6709\u8981\u6267\u884C\u7684 section\uFF08\u8BF7\u68C0\u67E5 --sections / --exclude\uFF09\u3002\n");
|
|
121128
|
+
process.exit(1);
|
|
121129
|
+
}
|
|
121130
|
+
const { startDate, endDate } = resolveFacebookDateRange(opts.start, opts.end);
|
|
121131
|
+
const concurrency = Math.max(
|
|
121132
|
+
1,
|
|
121133
|
+
Math.min(typeof opts.concurrency === "number" ? opts.concurrency : 5, 16)
|
|
121134
|
+
);
|
|
121135
|
+
const cliVersion = getCurrentVersion2();
|
|
121136
|
+
const overallT0 = performance5.now();
|
|
121137
|
+
const tasks = targets.map((def) => async () => {
|
|
121138
|
+
const t0 = performance5.now();
|
|
121139
|
+
const hint = endpointHintForFacebookSection(def, apiId);
|
|
121140
|
+
try {
|
|
121141
|
+
const payload = await fetchFacebookSectionPayload(def, opts, config, apiId);
|
|
121142
|
+
const summary2 = await writeReportAnalysisSnapshot({
|
|
121143
|
+
snapshotDir: opts.jsonOut,
|
|
121144
|
+
section: def.name,
|
|
121145
|
+
accountId: manifestId,
|
|
121146
|
+
dateRange: { start: startDate, end: endDate },
|
|
121147
|
+
payload,
|
|
121148
|
+
cliVersion
|
|
121149
|
+
});
|
|
121150
|
+
return {
|
|
121151
|
+
section: def.name,
|
|
121152
|
+
ok: true,
|
|
121153
|
+
elapsedMs: performance5.now() - t0,
|
|
121154
|
+
file: summary2.writtenFiles[0],
|
|
121155
|
+
endpointHint: hint
|
|
121156
|
+
};
|
|
121157
|
+
} catch (err) {
|
|
121158
|
+
return {
|
|
121159
|
+
section: def.name,
|
|
121160
|
+
ok: false,
|
|
121161
|
+
elapsedMs: performance5.now() - t0,
|
|
121162
|
+
error: err instanceof Error ? err.message : String(err),
|
|
121163
|
+
endpointHint: hint
|
|
121164
|
+
};
|
|
121165
|
+
}
|
|
121166
|
+
});
|
|
121167
|
+
const results = await runWithConcurrency2(tasks, concurrency);
|
|
121168
|
+
const succeeded = results.filter((r) => r.ok).length;
|
|
121169
|
+
const failed = results.length - succeeded;
|
|
121170
|
+
const absoluteSnapshotDir = path21.resolve(opts.jsonOut);
|
|
121171
|
+
const summary = {
|
|
121172
|
+
kind: "siluzan-tso-facebook-analysis-snapshot-batch",
|
|
121173
|
+
absoluteSnapshotDir,
|
|
121174
|
+
manifestFile: reportManifestFile(manifestId),
|
|
121175
|
+
accountId: manifestId,
|
|
121176
|
+
totalSections: results.length,
|
|
121177
|
+
succeeded,
|
|
121178
|
+
failed,
|
|
121179
|
+
concurrency,
|
|
121180
|
+
elapsedMs: performance5.now() - overallT0,
|
|
121181
|
+
results
|
|
121182
|
+
};
|
|
121183
|
+
console.log(JSON.stringify(summary));
|
|
121184
|
+
if (failed > 0) process.exit(2);
|
|
121185
|
+
}
|
|
121186
|
+
|
|
121187
|
+
// src/commands/facebook-analysis/register-cli.ts
|
|
121188
|
+
function registerFacebookAnalysisCommands(program2) {
|
|
121189
|
+
const sectionHelp = FACEBOOK_SECTION_NAMES.join(", ");
|
|
121190
|
+
program2.command("facebook-analysis").description(
|
|
121191
|
+
"Facebook Ads \u8D26\u6237\u5206\u6790\u6279\u91CF\u62C9\u53D6\uFF08TSO reporting/media-account/FacebookAds/\u2026\uFF0C7 \u4E2A Section\uFF09"
|
|
121192
|
+
).requiredOption(
|
|
121193
|
+
"-a, --account <id>",
|
|
121194
|
+
"Facebook \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6570\u5B57\u6216 act_<\u6570\u5B57>\uFF09"
|
|
121195
|
+
).requiredOption(
|
|
121196
|
+
"--json-out <dir>",
|
|
121197
|
+
"\u7ED3\u679C\u843D\u76D8\u76EE\u5F55\uFF1B\u6BCF\u7EF4\u5EA6 `<section>-<accountId>.json` + `report-manifest-<accountId>.json`"
|
|
121198
|
+
).option("-t, --token <token>", "Auth Token").option(
|
|
121199
|
+
"--start <date>",
|
|
121200
|
+
"\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF1B\u7701\u7565=\u8FD1 7 \u5929\u622A\u81F3\u6628\u5929\uFF09"
|
|
121201
|
+
).option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
|
|
121202
|
+
"--sections <list>",
|
|
121203
|
+
`\u4EC5\u6267\u884C\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u5982 overview,ad-sets,platform\uFF1B\u7701\u7565=\u5168\u90E8 7 \u4E2A\u3002\u53EF\u9009\uFF1A${sectionHelp}\uFF1BGoogle \u522B\u540D\uFF1Acampaigns,geographic,devices,ads,materials`
|
|
121204
|
+
).option("--exclude <list>", "\u6392\u9664\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0E --sections \u53EF\u53E0\u52A0").option(
|
|
121205
|
+
"--limit <n>",
|
|
121206
|
+
"\u4EC5 country \u7EF4\u5EA6\uFF1A\u6309 spend \u964D\u5E8F\u53D6\u524D N \u6761\uFF08\u4E0D\u4F20\u5219\u8FD4\u56DE\u5168\u90E8\u56FD\u5BB6\uFF09",
|
|
121207
|
+
(v) => parseInt(v, 10)
|
|
121208
|
+
).option("--concurrency <n>", "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 16", (v) => parseInt(v, 10)).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
121209
|
+
await runAllFacebookSections(opts);
|
|
121210
|
+
});
|
|
121211
|
+
}
|
|
121212
|
+
|
|
121213
|
+
// src/index.ts
|
|
120903
121214
|
init_version();
|
|
120904
121215
|
init_cli_json_snapshot();
|
|
120905
121216
|
installProcessHandlers();
|
|
120906
121217
|
function getVersion() {
|
|
120907
121218
|
try {
|
|
120908
|
-
const __dirname3 =
|
|
120909
|
-
const pkgPath =
|
|
121219
|
+
const __dirname3 = path22.dirname(fileURLToPath4(import.meta.url));
|
|
121220
|
+
const pkgPath = path22.join(__dirname3, "..", "package.json");
|
|
120910
121221
|
const pkg = JSON.parse(fs14.readFileSync(pkgPath, "utf8"));
|
|
120911
121222
|
return pkg.version ?? "0.0.0";
|
|
120912
121223
|
} catch {
|
|
@@ -120946,6 +121257,7 @@ var REGISTRARS = [
|
|
|
120946
121257
|
register13,
|
|
120947
121258
|
registerGoogleAnalysisCommands,
|
|
120948
121259
|
registerGoogleAnalysisBatchCommands,
|
|
121260
|
+
registerFacebookAnalysisCommands,
|
|
120949
121261
|
register14,
|
|
120950
121262
|
register15,
|
|
120951
121263
|
register16,
|