siluzan-tso-cli 1.1.27 → 1.1.28-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 +369 -60
- package/dist/skill/SKILL.md +8 -6
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/meta-period-report-rules.md +169 -0
- package/dist/skill/assets/meta-period-report.schema.json +228 -0
- package/dist/skill/references/README.md +2 -0
- package/dist/skill/references/accounts/accounts.md +43 -14
- package/dist/skill/references/accounts/finance.md +32 -32
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/account-analytics.md +7 -6
- package/dist/skill/references/analytics/facebook-analysis-guide.md +65 -12
- 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 +1 -1
- package/dist/skill/references/core/agent-conventions.md +1 -1
- package/dist/skill/references/core/deliverable-preflight.md +3 -2
- package/dist/skill/references/core/playbooks.md +15 -9
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/skill-authoring.md +1 -1
- package/dist/skill/references/core/tips.md +4 -2
- package/dist/skill/references/core/workflows.md +29 -12
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/report-templates/README.md +2 -1
- package/dist/skill/report-templates/REPORT-WORKFLOW.md +15 -5
- package/dist/skill/report-templates/meta-period-report-excel.md +222 -0
- package/dist/skill/report-templates/meta-period-report.html +634 -0
- package/dist/skill/report-templates/meta-period-report.md +149 -48
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/eval/cases/uj-ops-google-accounts-list-normal.scenario.json +4 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -258,9 +258,9 @@ var require_semver = __commonJS({
|
|
|
258
258
|
} else {
|
|
259
259
|
this.prerelease = m[4].split(".").map((id) => {
|
|
260
260
|
if (/^[0-9]+$/.test(id)) {
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
return
|
|
261
|
+
const num2 = +id;
|
|
262
|
+
if (num2 >= 0 && num2 < MAX_SAFE_INTEGER) {
|
|
263
|
+
return num2;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
return id;
|
|
@@ -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
|
|
|
@@ -101099,14 +101099,14 @@ function computeBackoffMs(attempt, policy) {
|
|
|
101099
101099
|
return capped + jitter;
|
|
101100
101100
|
}
|
|
101101
101101
|
function sleep3(ms, signal) {
|
|
101102
|
-
return new Promise((
|
|
101102
|
+
return new Promise((resolve15, reject) => {
|
|
101103
101103
|
if (signal?.aborted) {
|
|
101104
101104
|
reject(new Error("retry sleep aborted"));
|
|
101105
101105
|
return;
|
|
101106
101106
|
}
|
|
101107
101107
|
const timer = setTimeout(() => {
|
|
101108
101108
|
signal?.removeEventListener("abort", onAbort);
|
|
101109
|
-
|
|
101109
|
+
resolve15();
|
|
101110
101110
|
}, ms);
|
|
101111
101111
|
const onAbort = () => {
|
|
101112
101112
|
clearTimeout(timer);
|
|
@@ -102726,10 +102726,10 @@ var init_google_analysis3 = __esm({
|
|
|
102726
102726
|
// src/index.ts
|
|
102727
102727
|
init_dist();
|
|
102728
102728
|
init_dist();
|
|
102729
|
-
import * as
|
|
102730
|
-
import * as
|
|
102731
|
-
import { fileURLToPath as
|
|
102732
|
-
import { Command } from "commander";
|
|
102729
|
+
import * as fs18 from "fs";
|
|
102730
|
+
import * as path26 from "path";
|
|
102731
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
102732
|
+
import { Command as Command2 } from "commander";
|
|
102733
102733
|
|
|
102734
102734
|
// src/commands/login/urls.ts
|
|
102735
102735
|
init_defaults();
|
|
@@ -103212,8 +103212,8 @@ function deriveWebUrl(apiBaseUrl) {
|
|
|
103212
103212
|
}
|
|
103213
103213
|
var TSO_UMI_ROUTE_PREFIX = "/v3umijs/tso";
|
|
103214
103214
|
function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
103215
|
-
const
|
|
103216
|
-
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${
|
|
103215
|
+
const path27 = tsoSubRoute.replace(/^\/+/, "");
|
|
103216
|
+
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${path27}`;
|
|
103217
103217
|
const q = new URLSearchParams({ tso: umiPath });
|
|
103218
103218
|
if (extraQuery) {
|
|
103219
103219
|
for (const [key, value] of Object.entries(extraQuery)) {
|
|
@@ -103221,7 +103221,7 @@ function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
|
103221
103221
|
if (v) q.set(key, v);
|
|
103222
103222
|
}
|
|
103223
103223
|
}
|
|
103224
|
-
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${
|
|
103224
|
+
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${path27}?${q.toString()}`;
|
|
103225
103225
|
}
|
|
103226
103226
|
function cmdConfigShow() {
|
|
103227
103227
|
const shared = readSharedConfig();
|
|
@@ -110408,7 +110408,7 @@ function cloneKeywordBlockShell(block) {
|
|
|
110408
110408
|
delete shell["matchTypeV2"];
|
|
110409
110409
|
return shell;
|
|
110410
110410
|
}
|
|
110411
|
-
function splitKeywordsForBatchJobBlockIfMixed(block,
|
|
110411
|
+
function splitKeywordsForBatchJobBlockIfMixed(block, path27, warnings) {
|
|
110412
110412
|
const declaredUi = matchTypeV2ToUi(readBlockMatchTypeRaw(block));
|
|
110413
110413
|
const entries = collectKeywordEntriesFromBlock(block);
|
|
110414
110414
|
if (entries.length === 0) return [block];
|
|
@@ -110427,7 +110427,7 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path25, warnings) {
|
|
|
110427
110427
|
(ui) => matchTypeUiToV2(ui)
|
|
110428
110428
|
);
|
|
110429
110429
|
warnings.push(
|
|
110430
|
-
`${
|
|
110430
|
+
`${path27} \u542B\u591A\u79CD\u5339\u914D\u7C7B\u578B\uFF0C\u5DF2\u81EA\u52A8\u62C6\u5206\u4E3A ${groups.size} \u4E2A KeywordsForBatchJob \u5757\uFF08${labels.join("\u3001")}\uFF09`
|
|
110431
110431
|
);
|
|
110432
110432
|
const shell = cloneKeywordBlockShell(block);
|
|
110433
110433
|
const splitBlocks = [];
|
|
@@ -110447,16 +110447,16 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path25, warnings) {
|
|
|
110447
110447
|
}
|
|
110448
110448
|
return splitBlocks;
|
|
110449
110449
|
}
|
|
110450
|
-
function validateKeywordCore(core,
|
|
110450
|
+
function validateKeywordCore(core, path27, errors, lengthViolations) {
|
|
110451
110451
|
const trimmed = core.trim();
|
|
110452
110452
|
if (!trimmed) {
|
|
110453
|
-
errors.push(`${
|
|
110453
|
+
errors.push(`${path27} \u5173\u952E\u8BCD\u8BCD\u5E72\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
110454
110454
|
return false;
|
|
110455
110455
|
}
|
|
110456
110456
|
if (trimmed.length > GOOGLE_KEYWORD_MAX_CORE_LENGTH) {
|
|
110457
110457
|
if (lengthViolations) {
|
|
110458
110458
|
pushLengthViolation(lengthViolations, {
|
|
110459
|
-
path:
|
|
110459
|
+
path: path27,
|
|
110460
110460
|
field: "KeywordText",
|
|
110461
110461
|
kind: "keyword_core",
|
|
110462
110462
|
limit: GOOGLE_KEYWORD_MAX_CORE_LENGTH,
|
|
@@ -110466,13 +110466,13 @@ function validateKeywordCore(core, path25, errors, lengthViolations) {
|
|
|
110466
110466
|
});
|
|
110467
110467
|
}
|
|
110468
110468
|
errors.push(
|
|
110469
|
-
`${
|
|
110469
|
+
`${path27} \u5173\u952E\u8BCD\u8BCD\u5E72\u8D85\u8FC7 ${GOOGLE_KEYWORD_MAX_CORE_LENGTH} \u5B57\u7B26\uFF08\u5F53\u524D ${trimmed.length}\uFF09\uFF1A"${trimmed}"`
|
|
110470
110470
|
);
|
|
110471
110471
|
return false;
|
|
110472
110472
|
}
|
|
110473
110473
|
if (!VALID_CORE_REGEX.test(trimmed)) {
|
|
110474
110474
|
errors.push(
|
|
110475
|
-
`${
|
|
110475
|
+
`${path27} \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" : ""}"`
|
|
110476
110476
|
);
|
|
110477
110477
|
return false;
|
|
110478
110478
|
}
|
|
@@ -110529,24 +110529,24 @@ function canonicalizeKeywordBatchBlock(block, resolvedMatchV2, normalizedTexts,
|
|
|
110529
110529
|
}
|
|
110530
110530
|
}
|
|
110531
110531
|
}
|
|
110532
|
-
function pushKeywordAutoFixWarning(warnings,
|
|
110532
|
+
function pushKeywordAutoFixWarning(warnings, path27, fieldLabel, trimmedRaw, formatted, declaredUi, beforeUi, matchType, inferredMatchType) {
|
|
110533
110533
|
if (inferredMatchType) {
|
|
110534
110534
|
warnings.push(
|
|
110535
|
-
`${
|
|
110535
|
+
`${path27}.${fieldLabel} \u672A\u6307\u5B9A MatchTypeV2\uFF0C\u5DF2\u6309\u8BCD\u9762\u63A8\u65AD\u4E3A ${matchTypeUiToV2(matchType)}`
|
|
110536
110536
|
);
|
|
110537
110537
|
return;
|
|
110538
110538
|
}
|
|
110539
110539
|
if (declaredUi && beforeUi !== declaredUi) {
|
|
110540
110540
|
warnings.push(
|
|
110541
|
-
`${
|
|
110541
|
+
`${path27}.${fieldLabel} MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u4E0E\u8BCD\u9762\u4E0D\u4E00\u81F4\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`
|
|
110542
110542
|
);
|
|
110543
110543
|
return;
|
|
110544
110544
|
}
|
|
110545
110545
|
if (formatted !== trimmedRaw) {
|
|
110546
|
-
warnings.push(`${
|
|
110546
|
+
warnings.push(`${path27}.${fieldLabel} \u5DF2\u81EA\u52A8\u4FEE\u590D\u8BCD\u9762\uFF1A${trimmedRaw} \u2192 ${formatted}`);
|
|
110547
110547
|
}
|
|
110548
110548
|
}
|
|
110549
|
-
function normalizeKeywordTextList(texts, matchTypeRaw,
|
|
110549
|
+
function normalizeKeywordTextList(texts, matchTypeRaw, path27, fieldLabel, errors, warnings, lengthViolations) {
|
|
110550
110550
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110551
110551
|
const normalized = [];
|
|
110552
110552
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -110554,7 +110554,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110554
110554
|
for (let k = 0; k < texts.length; k++) {
|
|
110555
110555
|
const raw = texts[k];
|
|
110556
110556
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
110557
|
-
errors.push(`${
|
|
110557
|
+
errors.push(`${path27}.${fieldLabel}[${k}] \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110558
110558
|
continue;
|
|
110559
110559
|
}
|
|
110560
110560
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110562,7 +110562,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110562
110562
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110563
110563
|
pushKeywordAutoFixWarning(
|
|
110564
110564
|
warnings,
|
|
110565
|
-
|
|
110565
|
+
path27,
|
|
110566
110566
|
fieldLabel,
|
|
110567
110567
|
trimmedRaw,
|
|
110568
110568
|
formatted,
|
|
@@ -110572,10 +110572,10 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110572
110572
|
inferredMatchType
|
|
110573
110573
|
);
|
|
110574
110574
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110575
|
-
if (!validateKeywordCore(core, `${
|
|
110575
|
+
if (!validateKeywordCore(core, `${path27}.${fieldLabel}[${k}]`, errors, lengthViolations)) continue;
|
|
110576
110576
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110577
110577
|
if (seen.has(dedupeKey)) {
|
|
110578
|
-
warnings.push(`${
|
|
110578
|
+
warnings.push(`${path27}.${fieldLabel}[${k}] \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110579
110579
|
continue;
|
|
110580
110580
|
}
|
|
110581
110581
|
seen.add(dedupeKey);
|
|
@@ -110584,12 +110584,12 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110584
110584
|
}
|
|
110585
110585
|
return { normalized, resolvedUi };
|
|
110586
110586
|
}
|
|
110587
|
-
function normalizeKeywordsForBatchJobBlock(block,
|
|
110587
|
+
function normalizeKeywordsForBatchJobBlock(block, path27, errors, warnings, lengthViolations) {
|
|
110588
110588
|
const matchTypeRaw = readBlockMatchTypeRaw(block);
|
|
110589
110589
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110590
110590
|
if (matchTypeRaw !== void 0 && declaredUi === null) {
|
|
110591
110591
|
errors.push(
|
|
110592
|
-
`${
|
|
110592
|
+
`${path27}.MatchTypeV2 \u65E0\u6548\uFF08${String(matchTypeRaw)}\uFF09\uFF0C\u5408\u6CD5\u503C\uFF1ABROAD | PHRASE | EXACT`
|
|
110593
110593
|
);
|
|
110594
110594
|
return;
|
|
110595
110595
|
}
|
|
@@ -110604,7 +110604,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110604
110604
|
const result = normalizeKeywordTextList(
|
|
110605
110605
|
texts,
|
|
110606
110606
|
matchTypeRaw,
|
|
110607
|
-
|
|
110607
|
+
path27,
|
|
110608
110608
|
"KeywordText",
|
|
110609
110609
|
errors,
|
|
110610
110610
|
warnings,
|
|
@@ -110613,7 +110613,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110613
110613
|
normalizedTexts = result.normalized;
|
|
110614
110614
|
if (result.resolvedUi) resolvedUi = result.resolvedUi;
|
|
110615
110615
|
if (normalizedTexts.length === 0 && texts.length > 0) {
|
|
110616
|
-
errors.push(`${
|
|
110616
|
+
errors.push(`${path27}.KeywordText \u7ECF\u6821\u9A8C\u540E\u65E0\u6709\u6548\u5173\u952E\u8BCD\uFF0C\u8BF7\u4FEE\u6B63\u8BCD\u9762\u6216 MatchTypeV2`);
|
|
110617
110617
|
}
|
|
110618
110618
|
}
|
|
110619
110619
|
if (hasItems && items) {
|
|
@@ -110621,12 +110621,12 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110621
110621
|
for (let k = 0; k < items.length; k++) {
|
|
110622
110622
|
const item = items[k];
|
|
110623
110623
|
if (!item || typeof item !== "object") {
|
|
110624
|
-
errors.push(`${
|
|
110624
|
+
errors.push(`${path27}.Items[${k}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
110625
110625
|
continue;
|
|
110626
110626
|
}
|
|
110627
110627
|
const raw = readItemText(item);
|
|
110628
110628
|
if (raw === null || !raw.trim()) {
|
|
110629
|
-
errors.push(`${
|
|
110629
|
+
errors.push(`${path27}.Items[${k}].Text \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110630
110630
|
continue;
|
|
110631
110631
|
}
|
|
110632
110632
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110634,7 +110634,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110634
110634
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110635
110635
|
pushKeywordAutoFixWarning(
|
|
110636
110636
|
warnings,
|
|
110637
|
-
|
|
110637
|
+
path27,
|
|
110638
110638
|
`Items[${k}].Text`,
|
|
110639
110639
|
trimmedRaw,
|
|
110640
110640
|
formatted,
|
|
@@ -110644,10 +110644,10 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110644
110644
|
inferredMatchType
|
|
110645
110645
|
);
|
|
110646
110646
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110647
|
-
if (!validateKeywordCore(core, `${
|
|
110647
|
+
if (!validateKeywordCore(core, `${path27}.Items[${k}].Text`, errors, lengthViolations)) continue;
|
|
110648
110648
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110649
110649
|
if (seen.has(dedupeKey)) {
|
|
110650
|
-
warnings.push(`${
|
|
110650
|
+
warnings.push(`${path27}.Items[${k}].Text \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110651
110651
|
continue;
|
|
110652
110652
|
}
|
|
110653
110653
|
seen.add(dedupeKey);
|
|
@@ -113255,12 +113255,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113255
113255
|
for (let ki = 0; ki < texts.length; ki++) {
|
|
113256
113256
|
const t = texts[ki];
|
|
113257
113257
|
if (typeof t !== "string" || !t.trim()) continue;
|
|
113258
|
-
const
|
|
113258
|
+
const path27 = `${groupPath}.KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
113259
113259
|
const key = keywordKey(t, matchTypeV2);
|
|
113260
113260
|
if (!liveKwKeys.has(key)) {
|
|
113261
113261
|
missing.push({
|
|
113262
113262
|
layer: "keyword",
|
|
113263
|
-
path:
|
|
113263
|
+
path: path27,
|
|
113264
113264
|
adGroupName: groupName,
|
|
113265
113265
|
plannedContent: `\u8BCD\u9762: ${t} | \u5339\u914D: ${matchTypeV2}`,
|
|
113266
113266
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveKwInGroup.length} \u6761\u5173\u952E\u8BCD\uFF0C\u65E0\u952E ${key}`,
|
|
@@ -113278,12 +113278,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113278
113278
|
for (let ai = 0; ai < ads.length; ai++) {
|
|
113279
113279
|
const ad = asRecord2(ads[ai]);
|
|
113280
113280
|
if (!ad) continue;
|
|
113281
|
-
const
|
|
113281
|
+
const path27 = `${groupPath}.AdsForBatchJob[${ai}]`;
|
|
113282
113282
|
const primary = pickString(ad["headlinePart1"], ad["AdTitle"]);
|
|
113283
113283
|
if (!primary) {
|
|
113284
113284
|
missing.push({
|
|
113285
113285
|
layer: "ad",
|
|
113286
|
-
path:
|
|
113286
|
+
path: path27,
|
|
113287
113287
|
adGroupName: groupName,
|
|
113288
113288
|
plannedContent: `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF0C\u65E0\u6CD5\u6BD4\u5BF9\uFF09`,
|
|
113289
113289
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761\u521B\u610F`,
|
|
@@ -113296,7 +113296,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113296
113296
|
if (!found) {
|
|
113297
113297
|
missing.push({
|
|
113298
113298
|
layer: "ad",
|
|
113299
|
-
path:
|
|
113299
|
+
path: path27,
|
|
113300
113300
|
adGroupName: groupName,
|
|
113301
113301
|
plannedContent: `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}`,
|
|
113302
113302
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761 RSA\uFF0C\u65E0\u6B64\u9996\u6807\u9898`,
|
|
@@ -114494,13 +114494,13 @@ function pmaxChannelTypesUrl(googleApiUrl) {
|
|
|
114494
114494
|
}
|
|
114495
114495
|
function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
|
|
114496
114496
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114497
|
-
const
|
|
114498
|
-
return campaignId ? `${
|
|
114497
|
+
const path27 = `${base}/accounts/${accountId}/campaign/pmax`;
|
|
114498
|
+
return campaignId ? `${path27}/${campaignId}` : path27;
|
|
114499
114499
|
}
|
|
114500
114500
|
function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
|
|
114501
114501
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114502
|
-
const
|
|
114503
|
-
return suffix ? `${
|
|
114502
|
+
const path27 = `${base}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
|
|
114503
|
+
return suffix ? `${path27}/${suffix.replace(/^\//, "")}` : path27;
|
|
114504
114504
|
}
|
|
114505
114505
|
function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
|
|
114506
114506
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
@@ -121435,6 +121435,8 @@ function register25(program2) {
|
|
|
121435
121435
|
console.log(" CLI \u62C9\u6570\uFF1A");
|
|
121436
121436
|
console.log(" siluzan-tso website-diagnosis collect --url <url> --json-out ./snap-web");
|
|
121437
121437
|
console.log(" siluzan-tso website-diagnosis performance --url <url> --json-out ./snap-web");
|
|
121438
|
+
console.log(" \u9ED8\u8BA4\u4EA4\u4ED8 HTML\uFF1A");
|
|
121439
|
+
console.log(" siluzan-tso website-diagnosis render --data ./diagnosis.json --collect ./snap-web/<collect>.json");
|
|
121438
121440
|
console.log(" Skill\uFF1Areferences/analytics/website-diagnosis-guide.md\n");
|
|
121439
121441
|
console.log(" \u3010\u8D26\u6237\u5217\u8868 ARIT \u5206\u3011");
|
|
121440
121442
|
console.log(" list-accounts \u4F1A\u8865\u5145 ma.diagnoseReports \u4E2D reportSource=ARIT \u7684\u5F97\u5206\uFF1B");
|
|
@@ -121633,7 +121635,7 @@ async function runWebsiteDiagnosisCollect(opts) {
|
|
|
121633
121635
|
htmlPreview,
|
|
121634
121636
|
...htmlFull ? { htmlContent: htmlFull } : {},
|
|
121635
121637
|
...htmlError ? { htmlError } : {},
|
|
121636
|
-
agentHint: "1) \u6309 website-diagnosis-rules.md \u751F\u6210\u8BCA\u65AD JSON\uFF1B2) siluzan-tso website-diagnosis render --data <diagnosis.json> --collect <\u672C\u6587\u4EF6> \
|
|
121638
|
+
agentHint: "1) \u6309 website-diagnosis-rules.md \u751F\u6210\u8BCA\u65AD JSON\uFF1B2) siluzan-tso website-diagnosis render --data <diagnosis.json> --collect <\u672C\u6587\u4EF6> \u9ED8\u8BA4\u4EA7\u51FA HTML \u7EC8\u7A3F website-diagnosis-report.html\uFF08\u7981\u6B62\u4EC5 Markdown/JSON \u4EA4\u4ED8\uFF09\u3002"
|
|
121637
121639
|
};
|
|
121638
121640
|
if (await emitCliJsonOrSnapshot(
|
|
121639
121641
|
{ jsonOut: opts.jsonOut },
|
|
@@ -121756,7 +121758,7 @@ async function runWebsiteDiagnosisRender(opts) {
|
|
|
121756
121758
|
// src/commands/website-diagnosis/register.ts
|
|
121757
121759
|
function registerWebsiteDiagnosisCommands(program2) {
|
|
121758
121760
|
const root = program2.command("website-diagnosis").description(
|
|
121759
|
-
"\u7F51\u7AD9\u8BCA\u65AD\uFF1ALighthouse \u6027\u80FD\u3001HTML \u91C7\u96C6\
|
|
121761
|
+
"\u7F51\u7AD9\u8BCA\u65AD\uFF1ALighthouse \u6027\u80FD\u3001HTML \u91C7\u96C6\u3001ARIT \u5386\u53F2\u5F97\u5206\uFF1B\u9ED8\u8BA4\u4EA4\u4ED8 HTML \u62A5\u544A\uFF08render \u5B50\u547D\u4EE4\uFF09"
|
|
121760
121762
|
);
|
|
121761
121763
|
root.command("performance").description("\u62C9\u53D6 Lighthouse \u6027\u80FD\u6570\u636E\uFF08GET WebsiteDiagnosisReports/performance\uFF09").requiredOption("--url <url>", "\u7F51\u7AD9 URL\uFF08\u53EF\u7701\u7565 https://\uFF0C\u81EA\u52A8\u8865\u5168\uFF09").option("--token <token>", "JWT\uFF08\u9ED8\u8BA4\u8BFB config / \u73AF\u5883\u53D8\u91CF\uFF09").option("--verbose", "\u6253\u5370\u8BF7\u6C42\u8BE6\u60C5").option("--json-out <dir>", "\u843D\u76D8 cli-manifest + JSON").action(async (opts) => {
|
|
121762
121764
|
await runWebsiteDiagnosisPerformance({
|
|
@@ -121789,7 +121791,7 @@ function registerWebsiteDiagnosisCommands(program2) {
|
|
|
121789
121791
|
}
|
|
121790
121792
|
);
|
|
121791
121793
|
root.command("render").description(
|
|
121792
|
-
"\u6839\u636E\u8BCA\u65AD JSON \u751F\u6210\
|
|
121794
|
+
"\u6839\u636E\u8BCA\u65AD JSON \u751F\u6210 HTML \u7EC8\u7A3F\uFF08\u9ED8\u8BA4\u4EA4\u4ED8\u683C\u5F0F\uFF0Cwebsite-diagnosis-report.html\uFF09"
|
|
121793
121795
|
).requiredOption("--data <file>", "\u8BCA\u65AD\u7ED3\u679C JSON\uFF08getWebsiteDiagnosisData \u540C\u7ED3\u6784\uFF09").option("--collect <file>", "\u53EF\u9009\uFF1Acollect \u843D\u76D8 JSON\uFF0C\u7528\u4E8E\u5408\u5E76 lighthouse").option("--out <file>", "\u8F93\u51FA HTML \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\uFF09").action(async (opts) => {
|
|
121794
121796
|
await runWebsiteDiagnosisRender({
|
|
121795
121797
|
dataFile: opts.data,
|
|
@@ -122476,9 +122478,298 @@ function endpointHintForFacebookSection(def, apiId) {
|
|
|
122476
122478
|
return `GET \u2026/FacebookAds/${apiId}/${def.segment}`;
|
|
122477
122479
|
}
|
|
122478
122480
|
|
|
122481
|
+
// src/commands/facebook-analysis/register-cli.ts
|
|
122482
|
+
import { Command } from "commander";
|
|
122483
|
+
|
|
122484
|
+
// src/commands/facebook-analysis/render-report.ts
|
|
122485
|
+
import fs17 from "fs";
|
|
122486
|
+
import fsPromises2 from "fs/promises";
|
|
122487
|
+
import path24 from "path";
|
|
122488
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
122489
|
+
|
|
122490
|
+
// src/commands/facebook-analysis/merge-snapshot.ts
|
|
122491
|
+
import * as fs16 from "fs/promises";
|
|
122492
|
+
import * as path23 from "path";
|
|
122493
|
+
function asRecord5(value) {
|
|
122494
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
122495
|
+
return value;
|
|
122496
|
+
}
|
|
122497
|
+
return null;
|
|
122498
|
+
}
|
|
122499
|
+
function num(value) {
|
|
122500
|
+
const n = Number(value);
|
|
122501
|
+
return Number.isFinite(n) ? n : void 0;
|
|
122502
|
+
}
|
|
122503
|
+
function audienceLabel(age, gender) {
|
|
122504
|
+
const g = String(gender ?? "").toLowerCase();
|
|
122505
|
+
const genderZh = g === "male" ? "male" : g === "female" ? "female" : String(gender ?? "");
|
|
122506
|
+
return `${age ?? "\u2014"} \xB7 ${genderZh}`;
|
|
122507
|
+
}
|
|
122508
|
+
function fatigueFromFrequency(freq) {
|
|
122509
|
+
if (freq == null) return { level: "\u4F4E", score: 25 };
|
|
122510
|
+
if (freq >= 2.2) return { level: "\u9AD8", score: 75 };
|
|
122511
|
+
if (freq >= 1.6) return { level: "\u4E2D", score: 55 };
|
|
122512
|
+
return { level: "\u4F4E", score: 25 };
|
|
122513
|
+
}
|
|
122514
|
+
function statusFromCpl(cpl, avg) {
|
|
122515
|
+
if (cpl == null || avg <= 0) return { tag: "yellow", label: "\u89C2\u5BDF" };
|
|
122516
|
+
if (cpl <= avg * 0.9) return { tag: "green", label: "\u76C8\u5229" };
|
|
122517
|
+
if (cpl >= avg * 1.15) return { tag: "red", label: "\u5371\u9669" };
|
|
122518
|
+
return { tag: "yellow", label: "\u89C2\u5BDF" };
|
|
122519
|
+
}
|
|
122520
|
+
async function readManifest(snapshotDir) {
|
|
122521
|
+
const entries = await fs16.readdir(snapshotDir);
|
|
122522
|
+
const manifestNames = entries.filter((n) => n.startsWith("report-manifest") && n.endsWith(".json"));
|
|
122523
|
+
const ordered = [
|
|
122524
|
+
...manifestNames.filter((n) => n !== REPORT_MANIFEST_FILE),
|
|
122525
|
+
...manifestNames.includes(REPORT_MANIFEST_FILE) ? [REPORT_MANIFEST_FILE] : []
|
|
122526
|
+
];
|
|
122527
|
+
for (const name2 of ordered) {
|
|
122528
|
+
try {
|
|
122529
|
+
const raw = await fs16.readFile(path23.join(snapshotDir, name2), "utf8");
|
|
122530
|
+
const parsed = JSON.parse(raw);
|
|
122531
|
+
if (parsed?.artifacts?.length) return parsed;
|
|
122532
|
+
} catch {
|
|
122533
|
+
}
|
|
122534
|
+
}
|
|
122535
|
+
return null;
|
|
122536
|
+
}
|
|
122537
|
+
async function loadSectionFile(snapshotDir, file) {
|
|
122538
|
+
try {
|
|
122539
|
+
const raw = await fs16.readFile(path23.join(snapshotDir, file), "utf8");
|
|
122540
|
+
return asRecord5(JSON.parse(raw));
|
|
122541
|
+
} catch {
|
|
122542
|
+
return null;
|
|
122543
|
+
}
|
|
122544
|
+
}
|
|
122545
|
+
function aggregatePlatform(networks) {
|
|
122546
|
+
const map = /* @__PURE__ */ new Map();
|
|
122547
|
+
for (const row of networks) {
|
|
122548
|
+
const platform = String(row.publisherPlatform ?? row.network ?? "unknown");
|
|
122549
|
+
const prev = map.get(platform) ?? { spend: 0, results: 0 };
|
|
122550
|
+
map.set(platform, {
|
|
122551
|
+
spend: prev.spend + (num(row.spend) ?? 0),
|
|
122552
|
+
results: prev.results + (num(row.results) ?? 0)
|
|
122553
|
+
});
|
|
122554
|
+
}
|
|
122555
|
+
const labels = [];
|
|
122556
|
+
const cpl = [];
|
|
122557
|
+
const spend = [];
|
|
122558
|
+
for (const [label, agg] of [...map.entries()].sort((a, b) => b[1].spend - a[1].spend)) {
|
|
122559
|
+
labels.push(label);
|
|
122560
|
+
spend.push(agg.spend);
|
|
122561
|
+
cpl.push(agg.results > 0 ? agg.spend / agg.results : 0);
|
|
122562
|
+
}
|
|
122563
|
+
return { labels, cpl, spend };
|
|
122564
|
+
}
|
|
122565
|
+
function buildAudienceRows(audiences) {
|
|
122566
|
+
return audiences.map((a) => ({
|
|
122567
|
+
label: audienceLabel(a.age, a.gender),
|
|
122568
|
+
spend: num(a.spend) ?? 0,
|
|
122569
|
+
results: num(a.results) ?? 0,
|
|
122570
|
+
costPerResult: num(a.costPerResult) ?? (num(a.results) ? (num(a.spend) ?? 0) / (num(a.results) ?? 1) : 0),
|
|
122571
|
+
frequency: num(a.frequency)
|
|
122572
|
+
})).filter((r) => r.spend > 0 || r.results > 0);
|
|
122573
|
+
}
|
|
122574
|
+
async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
122575
|
+
const absDir = path23.resolve(snapshotDir);
|
|
122576
|
+
const manifest = await readManifest(snapshotDir);
|
|
122577
|
+
if (!manifest) {
|
|
122578
|
+
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C facebook-analysis --json-out`);
|
|
122579
|
+
}
|
|
122580
|
+
const sectionMap = /* @__PURE__ */ new Map();
|
|
122581
|
+
for (const art of manifest.artifacts) {
|
|
122582
|
+
const data = await loadSectionFile(absDir, art.file);
|
|
122583
|
+
if (data) sectionMap.set(art.section, data);
|
|
122584
|
+
}
|
|
122585
|
+
const overview = sectionMap.get("overview");
|
|
122586
|
+
const current = asRecord5(overview?.currentPeriod);
|
|
122587
|
+
const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
|
|
122588
|
+
const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
|
|
122589
|
+
const kpis = { ...payload.kpis ?? {} };
|
|
122590
|
+
if (current) {
|
|
122591
|
+
if (kpis.spend == null) kpis.spend = current.spend;
|
|
122592
|
+
if (kpis.results == null) kpis.results = current.results;
|
|
122593
|
+
if (kpis.costPerResult == null) kpis.costPerResult = current.costPerResult;
|
|
122594
|
+
if (kpis.reach == null) kpis.reach = current.reach;
|
|
122595
|
+
if (kpis.impressions == null) kpis.impressions = current.impressions;
|
|
122596
|
+
if (kpis.frequency == null) kpis.frequency = current.frequency;
|
|
122597
|
+
}
|
|
122598
|
+
const meta = { ...payload.meta ?? {} };
|
|
122599
|
+
if (!meta.accountName && accountName) meta.accountName = accountName;
|
|
122600
|
+
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
122601
|
+
if (!meta.startDate && manifest.dateRange?.start) meta.startDate = manifest.dateRange.start;
|
|
122602
|
+
if (!meta.endDate && manifest.dateRange?.end) meta.endDate = manifest.dateRange.end;
|
|
122603
|
+
if (!meta.attributionSetting && current?.attributionSetting) {
|
|
122604
|
+
meta.attributionSetting = String(current.attributionSetting);
|
|
122605
|
+
}
|
|
122606
|
+
if (!meta.resultType && current?.resultType) meta.resultType = String(current.resultType);
|
|
122607
|
+
const charts = { ...payload.charts ?? {} };
|
|
122608
|
+
const avgCpl = num(kpis.costPerResult) ?? 0;
|
|
122609
|
+
if (!charts.platform) {
|
|
122610
|
+
const platform = sectionMap.get("platform");
|
|
122611
|
+
const networks = Array.isArray(platform?.networks) ? platform.networks : [];
|
|
122612
|
+
if (networks.length) charts.platform = aggregatePlatform(networks);
|
|
122613
|
+
}
|
|
122614
|
+
if (!charts.country) {
|
|
122615
|
+
const country = sectionMap.get("country");
|
|
122616
|
+
const countries = Array.isArray(country?.countries) ? country.countries : [];
|
|
122617
|
+
if (countries.length) {
|
|
122618
|
+
const sorted = [...countries].sort((a, b) => (num(b.spend) ?? 0) - (num(a.spend) ?? 0));
|
|
122619
|
+
charts.country = {
|
|
122620
|
+
labels: sorted.map((c) => String(c.countryOrRegion ?? "\u2014")),
|
|
122621
|
+
cpl: sorted.map((c) => num(c.costPerResult) ?? 0)
|
|
122622
|
+
};
|
|
122623
|
+
}
|
|
122624
|
+
}
|
|
122625
|
+
if (!charts.audience) {
|
|
122626
|
+
const audience = sectionMap.get("audience");
|
|
122627
|
+
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
122628
|
+
if (audiences.length) {
|
|
122629
|
+
const rows = buildAudienceRows(audiences).sort((a, b) => a.costPerResult - b.costPerResult);
|
|
122630
|
+
charts.audience = {
|
|
122631
|
+
labels: rows.map((r) => r.label),
|
|
122632
|
+
cpl: rows.map((r) => r.costPerResult),
|
|
122633
|
+
leads: rows.map((r) => r.results)
|
|
122634
|
+
};
|
|
122635
|
+
}
|
|
122636
|
+
}
|
|
122637
|
+
if (!charts.funnel && num(kpis.reach) != null) {
|
|
122638
|
+
charts.funnel = { reach: kpis.reach, results: kpis.results ?? 0 };
|
|
122639
|
+
}
|
|
122640
|
+
const tables = { ...payload.tables ?? {} };
|
|
122641
|
+
if (!tables.adSets) {
|
|
122642
|
+
const adSets = sectionMap.get("ad-sets");
|
|
122643
|
+
const groups = Array.isArray(adSets?.adGroups) ? adSets.adGroups : [];
|
|
122644
|
+
if (groups.length) {
|
|
122645
|
+
tables.adSets = groups.map((g) => {
|
|
122646
|
+
const cpl = num(g.costPerResult);
|
|
122647
|
+
const freq = num(g.frequency);
|
|
122648
|
+
const fatigue = fatigueFromFrequency(freq);
|
|
122649
|
+
const status = statusFromCpl(cpl, avgCpl);
|
|
122650
|
+
return {
|
|
122651
|
+
name: String(g.adGroupName ?? g.campaignName ?? "\u2014"),
|
|
122652
|
+
spend: num(g.spend) ?? 0,
|
|
122653
|
+
results: num(g.results) ?? 0,
|
|
122654
|
+
costPerResult: cpl ?? 0,
|
|
122655
|
+
frequency: freq,
|
|
122656
|
+
fatigueLevel: fatigue.level,
|
|
122657
|
+
fatigueScore: fatigue.score,
|
|
122658
|
+
statusTag: status.tag,
|
|
122659
|
+
statusLabel: status.label
|
|
122660
|
+
};
|
|
122661
|
+
}).sort((a, b) => b.spend - a.spend);
|
|
122662
|
+
}
|
|
122663
|
+
}
|
|
122664
|
+
if (!tables.audienceTop || !tables.audienceBottom) {
|
|
122665
|
+
const audience = sectionMap.get("audience");
|
|
122666
|
+
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
122667
|
+
if (audiences.length) {
|
|
122668
|
+
const rows = buildAudienceRows(audiences).sort((a, b) => a.costPerResult - b.costPerResult);
|
|
122669
|
+
const topN = rows.slice(0, 10);
|
|
122670
|
+
const bottomN = [...rows].reverse().slice(0, 10);
|
|
122671
|
+
if (!tables.audienceTop) tables.audienceTop = topN;
|
|
122672
|
+
if (!tables.audienceBottom) tables.audienceBottom = bottomN;
|
|
122673
|
+
}
|
|
122674
|
+
}
|
|
122675
|
+
return {
|
|
122676
|
+
...payload,
|
|
122677
|
+
meta,
|
|
122678
|
+
kpis,
|
|
122679
|
+
charts,
|
|
122680
|
+
tables
|
|
122681
|
+
};
|
|
122682
|
+
}
|
|
122683
|
+
|
|
122684
|
+
// src/commands/facebook-analysis/render-report.ts
|
|
122685
|
+
var TEMPLATE_BASENAMES2 = {
|
|
122686
|
+
html: "meta-period-report.html",
|
|
122687
|
+
runtime: "meta-period-report.runtime.js"
|
|
122688
|
+
};
|
|
122689
|
+
var INJECT_MARKER = "window.__META_PERIOD_REPORT__ = window.__META_PERIOD_REPORT__ || null;";
|
|
122690
|
+
function resolveSkillTemplatePath2(basename11) {
|
|
122691
|
+
const dir = path24.dirname(fileURLToPath5(import.meta.url));
|
|
122692
|
+
const candidates = [
|
|
122693
|
+
path24.join(dir, "skill", "report-templates", basename11),
|
|
122694
|
+
path24.join(dir, "skill", "siluzan-ads", "report-templates", basename11),
|
|
122695
|
+
path24.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename11)
|
|
122696
|
+
];
|
|
122697
|
+
for (const p of candidates) {
|
|
122698
|
+
if (fs17.existsSync(p)) return p;
|
|
122699
|
+
}
|
|
122700
|
+
return candidates[0];
|
|
122701
|
+
}
|
|
122702
|
+
function metaPeriodReportTemplatePath() {
|
|
122703
|
+
return resolveSkillTemplatePath2(TEMPLATE_BASENAMES2.html);
|
|
122704
|
+
}
|
|
122705
|
+
function metaPeriodReportRuntimePath() {
|
|
122706
|
+
return resolveSkillTemplatePath2(TEMPLATE_BASENAMES2.runtime);
|
|
122707
|
+
}
|
|
122708
|
+
async function readJsonFile2(filePath) {
|
|
122709
|
+
const text = await fsPromises2.readFile(filePath, "utf8");
|
|
122710
|
+
try {
|
|
122711
|
+
return JSON.parse(text);
|
|
122712
|
+
} catch {
|
|
122713
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
122714
|
+
}
|
|
122715
|
+
}
|
|
122716
|
+
function asRecord6(value) {
|
|
122717
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
122718
|
+
return value;
|
|
122719
|
+
}
|
|
122720
|
+
throw new Error("\u62A5\u544A\u6570\u636E\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
122721
|
+
}
|
|
122722
|
+
function injectReportData2(html, payload) {
|
|
122723
|
+
const json = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
122724
|
+
if (!html.includes(INJECT_MARKER)) {
|
|
122725
|
+
throw new Error("\u62A5\u544A\u6A21\u677F\u7F3A\u5C11\u6570\u636E\u6CE8\u5165\u951A\u70B9\uFF0C\u8BF7\u66F4\u65B0 meta-period-report.html");
|
|
122726
|
+
}
|
|
122727
|
+
return html.replace(INJECT_MARKER, `window.__META_PERIOD_REPORT__ = ${json};`);
|
|
122728
|
+
}
|
|
122729
|
+
async function runFacebookAnalysisRender(opts) {
|
|
122730
|
+
const dataPath = path24.resolve(opts.dataFile);
|
|
122731
|
+
let data = asRecord6(await readJsonFile2(dataPath));
|
|
122732
|
+
if (opts.snapshotDir?.trim()) {
|
|
122733
|
+
data = await mergeFacebookSnapshotIntoReport(data, path24.resolve(opts.snapshotDir));
|
|
122734
|
+
}
|
|
122735
|
+
const templatePath = metaPeriodReportTemplatePath();
|
|
122736
|
+
let html;
|
|
122737
|
+
try {
|
|
122738
|
+
html = await fsPromises2.readFile(templatePath, "utf8");
|
|
122739
|
+
} catch {
|
|
122740
|
+
console.error(`
|
|
122741
|
+
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
122742
|
+
\u8BF7\u5148\u6267\u884C npm run build
|
|
122743
|
+
`);
|
|
122744
|
+
process.exit(1);
|
|
122745
|
+
}
|
|
122746
|
+
const outPath = path24.resolve(
|
|
122747
|
+
opts.out ?? path24.join(path24.dirname(dataPath), "meta-period-report.html")
|
|
122748
|
+
);
|
|
122749
|
+
const outDir = path24.dirname(outPath);
|
|
122750
|
+
await fsPromises2.mkdir(outDir, { recursive: true });
|
|
122751
|
+
await fsPromises2.writeFile(outPath, injectReportData2(html, data), "utf8");
|
|
122752
|
+
const runtimeSrc = metaPeriodReportRuntimePath();
|
|
122753
|
+
const runtimeOut = path24.join(outDir, TEMPLATE_BASENAMES2.runtime);
|
|
122754
|
+
let runtimeCopied = false;
|
|
122755
|
+
try {
|
|
122756
|
+
await fsPromises2.copyFile(runtimeSrc, runtimeOut);
|
|
122757
|
+
runtimeCopied = true;
|
|
122758
|
+
} catch {
|
|
122759
|
+
}
|
|
122760
|
+
console.log(`
|
|
122761
|
+
\u2705 Meta/Facebook \u5468\u671F\u5206\u6790 HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
122762
|
+
`);
|
|
122763
|
+
if (runtimeCopied) {
|
|
122764
|
+
console.log(` \u8FD0\u884C\u65F6\u811A\u672C\uFF1A${runtimeOut}
|
|
122765
|
+
`);
|
|
122766
|
+
}
|
|
122767
|
+
console.log("\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 HTML \u6587\u4EF6\u5373\u53EF\u67E5\u770B\u56FE\u8868\u4E0E\u5B8C\u6574\u7AE0\u8282\uFF08\u9700\u8054\u7F51\u52A0\u8F7D Chart.js CDN\uFF09\u3002\n");
|
|
122768
|
+
}
|
|
122769
|
+
|
|
122479
122770
|
// src/commands/facebook-analysis/run-batch.ts
|
|
122480
122771
|
init_auth();
|
|
122481
|
-
import * as
|
|
122772
|
+
import * as path25 from "path";
|
|
122482
122773
|
import { performance as performance5 } from "perf_hooks";
|
|
122483
122774
|
init_version();
|
|
122484
122775
|
|
|
@@ -122582,7 +122873,7 @@ async function runAllFacebookSections(opts) {
|
|
|
122582
122873
|
const results = await runWithConcurrency2(tasks, concurrency);
|
|
122583
122874
|
const succeeded = results.filter((r) => r.ok).length;
|
|
122584
122875
|
const failed = results.length - succeeded;
|
|
122585
|
-
const absoluteSnapshotDir =
|
|
122876
|
+
const absoluteSnapshotDir = path25.resolve(opts.jsonOut);
|
|
122586
122877
|
const summary = {
|
|
122587
122878
|
kind: "siluzan-tso-facebook-analysis-snapshot-batch",
|
|
122588
122879
|
absoluteSnapshotDir,
|
|
@@ -122600,10 +122891,9 @@ async function runAllFacebookSections(opts) {
|
|
|
122600
122891
|
}
|
|
122601
122892
|
|
|
122602
122893
|
// src/commands/facebook-analysis/register-cli.ts
|
|
122603
|
-
function
|
|
122604
|
-
|
|
122605
|
-
|
|
122606
|
-
"Facebook Ads \u8D26\u6237\u5206\u6790\u6279\u91CF\u62C9\u53D6\uFF08TSO reporting/media-account/FacebookAds/\u2026\uFF0C7 \u4E2A Section\uFF09"
|
|
122894
|
+
function registerBatchCommand(sectionHelp) {
|
|
122895
|
+
return new Command("run").description(
|
|
122896
|
+
"\u6279\u91CF\u62C9\u53D6 TSO reporting/media-account/FacebookAds Section \u6570\u636E\uFF08\u7701\u7565\u5B50\u547D\u4EE4\u540D\u65F6\u9ED8\u8BA4\u6267\u884C\u672C\u547D\u4EE4\uFF09"
|
|
122607
122897
|
).requiredOption(
|
|
122608
122898
|
"-a, --account <id>",
|
|
122609
122899
|
"Facebook \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6570\u5B57\u6216 act_<\u6570\u5B57>\uFF09"
|
|
@@ -122624,6 +122914,25 @@ function registerFacebookAnalysisCommands(program2) {
|
|
|
122624
122914
|
await runAllFacebookSections(opts);
|
|
122625
122915
|
});
|
|
122626
122916
|
}
|
|
122917
|
+
function registerFacebookAnalysisCommands(program2) {
|
|
122918
|
+
const sectionHelp = FACEBOOK_SECTION_NAMES.join(", ");
|
|
122919
|
+
const root = program2.command("facebook-analysis").description(
|
|
122920
|
+
"Facebook Ads \u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6 Section \u6570\u636E\uFF08\u9ED8\u8BA4\uFF09\uFF0C\u6216\u7531 render \u751F\u6210 HTML \u5468\u671F\u62A5\u544A"
|
|
122921
|
+
);
|
|
122922
|
+
root.addCommand(registerBatchCommand(sectionHelp), { isDefault: true });
|
|
122923
|
+
root.command("render").description(
|
|
122924
|
+
"\u6839\u636E Agent \u64B0\u5199\u7684\u62A5\u544A JSON \u751F\u6210 Meta/Facebook \u5468\u671F\u5206\u6790 HTML \u7EC8\u7A3F\uFF08meta-period-report.html\uFF09"
|
|
122925
|
+
).requiredOption("--data <file>", "Agent \u4EA7\u51FA\u7684 meta-period-report.json").option(
|
|
122926
|
+
"--snapshot-dir <dir>",
|
|
122927
|
+
"\u53EF\u9009\uFF1Afacebook-analysis --json-out \u76EE\u5F55\uFF0C\u81EA\u52A8\u5408\u5E76 KPI / \u56FE\u8868 / \u8868\u683C"
|
|
122928
|
+
).option("--out <file>", "\u8F93\u51FA HTML \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\uFF09").action(async (opts) => {
|
|
122929
|
+
await runFacebookAnalysisRender({
|
|
122930
|
+
dataFile: opts.data,
|
|
122931
|
+
snapshotDir: opts.snapshotDir,
|
|
122932
|
+
out: opts.out
|
|
122933
|
+
});
|
|
122934
|
+
});
|
|
122935
|
+
}
|
|
122627
122936
|
|
|
122628
122937
|
// src/index.ts
|
|
122629
122938
|
init_version();
|
|
@@ -122631,15 +122940,15 @@ init_cli_json_snapshot();
|
|
|
122631
122940
|
installProcessHandlers();
|
|
122632
122941
|
function getVersion() {
|
|
122633
122942
|
try {
|
|
122634
|
-
const __dirname3 =
|
|
122635
|
-
const pkgPath =
|
|
122636
|
-
const pkg = JSON.parse(
|
|
122943
|
+
const __dirname3 = path26.dirname(fileURLToPath6(import.meta.url));
|
|
122944
|
+
const pkgPath = path26.join(__dirname3, "..", "package.json");
|
|
122945
|
+
const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
|
|
122637
122946
|
return pkg.version ?? "0.0.0";
|
|
122638
122947
|
} catch {
|
|
122639
122948
|
return "0.0.0";
|
|
122640
122949
|
}
|
|
122641
122950
|
}
|
|
122642
|
-
var program = new
|
|
122951
|
+
var program = new Command2();
|
|
122643
122952
|
program.name("siluzan-tso").description(
|
|
122644
122953
|
"Siluzan \u5E7F\u544A\u8D26\u6237\u7BA1\u7406\uFF1A\u8D26\u6237\u67E5\u8BE2\u3001\u4F59\u989D\u3001\u6295\u653E\u6570\u636E\u3001\u5F00\u6237\u7533\u8BF7\uFF08Google/TikTok/Yandex/Bing/Kwai\uFF09\u3001\n\u8D26\u53F7\u5206\u4EAB/\u89E3\u7ED1\u3001\u4F18\u5316\u62A5\u544A\u3001Google \u8D26\u6237\u5206\u6790\u7F51\u5173\uFF08google-analysis\uFF09\u3001\u7F51\u7AD9\u8BCA\u65AD\uFF08website-diagnosis\uFF09\u3001\u6218\u7565\u5E02\u573A\u5206\u6790\uFF08market-analysis\uFF0CAgent \u751F\u6210\u62A5\u544A\uFF09\u3001\u5145\u503C\u8F6C\u8D26\u3001\u5F00\u7968\u3001\u667A\u80FD\u9884\u8B66\u3001Google \u5E7F\u544A\u7BA1\u7406\uFF08\u542B\u5F02\u6B65\u6279\u91CF\uFF09\u3002"
|
|
122645
122954
|
).version(getVersion());
|