siluzan-tso-cli 1.1.44 → 1.1.45-beta.1
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 +924 -70
- package/dist/skill/SKILL.md +1 -0
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +1 -0
- package/dist/skill/references/accounts/accounts-list.md +1 -1
- package/dist/skill/references/accounts/accounts-permissions.md +2 -2
- package/dist/skill/references/accounts/finance.md +1 -1
- package/dist/skill/references/accounts/open-account-by-media.md +1 -1
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/account-analytics.md +44 -1
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/references/report-templates/README.md +2 -0
- package/dist/skill/references/report-templates/REPORT-WORKFLOW.md +6 -4
- package/dist/skill/references/report-templates/yandex-period-report-excel.md +123 -0
- package/dist/skill/references/report-templates/yandex-period-report.md +121 -0
- package/dist/skill/report-templates/README.md +2 -0
- package/dist/skill/report-templates/REPORT-WORKFLOW.md +6 -4
- package/dist/skill/report-templates/yandex-period-report-excel.md +123 -0
- package/dist/skill/report-templates/yandex-period-report.html +968 -0
- package/dist/skill/report-templates/yandex-period-report.md +121 -0
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/package.json +3 -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 num11 = +id;
|
|
262
|
+
if (num11 >= 0 && num11 < MAX_SAFE_INTEGER) {
|
|
263
|
+
return num11;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
return id;
|
|
@@ -4026,7 +4026,7 @@ var DEFAULT_API_BASE;
|
|
|
4026
4026
|
var init_defaults = __esm({
|
|
4027
4027
|
"src/config/defaults.ts"() {
|
|
4028
4028
|
"use strict";
|
|
4029
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
4029
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
4030
4030
|
}
|
|
4031
4031
|
});
|
|
4032
4032
|
|
|
@@ -4046,6 +4046,9 @@ function deriveTiktokApiUrl(tsoApiBaseUrl) {
|
|
|
4046
4046
|
function deriveFacebookApiUrl(tsoApiBaseUrl) {
|
|
4047
4047
|
return tsoApiBaseUrl.includes("-ci") ? "https://facebookapi-ci.mysiluzan.com" : "https://facebookapi.mysiluzan.com";
|
|
4048
4048
|
}
|
|
4049
|
+
function deriveYandexApiUrl(tsoApiBaseUrl) {
|
|
4050
|
+
return tsoApiBaseUrl.includes("-ci") ? "https://yandexapi-ci.mysiluzan.com" : "https://yandexapi.mysiluzan.com";
|
|
4051
|
+
}
|
|
4049
4052
|
function deriveChatGptApiUrl(tsoApiBaseUrl) {
|
|
4050
4053
|
return tsoApiBaseUrl.includes("-ci") ? "https://chatgpt-ci.mysiluzan.com" : "https://chatgpt.mysiluzan.com";
|
|
4051
4054
|
}
|
|
@@ -4431,6 +4434,7 @@ function loadConfig(tokenArg) {
|
|
|
4431
4434
|
mainApiUrl: deriveMainApiUrl(apiBaseUrl),
|
|
4432
4435
|
tiktokApiUrl: deriveTiktokApiUrl(apiBaseUrl),
|
|
4433
4436
|
facebookApiUrl: deriveFacebookApiUrl(apiBaseUrl),
|
|
4437
|
+
yandexApiUrl: process.env.SILUZAN_YANDEX_API ?? deriveYandexApiUrl(apiBaseUrl),
|
|
4434
4438
|
chatGptApiUrl: deriveChatGptApiUrl(apiBaseUrl),
|
|
4435
4439
|
csoBaseUrl,
|
|
4436
4440
|
dataPermission: process.env.SILUZAN_DATA_PERMISSION ?? shared.dataPermission
|
|
@@ -5561,8 +5565,8 @@ var init_daily_metrics_range = __esm({
|
|
|
5561
5565
|
async function withAsyncLock(key, fn) {
|
|
5562
5566
|
const prev = chains.get(key) ?? Promise.resolve();
|
|
5563
5567
|
let release;
|
|
5564
|
-
const gate = new Promise((
|
|
5565
|
-
release =
|
|
5568
|
+
const gate = new Promise((resolve23) => {
|
|
5569
|
+
release = resolve23;
|
|
5566
5570
|
});
|
|
5567
5571
|
chains.set(
|
|
5568
5572
|
key,
|
|
@@ -6151,14 +6155,14 @@ function computeBackoffMs(attempt, policy) {
|
|
|
6151
6155
|
return capped + jitter;
|
|
6152
6156
|
}
|
|
6153
6157
|
function sleep3(ms, signal) {
|
|
6154
|
-
return new Promise((
|
|
6158
|
+
return new Promise((resolve23, reject) => {
|
|
6155
6159
|
if (signal?.aborted) {
|
|
6156
6160
|
reject(new Error("retry sleep aborted"));
|
|
6157
6161
|
return;
|
|
6158
6162
|
}
|
|
6159
6163
|
const timer = setTimeout(() => {
|
|
6160
6164
|
signal?.removeEventListener("abort", onAbort);
|
|
6161
|
-
|
|
6165
|
+
resolve23();
|
|
6162
6166
|
}, ms);
|
|
6163
6167
|
const onAbort = () => {
|
|
6164
6168
|
clearTimeout(timer);
|
|
@@ -104361,10 +104365,10 @@ var init_google_analysis3 = __esm({
|
|
|
104361
104365
|
// src/index.ts
|
|
104362
104366
|
init_dist();
|
|
104363
104367
|
init_dist();
|
|
104364
|
-
import * as
|
|
104365
|
-
import * as
|
|
104366
|
-
import { fileURLToPath as
|
|
104367
|
-
import { Command as
|
|
104368
|
+
import * as fs35 from "fs";
|
|
104369
|
+
import * as path46 from "path";
|
|
104370
|
+
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
104371
|
+
import { Command as Command6 } from "commander";
|
|
104368
104372
|
|
|
104369
104373
|
// src/commands/login/urls.ts
|
|
104370
104374
|
init_defaults();
|
|
@@ -104849,8 +104853,8 @@ function deriveWebUrl(apiBaseUrl) {
|
|
|
104849
104853
|
}
|
|
104850
104854
|
var TSO_UMI_ROUTE_PREFIX = "/v3umijs/tso";
|
|
104851
104855
|
function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
104852
|
-
const
|
|
104853
|
-
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${
|
|
104856
|
+
const path47 = tsoSubRoute.replace(/^\/+/, "");
|
|
104857
|
+
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${path47}`;
|
|
104854
104858
|
const q = new URLSearchParams({ tso: umiPath });
|
|
104855
104859
|
if (extraQuery) {
|
|
104856
104860
|
for (const [key, value] of Object.entries(extraQuery)) {
|
|
@@ -104858,7 +104862,7 @@ function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
|
104858
104862
|
if (v) q.set(key, v);
|
|
104859
104863
|
}
|
|
104860
104864
|
}
|
|
104861
|
-
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${
|
|
104865
|
+
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${path47}?${q.toString()}`;
|
|
104862
104866
|
}
|
|
104863
104867
|
function cmdConfigShow() {
|
|
104864
104868
|
const shared = readSharedConfig();
|
|
@@ -112413,7 +112417,7 @@ function cloneKeywordBlockShell(block) {
|
|
|
112413
112417
|
delete shell["matchTypeV2"];
|
|
112414
112418
|
return shell;
|
|
112415
112419
|
}
|
|
112416
|
-
function splitKeywordsForBatchJobBlockIfMixed(block,
|
|
112420
|
+
function splitKeywordsForBatchJobBlockIfMixed(block, path47, warnings) {
|
|
112417
112421
|
const declaredUi = matchTypeV2ToUi(readBlockMatchTypeRaw(block));
|
|
112418
112422
|
const entries = collectKeywordEntriesFromBlock(block);
|
|
112419
112423
|
if (entries.length === 0) return [block];
|
|
@@ -112432,7 +112436,7 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path44, warnings) {
|
|
|
112432
112436
|
(ui) => matchTypeUiToV2(ui)
|
|
112433
112437
|
);
|
|
112434
112438
|
warnings.push(
|
|
112435
|
-
`${
|
|
112439
|
+
`${path47} \u542B\u591A\u79CD\u5339\u914D\u7C7B\u578B\uFF0C\u5DF2\u81EA\u52A8\u62C6\u5206\u4E3A ${groups.size} \u4E2A KeywordsForBatchJob \u5757\uFF08${labels.join("\u3001")}\uFF09`
|
|
112436
112440
|
);
|
|
112437
112441
|
const shell = cloneKeywordBlockShell(block);
|
|
112438
112442
|
const splitBlocks = [];
|
|
@@ -112452,16 +112456,16 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path44, warnings) {
|
|
|
112452
112456
|
}
|
|
112453
112457
|
return splitBlocks;
|
|
112454
112458
|
}
|
|
112455
|
-
function validateKeywordCore(core,
|
|
112459
|
+
function validateKeywordCore(core, path47, errors, lengthViolations) {
|
|
112456
112460
|
const trimmed = core.trim();
|
|
112457
112461
|
if (!trimmed) {
|
|
112458
|
-
errors.push(`${
|
|
112462
|
+
errors.push(`${path47} \u5173\u952E\u8BCD\u8BCD\u5E72\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
112459
112463
|
return false;
|
|
112460
112464
|
}
|
|
112461
112465
|
if (trimmed.length > GOOGLE_KEYWORD_MAX_CORE_LENGTH) {
|
|
112462
112466
|
if (lengthViolations) {
|
|
112463
112467
|
pushLengthViolation(lengthViolations, {
|
|
112464
|
-
path:
|
|
112468
|
+
path: path47,
|
|
112465
112469
|
field: "KeywordText",
|
|
112466
112470
|
kind: "keyword_core",
|
|
112467
112471
|
limit: GOOGLE_KEYWORD_MAX_CORE_LENGTH,
|
|
@@ -112471,13 +112475,13 @@ function validateKeywordCore(core, path44, errors, lengthViolations) {
|
|
|
112471
112475
|
});
|
|
112472
112476
|
}
|
|
112473
112477
|
errors.push(
|
|
112474
|
-
`${
|
|
112478
|
+
`${path47} \u5173\u952E\u8BCD\u8BCD\u5E72\u8D85\u8FC7 ${GOOGLE_KEYWORD_MAX_CORE_LENGTH} \u5B57\u7B26\uFF08\u5F53\u524D ${trimmed.length}\uFF09\uFF1A"${trimmed}"`
|
|
112475
112479
|
);
|
|
112476
112480
|
return false;
|
|
112477
112481
|
}
|
|
112478
112482
|
if (!VALID_CORE_REGEX.test(trimmed)) {
|
|
112479
112483
|
errors.push(
|
|
112480
|
-
`${
|
|
112484
|
+
`${path47} \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" : ""}"`
|
|
112481
112485
|
);
|
|
112482
112486
|
return false;
|
|
112483
112487
|
}
|
|
@@ -112534,24 +112538,24 @@ function canonicalizeKeywordBatchBlock(block, resolvedMatchV2, normalizedTexts,
|
|
|
112534
112538
|
}
|
|
112535
112539
|
}
|
|
112536
112540
|
}
|
|
112537
|
-
function pushKeywordAutoFixWarning(warnings,
|
|
112541
|
+
function pushKeywordAutoFixWarning(warnings, path47, fieldLabel, trimmedRaw, formatted, declaredUi, beforeUi, matchType, inferredMatchType) {
|
|
112538
112542
|
if (inferredMatchType) {
|
|
112539
112543
|
warnings.push(
|
|
112540
|
-
`${
|
|
112544
|
+
`${path47}.${fieldLabel} \u672A\u6307\u5B9A MatchTypeV2\uFF0C\u5DF2\u6309\u8BCD\u9762\u63A8\u65AD\u4E3A ${matchTypeUiToV2(matchType)}`
|
|
112541
112545
|
);
|
|
112542
112546
|
return;
|
|
112543
112547
|
}
|
|
112544
112548
|
if (declaredUi && beforeUi !== declaredUi) {
|
|
112545
112549
|
warnings.push(
|
|
112546
|
-
`${
|
|
112550
|
+
`${path47}.${fieldLabel} MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u4E0E\u8BCD\u9762\u4E0D\u4E00\u81F4\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`
|
|
112547
112551
|
);
|
|
112548
112552
|
return;
|
|
112549
112553
|
}
|
|
112550
112554
|
if (formatted !== trimmedRaw) {
|
|
112551
|
-
warnings.push(`${
|
|
112555
|
+
warnings.push(`${path47}.${fieldLabel} \u5DF2\u81EA\u52A8\u4FEE\u590D\u8BCD\u9762\uFF1A${trimmedRaw} \u2192 ${formatted}`);
|
|
112552
112556
|
}
|
|
112553
112557
|
}
|
|
112554
|
-
function normalizeKeywordTextList(texts, matchTypeRaw,
|
|
112558
|
+
function normalizeKeywordTextList(texts, matchTypeRaw, path47, fieldLabel, errors, warnings, lengthViolations) {
|
|
112555
112559
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
112556
112560
|
const normalized = [];
|
|
112557
112561
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -112559,7 +112563,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path44, fieldLabel, error
|
|
|
112559
112563
|
for (let k = 0; k < texts.length; k++) {
|
|
112560
112564
|
const raw = texts[k];
|
|
112561
112565
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
112562
|
-
errors.push(`${
|
|
112566
|
+
errors.push(`${path47}.${fieldLabel}[${k}] \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
112563
112567
|
continue;
|
|
112564
112568
|
}
|
|
112565
112569
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -112570,7 +112574,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path44, fieldLabel, error
|
|
|
112570
112574
|
);
|
|
112571
112575
|
pushKeywordAutoFixWarning(
|
|
112572
112576
|
warnings,
|
|
112573
|
-
|
|
112577
|
+
path47,
|
|
112574
112578
|
fieldLabel,
|
|
112575
112579
|
trimmedRaw,
|
|
112576
112580
|
formatted,
|
|
@@ -112580,11 +112584,11 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path44, fieldLabel, error
|
|
|
112580
112584
|
inferredMatchType
|
|
112581
112585
|
);
|
|
112582
112586
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
112583
|
-
if (!validateKeywordCore(core, `${
|
|
112587
|
+
if (!validateKeywordCore(core, `${path47}.${fieldLabel}[${k}]`, errors, lengthViolations))
|
|
112584
112588
|
continue;
|
|
112585
112589
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
112586
112590
|
if (seen.has(dedupeKey)) {
|
|
112587
|
-
warnings.push(`${
|
|
112591
|
+
warnings.push(`${path47}.${fieldLabel}[${k}] \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
112588
112592
|
continue;
|
|
112589
112593
|
}
|
|
112590
112594
|
seen.add(dedupeKey);
|
|
@@ -112593,12 +112597,12 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path44, fieldLabel, error
|
|
|
112593
112597
|
}
|
|
112594
112598
|
return { normalized, resolvedUi };
|
|
112595
112599
|
}
|
|
112596
|
-
function normalizeKeywordsForBatchJobBlock(block,
|
|
112600
|
+
function normalizeKeywordsForBatchJobBlock(block, path47, errors, warnings, lengthViolations) {
|
|
112597
112601
|
const matchTypeRaw = readBlockMatchTypeRaw(block);
|
|
112598
112602
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
112599
112603
|
if (matchTypeRaw !== void 0 && declaredUi === null) {
|
|
112600
112604
|
errors.push(
|
|
112601
|
-
`${
|
|
112605
|
+
`${path47}.MatchTypeV2 \u65E0\u6548\uFF08${String(matchTypeRaw)}\uFF09\uFF0C\u5408\u6CD5\u503C\uFF1ABROAD | PHRASE | EXACT`
|
|
112602
112606
|
);
|
|
112603
112607
|
return;
|
|
112604
112608
|
}
|
|
@@ -112613,7 +112617,7 @@ function normalizeKeywordsForBatchJobBlock(block, path44, errors, warnings, leng
|
|
|
112613
112617
|
const result = normalizeKeywordTextList(
|
|
112614
112618
|
texts,
|
|
112615
112619
|
matchTypeRaw,
|
|
112616
|
-
|
|
112620
|
+
path47,
|
|
112617
112621
|
"KeywordText",
|
|
112618
112622
|
errors,
|
|
112619
112623
|
warnings,
|
|
@@ -112622,7 +112626,7 @@ function normalizeKeywordsForBatchJobBlock(block, path44, errors, warnings, leng
|
|
|
112622
112626
|
normalizedTexts = result.normalized;
|
|
112623
112627
|
if (result.resolvedUi) resolvedUi = result.resolvedUi;
|
|
112624
112628
|
if (normalizedTexts.length === 0 && texts.length > 0) {
|
|
112625
|
-
errors.push(`${
|
|
112629
|
+
errors.push(`${path47}.KeywordText \u7ECF\u6821\u9A8C\u540E\u65E0\u6709\u6548\u5173\u952E\u8BCD\uFF0C\u8BF7\u4FEE\u6B63\u8BCD\u9762\u6216 MatchTypeV2`);
|
|
112626
112630
|
}
|
|
112627
112631
|
}
|
|
112628
112632
|
if (hasItems && items2) {
|
|
@@ -112630,12 +112634,12 @@ function normalizeKeywordsForBatchJobBlock(block, path44, errors, warnings, leng
|
|
|
112630
112634
|
for (let k = 0; k < items2.length; k++) {
|
|
112631
112635
|
const item = items2[k];
|
|
112632
112636
|
if (!item || typeof item !== "object") {
|
|
112633
|
-
errors.push(`${
|
|
112637
|
+
errors.push(`${path47}.Items[${k}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
112634
112638
|
continue;
|
|
112635
112639
|
}
|
|
112636
112640
|
const raw = readItemText(item);
|
|
112637
112641
|
if (raw === null || !raw.trim()) {
|
|
112638
|
-
errors.push(`${
|
|
112642
|
+
errors.push(`${path47}.Items[${k}].Text \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
112639
112643
|
continue;
|
|
112640
112644
|
}
|
|
112641
112645
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -112646,7 +112650,7 @@ function normalizeKeywordsForBatchJobBlock(block, path44, errors, warnings, leng
|
|
|
112646
112650
|
);
|
|
112647
112651
|
pushKeywordAutoFixWarning(
|
|
112648
112652
|
warnings,
|
|
112649
|
-
|
|
112653
|
+
path47,
|
|
112650
112654
|
`Items[${k}].Text`,
|
|
112651
112655
|
trimmedRaw,
|
|
112652
112656
|
formatted,
|
|
@@ -112656,11 +112660,11 @@ function normalizeKeywordsForBatchJobBlock(block, path44, errors, warnings, leng
|
|
|
112656
112660
|
inferredMatchType
|
|
112657
112661
|
);
|
|
112658
112662
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
112659
|
-
if (!validateKeywordCore(core, `${
|
|
112663
|
+
if (!validateKeywordCore(core, `${path47}.Items[${k}].Text`, errors, lengthViolations))
|
|
112660
112664
|
continue;
|
|
112661
112665
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
112662
112666
|
if (seen.has(dedupeKey)) {
|
|
112663
|
-
warnings.push(`${
|
|
112667
|
+
warnings.push(`${path47}.Items[${k}].Text \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
112664
112668
|
continue;
|
|
112665
112669
|
}
|
|
112666
112670
|
seen.add(dedupeKey);
|
|
@@ -112805,16 +112809,16 @@ function warnIfNegativeKeywordsInPositiveKeywords(campaign, warnings) {
|
|
|
112805
112809
|
const raw = texts[ki];
|
|
112806
112810
|
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
112807
112811
|
const core = normalizeKeywordCoreForNegativeCheck(raw);
|
|
112808
|
-
const
|
|
112812
|
+
const path47 = `campaign.AdGroupsForBatchJob[${gi}].KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
112809
112813
|
if (plannedNegCores.has(core)) {
|
|
112810
112814
|
warnings.push(
|
|
112811
|
-
`${
|
|
112815
|
+
`${path47} \u8BCD\u9762\u300C${raw}\u300D\u5DF2\u51FA\u73B0\u5728 campaign.NegativeKeywordsForBatchJob\uFF0C\u4E0D\u5E94\u91CD\u590D\u5199\u5165\u6B63\u5411 KeywordsForBatchJob\uFF1B\u5426\u8BCD\u53EA\u653E NegativeKeywordsForBatchJob`
|
|
112812
112816
|
);
|
|
112813
112817
|
continue;
|
|
112814
112818
|
}
|
|
112815
112819
|
if (looksLikeStandaloneNegativeKeyword(core)) {
|
|
112816
112820
|
warnings.push(
|
|
112817
|
-
`${
|
|
112821
|
+
`${path47} \u8BCD\u9762\u300C${raw}\u300D\u7591\u4F3C\u5426\u5B9A\u5173\u952E\u8BCD\uFF08\u5E38\u89C1\u5426\u8BCD\u8BCD\u6839\uFF09\uFF0C\u5E94\u5199\u5165 campaign.NegativeKeywordsForBatchJob\uFF08MatchTypeV2: BROAD\uFF09\uFF0C\u52FF\u653E\u5165 KeywordsForBatchJob`
|
|
112818
112822
|
);
|
|
112819
112823
|
}
|
|
112820
112824
|
}
|
|
@@ -116445,13 +116449,13 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116445
116449
|
for (let ki = 0; ki < texts.length; ki++) {
|
|
116446
116450
|
const t = texts[ki];
|
|
116447
116451
|
if (typeof t !== "string" || !t.trim()) continue;
|
|
116448
|
-
const
|
|
116452
|
+
const path47 = `${groupPath}.KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
116449
116453
|
const key = keywordKey(t, matchTypeV2);
|
|
116450
116454
|
const plannedContent = `\u8BCD\u9762: ${t} | \u5339\u914D: ${matchTypeV2}`;
|
|
116451
116455
|
if (groupAbsent) {
|
|
116452
116456
|
pushItem(items2, {
|
|
116453
116457
|
layer: "keyword",
|
|
116454
|
-
path:
|
|
116458
|
+
path: path47,
|
|
116455
116459
|
adGroupName: groupName,
|
|
116456
116460
|
plannedContent,
|
|
116457
116461
|
status: "skipped",
|
|
@@ -116463,7 +116467,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116463
116467
|
if (!liveKwKeys.has(key)) {
|
|
116464
116468
|
pushItem(items2, {
|
|
116465
116469
|
layer: "keyword",
|
|
116466
|
-
path:
|
|
116470
|
+
path: path47,
|
|
116467
116471
|
adGroupName: groupName,
|
|
116468
116472
|
plannedContent,
|
|
116469
116473
|
status: "missing",
|
|
@@ -116473,7 +116477,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116473
116477
|
} else {
|
|
116474
116478
|
pushItem(items2, {
|
|
116475
116479
|
layer: "keyword",
|
|
116476
|
-
path:
|
|
116480
|
+
path: path47,
|
|
116477
116481
|
adGroupName: groupName,
|
|
116478
116482
|
plannedContent,
|
|
116479
116483
|
status: "ok",
|
|
@@ -116498,14 +116502,14 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116498
116502
|
for (let ai = 0; ai < ads.length; ai++) {
|
|
116499
116503
|
const ad = asRecord3(ads[ai]);
|
|
116500
116504
|
if (!ad) continue;
|
|
116501
|
-
const
|
|
116505
|
+
const path47 = `${groupPath}.AdsForBatchJob[${ai}]`;
|
|
116502
116506
|
const primary = pickString2(ad["headlinePart1"], ad["AdTitle"]);
|
|
116503
116507
|
const finalUrl = pickString2(ad["Finalurl"], ad["DestinationUrl"], ad["finalUrl"]);
|
|
116504
116508
|
const rsaAssets = listPlannedRsaAssets(ad, groupPath, ai, groupName);
|
|
116505
116509
|
if (groupAbsent) {
|
|
116506
116510
|
pushItem(items2, {
|
|
116507
116511
|
layer: "ad",
|
|
116508
|
-
path:
|
|
116512
|
+
path: path47,
|
|
116509
116513
|
adGroupName: groupName,
|
|
116510
116514
|
plannedContent: primary ? `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}` : `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF09`,
|
|
116511
116515
|
status: "skipped",
|
|
@@ -116529,7 +116533,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116529
116533
|
if (!primary) {
|
|
116530
116534
|
pushItem(items2, {
|
|
116531
116535
|
layer: "ad",
|
|
116532
|
-
path:
|
|
116536
|
+
path: path47,
|
|
116533
116537
|
adGroupName: groupName,
|
|
116534
116538
|
plannedContent: `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF0C\u65E0\u6CD5\u6BD4\u5BF9\u6574\u6761 RSA\uFF09`,
|
|
116535
116539
|
status: "missing",
|
|
@@ -116555,7 +116559,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116555
116559
|
const rsaFound = liveAdsInGroup.some((la) => liveAdHasHeadline(la, primary));
|
|
116556
116560
|
pushItem(items2, {
|
|
116557
116561
|
layer: "ad",
|
|
116558
|
-
path:
|
|
116562
|
+
path: path47,
|
|
116559
116563
|
adGroupName: groupName,
|
|
116560
116564
|
plannedContent: `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}`,
|
|
116561
116565
|
status: rsaFound ? "ok" : "missing",
|
|
@@ -116621,11 +116625,11 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116621
116625
|
for (let ei = 0; ei < extBlocks.length; ei++) {
|
|
116622
116626
|
const ext = asRecord3(extBlocks[ei]);
|
|
116623
116627
|
const plannedContent = formatExtensionPlanned(ext);
|
|
116624
|
-
const
|
|
116628
|
+
const path47 = `campaign.ExtensionsForBatchJob[${ei}]`;
|
|
116625
116629
|
if (campaignMissing) {
|
|
116626
116630
|
pushItem(items2, {
|
|
116627
116631
|
layer: "extension",
|
|
116628
|
-
path:
|
|
116632
|
+
path: path47,
|
|
116629
116633
|
plannedContent,
|
|
116630
116634
|
status: "skipped",
|
|
116631
116635
|
liveNote: "\u7CFB\u5217\u672A\u627E\u5230\uFF0C\u8DF3\u8FC7\u9644\u52A0\u4FE1\u606F\u6BD4\u5BF9",
|
|
@@ -116637,7 +116641,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116637
116641
|
const remediateCommand = !found && ext && accountId && campaignId ? buildExtensionRemediateCommandLine({ accountId, campaignId, ext }) ?? void 0 : void 0;
|
|
116638
116642
|
pushItem(items2, {
|
|
116639
116643
|
layer: "extension",
|
|
116640
|
-
path:
|
|
116644
|
+
path: path47,
|
|
116641
116645
|
plannedContent,
|
|
116642
116646
|
status: found ? "ok" : "missing",
|
|
116643
116647
|
liveNote: `\u7CFB\u5217\u7EA7\u9644\u52A0\u4FE1\u606F\u8D26\u6237\u5185 ${liveExt}/${plannedExt} \u6761`,
|
|
@@ -116664,11 +116668,11 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116664
116668
|
if (!id) continue;
|
|
116665
116669
|
const displayName = locationNames[li] || pickString2(loc["locationName"], loc["name"], loc["countryOrRegion"]) || "";
|
|
116666
116670
|
const plannedContent = `locationId: ${id}${displayName ? ` | \u540D\u79F0: ${displayName}` : ""}`;
|
|
116667
|
-
const
|
|
116671
|
+
const path47 = `campaign.targetedLocations[${li}]`;
|
|
116668
116672
|
if (campaignMissing) {
|
|
116669
116673
|
pushItem(items2, {
|
|
116670
116674
|
layer: "location",
|
|
116671
|
-
path:
|
|
116675
|
+
path: path47,
|
|
116672
116676
|
plannedContent,
|
|
116673
116677
|
status: "skipped",
|
|
116674
116678
|
liveNote: "\u7CFB\u5217\u672A\u627E\u5230\uFF0C\u8DF3\u8FC7\u5730\u57DF\u6BD4\u5BF9",
|
|
@@ -116680,7 +116684,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
116680
116684
|
const remediateCommand = !found && accountId && campaignId ? buildGeoRemediateCommandLine({ accountId, campaignId, locationId: id }) : void 0;
|
|
116681
116685
|
pushItem(items2, {
|
|
116682
116686
|
layer: "location",
|
|
116683
|
-
path:
|
|
116687
|
+
path: path47,
|
|
116684
116688
|
plannedContent,
|
|
116685
116689
|
status: found ? "ok" : "missing",
|
|
116686
116690
|
liveNote: `\u7CFB\u5217\u5DF2\u5B9A\u5411 ${liveLocIds.size}/${plannedLocCount} \u4E2A\u5730\u57DF`,
|
|
@@ -118192,8 +118196,8 @@ function pmaxChannelTypesUrl(googleApiUrl) {
|
|
|
118192
118196
|
}
|
|
118193
118197
|
function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
|
|
118194
118198
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
118195
|
-
const
|
|
118196
|
-
return campaignId ? `${
|
|
118199
|
+
const path47 = `${base}/accounts/${accountId}/campaign/pmax`;
|
|
118200
|
+
return campaignId ? `${path47}/${campaignId}` : path47;
|
|
118197
118201
|
}
|
|
118198
118202
|
function pmaxBrandAssetsUrl(googleApiUrl, accountId, campaignId) {
|
|
118199
118203
|
return `${pmaxCampaignUrl(googleApiUrl, accountId, campaignId)}/brand-assets`;
|
|
@@ -118203,8 +118207,8 @@ function pmaxBrandGuidelinesEnableUrl(googleApiUrl, accountId, campaignId) {
|
|
|
118203
118207
|
}
|
|
118204
118208
|
function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
|
|
118205
118209
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
118206
|
-
const
|
|
118207
|
-
return suffix ? `${
|
|
118210
|
+
const path47 = `${base}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
|
|
118211
|
+
return suffix ? `${path47}/${suffix.replace(/^\//, "")}` : path47;
|
|
118208
118212
|
}
|
|
118209
118213
|
function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
|
|
118210
118214
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
@@ -120945,8 +120949,8 @@ async function runAdPmaxImageConvert(opts) {
|
|
|
120945
120949
|
}
|
|
120946
120950
|
|
|
120947
120951
|
// src/commands/ad/pmax-brand-mgmt.ts
|
|
120948
|
-
function loadBrandConfig(
|
|
120949
|
-
const cfg = loadPmaxJsonFile(
|
|
120952
|
+
function loadBrandConfig(path47, accountId, campaignId) {
|
|
120953
|
+
const cfg = loadPmaxJsonFile(path47);
|
|
120950
120954
|
return {
|
|
120951
120955
|
...cfg,
|
|
120952
120956
|
account: String(cfg["account"] ?? accountId).trim(),
|
|
@@ -129664,9 +129668,9 @@ function asRecord7(value) {
|
|
|
129664
129668
|
}
|
|
129665
129669
|
return null;
|
|
129666
129670
|
}
|
|
129667
|
-
function getNestedValue(root,
|
|
129671
|
+
function getNestedValue(root, path47) {
|
|
129668
129672
|
let cur = root;
|
|
129669
|
-
for (const key of
|
|
129673
|
+
for (const key of path47) {
|
|
129670
129674
|
const rec = asRecord7(cur);
|
|
129671
129675
|
if (!rec) return void 0;
|
|
129672
129676
|
cur = rec[key];
|
|
@@ -133961,6 +133965,855 @@ function registerTikTokAnalysisCommands(program2) {
|
|
|
133961
133965
|
);
|
|
133962
133966
|
}
|
|
133963
133967
|
|
|
133968
|
+
// src/commands/yandex-analysis/register-cli.ts
|
|
133969
|
+
import { Command as Command5 } from "commander";
|
|
133970
|
+
|
|
133971
|
+
// src/commands/yandex-analysis/sections.ts
|
|
133972
|
+
var YANDEX_SECTIONS = [
|
|
133973
|
+
{
|
|
133974
|
+
name: "overview",
|
|
133975
|
+
description: "\u8D26\u6237\u603B\u89C8\uFF1A\u4F59\u989D + \u533A\u95F4\u6C47\u603B KPI",
|
|
133976
|
+
path: "overview"
|
|
133977
|
+
},
|
|
133978
|
+
{
|
|
133979
|
+
name: "daily",
|
|
133980
|
+
description: "\u6309\u65E5\u7EE9\u6548\uFF08\u53EF\u4F9B\u8C03\u7528\u65B9\u81EA\u884C\u805A\u5468\uFF09",
|
|
133981
|
+
path: "daily"
|
|
133982
|
+
},
|
|
133983
|
+
{
|
|
133984
|
+
name: "search",
|
|
133985
|
+
description: "\u7F51\u7EDC\u7EF4\u5EA6\uFF08\u4EC5 SEARCH\uFF09",
|
|
133986
|
+
path: "search"
|
|
133987
|
+
},
|
|
133988
|
+
{
|
|
133989
|
+
name: "campaigns",
|
|
133990
|
+
description: "Campaign \u7EE9\u6548 + \u9884\u7B97/\u6218\u7565/targetCpa",
|
|
133991
|
+
path: "campaigns",
|
|
133992
|
+
limitOption: true
|
|
133993
|
+
},
|
|
133994
|
+
{
|
|
133995
|
+
name: "keywords",
|
|
133996
|
+
description: "\u5173\u952E\u8BCD\uFF08Criteria\uFF09\u7EE9\u6548",
|
|
133997
|
+
path: "keywords",
|
|
133998
|
+
limitOption: true
|
|
133999
|
+
},
|
|
134000
|
+
{
|
|
134001
|
+
name: "search-terms",
|
|
134002
|
+
description: "\u641C\u7D22\u8BCD\u7EE9\u6548\uFF08Direct \u9650\u5236\uFF1A\u4EC5\u8FD1 180 \u5929\uFF09",
|
|
134003
|
+
path: "search-terms",
|
|
134004
|
+
limitOption: true,
|
|
134005
|
+
searchTermsMaxDays: 180
|
|
134006
|
+
},
|
|
134007
|
+
{
|
|
134008
|
+
name: "geo",
|
|
134009
|
+
description: "\u5730\u57DF\u7EE9\u6548\uFF08\u4EC5 SEARCH\uFF09",
|
|
134010
|
+
path: "geo",
|
|
134011
|
+
limitOption: true
|
|
134012
|
+
},
|
|
134013
|
+
{
|
|
134014
|
+
name: "devices",
|
|
134015
|
+
description: "\u8BBE\u5907\u7EE9\u6548\uFF08\u4EC5 SEARCH\uFF09",
|
|
134016
|
+
path: "devices"
|
|
134017
|
+
}
|
|
134018
|
+
];
|
|
134019
|
+
var YANDEX_SECTION_NAMES = YANDEX_SECTIONS.map((s) => s.name);
|
|
134020
|
+
var YANDEX_SECTION_ALIASES = {
|
|
134021
|
+
geographic: "geo",
|
|
134022
|
+
device: "devices",
|
|
134023
|
+
"search-queries": "search-terms"
|
|
134024
|
+
};
|
|
134025
|
+
|
|
134026
|
+
// src/commands/yandex-analysis/run-batch.ts
|
|
134027
|
+
init_auth();
|
|
134028
|
+
import * as path43 from "path";
|
|
134029
|
+
import { performance as performance8 } from "perf_hooks";
|
|
134030
|
+
init_version();
|
|
134031
|
+
|
|
134032
|
+
// src/commands/yandex-analysis/fetch.ts
|
|
134033
|
+
init_auth();
|
|
134034
|
+
var YANDEX_KEYWORD_LIMIT_DEFAULT = 100;
|
|
134035
|
+
var YANDEX_KEYWORD_LIMIT_MAX = 1e4;
|
|
134036
|
+
var YANDEX_SEARCH_TERMS_MAX_DAYS = 180;
|
|
134037
|
+
function stripLocalDate2(d) {
|
|
134038
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
134039
|
+
}
|
|
134040
|
+
function parseLocalYmd2(ymd) {
|
|
134041
|
+
const parts = ymd.trim().split("-").map((x) => parseInt(x, 10));
|
|
134042
|
+
if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {
|
|
134043
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
134044
|
+
}
|
|
134045
|
+
const [y, m, day] = parts;
|
|
134046
|
+
return new Date(y, m - 1, day);
|
|
134047
|
+
}
|
|
134048
|
+
function formatLocalYmd2(d) {
|
|
134049
|
+
const y = d.getFullYear();
|
|
134050
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
134051
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
134052
|
+
return `${y}-${m}-${day}`;
|
|
134053
|
+
}
|
|
134054
|
+
function daysInclusive(start, end) {
|
|
134055
|
+
const ms = stripLocalDate2(end).getTime() - stripLocalDate2(start).getTime();
|
|
134056
|
+
return Math.floor(ms / 864e5) + 1;
|
|
134057
|
+
}
|
|
134058
|
+
function resolveYandexDateRange(start, end) {
|
|
134059
|
+
if (start && end) {
|
|
134060
|
+
const s = parseLocalYmd2(start);
|
|
134061
|
+
const e = parseLocalYmd2(end);
|
|
134062
|
+
if (Number.isNaN(s.getTime()) || Number.isNaN(e.getTime())) {
|
|
134063
|
+
console.error("\n\u274C --start / --end \u987B\u4E3A\u6709\u6548\u65E5\u671F YYYY-MM-DD\u3002\n");
|
|
134064
|
+
process.exit(1);
|
|
134065
|
+
}
|
|
134066
|
+
if (s > e) {
|
|
134067
|
+
console.error("\n\u274C \u5F00\u59CB\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u7ED3\u675F\u65E5\u671F\u3002\n");
|
|
134068
|
+
process.exit(1);
|
|
134069
|
+
}
|
|
134070
|
+
const today = stripLocalDate2(/* @__PURE__ */ new Date());
|
|
134071
|
+
if (stripLocalDate2(s) > today || stripLocalDate2(e) > today) {
|
|
134072
|
+
console.error("\n\u274C Yandex \u62A5\u8868\u8D77\u6B62\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u4ECA\u5929\u3002\n");
|
|
134073
|
+
process.exit(1);
|
|
134074
|
+
}
|
|
134075
|
+
return { startDate: start.trim(), endDate: end.trim() };
|
|
134076
|
+
}
|
|
134077
|
+
if (!start && !end) {
|
|
134078
|
+
const endD = stripLocalDate2(/* @__PURE__ */ new Date());
|
|
134079
|
+
const startD = new Date(endD);
|
|
134080
|
+
startD.setDate(startD.getDate() - 6);
|
|
134081
|
+
return { startDate: formatLocalYmd2(startD), endDate: formatLocalYmd2(endD) };
|
|
134082
|
+
}
|
|
134083
|
+
console.error(
|
|
134084
|
+
"\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u533A\u95F4\uFF08\u8FD1 7 \u5929\uFF0C\u542B\u4ECA\u5929\uFF09\u3002\n"
|
|
134085
|
+
);
|
|
134086
|
+
process.exit(1);
|
|
134087
|
+
}
|
|
134088
|
+
function assertYandexSearchTermsRange(startDate, endDate) {
|
|
134089
|
+
const s = parseLocalYmd2(startDate);
|
|
134090
|
+
const e = parseLocalYmd2(endDate);
|
|
134091
|
+
const today = stripLocalDate2(/* @__PURE__ */ new Date());
|
|
134092
|
+
const earliest = new Date(today);
|
|
134093
|
+
earliest.setDate(earliest.getDate() - (YANDEX_SEARCH_TERMS_MAX_DAYS - 1));
|
|
134094
|
+
if (stripLocalDate2(s) < earliest || stripLocalDate2(e) > today) {
|
|
134095
|
+
console.error(
|
|
134096
|
+
`
|
|
134097
|
+
\u274C search-terms \u4EC5\u652F\u6301\u8FD1 ${YANDEX_SEARCH_TERMS_MAX_DAYS} \u5929\uFF08Direct \u9650\u5236\uFF09\u3002\u8BF7\u5C06 --start/--end \u9650\u5236\u5728 ${formatLocalYmd2(earliest)} ~ ${formatLocalYmd2(today)}\u3002
|
|
134098
|
+
`
|
|
134099
|
+
);
|
|
134100
|
+
process.exit(1);
|
|
134101
|
+
}
|
|
134102
|
+
if (daysInclusive(s, e) > YANDEX_SEARCH_TERMS_MAX_DAYS) {
|
|
134103
|
+
console.error(
|
|
134104
|
+
`
|
|
134105
|
+
\u274C search-terms \u67E5\u8BE2\u8DE8\u5EA6\u4E0D\u80FD\u8D85\u8FC7 ${YANDEX_SEARCH_TERMS_MAX_DAYS} \u5929\u3002
|
|
134106
|
+
`
|
|
134107
|
+
);
|
|
134108
|
+
process.exit(1);
|
|
134109
|
+
}
|
|
134110
|
+
}
|
|
134111
|
+
function assertYandexAccountId(id) {
|
|
134112
|
+
const t = id.trim();
|
|
134113
|
+
if (!t) {
|
|
134114
|
+
console.error("\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\uFF08Yandex Client-Login / mediaCustomerId\uFF0C\u5982 porg-xxx\uFF09\u3002\n");
|
|
134115
|
+
process.exit(1);
|
|
134116
|
+
}
|
|
134117
|
+
return t;
|
|
134118
|
+
}
|
|
134119
|
+
function requireYandexApi(config) {
|
|
134120
|
+
const base = (config.yandexApiUrl ?? "").replace(/\/$/, "");
|
|
134121
|
+
if (!base) {
|
|
134122
|
+
console.error(
|
|
134123
|
+
"\n\u274C \u672A\u627E\u5230 Yandex API \u5730\u5740\uFF08yandexApiUrl\uFF09\u3002\n \u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_YANDEX_API \u8986\u76D6\u3002\n"
|
|
134124
|
+
);
|
|
134125
|
+
process.exit(1);
|
|
134126
|
+
}
|
|
134127
|
+
return base;
|
|
134128
|
+
}
|
|
134129
|
+
function resolveYandexLimit(raw) {
|
|
134130
|
+
const n = typeof raw === "number" ? raw : parseInt(String(raw ?? ""), 10);
|
|
134131
|
+
if (!Number.isFinite(n) || n <= 0) return YANDEX_KEYWORD_LIMIT_DEFAULT;
|
|
134132
|
+
return Math.min(Math.floor(n), YANDEX_KEYWORD_LIMIT_MAX);
|
|
134133
|
+
}
|
|
134134
|
+
function analysisUrl(yandexApiUrl, pathSeg, query) {
|
|
134135
|
+
const base = yandexApiUrl.replace(/\/$/, "");
|
|
134136
|
+
const q = query ? query.startsWith("?") ? query : `?${query}` : "";
|
|
134137
|
+
return `${base}/yandex-analysis/${pathSeg}${q}`;
|
|
134138
|
+
}
|
|
134139
|
+
async function fetchYandexSectionPayload(def, opts, config, accountId) {
|
|
134140
|
+
const { startDate, endDate } = resolveYandexDateRange(opts.start, opts.end);
|
|
134141
|
+
if (def.searchTermsMaxDays) {
|
|
134142
|
+
assertYandexSearchTermsRange(startDate, endDate);
|
|
134143
|
+
}
|
|
134144
|
+
const yandexApiUrl = requireYandexApi(config);
|
|
134145
|
+
const params = new URLSearchParams({
|
|
134146
|
+
account: accountId,
|
|
134147
|
+
start: startDate,
|
|
134148
|
+
end: endDate
|
|
134149
|
+
});
|
|
134150
|
+
if (def.limitOption) {
|
|
134151
|
+
params.set("limit", String(resolveYandexLimit(opts.limit)));
|
|
134152
|
+
}
|
|
134153
|
+
const url = analysisUrl(yandexApiUrl, def.path, params.toString());
|
|
134154
|
+
return apiFetch2(url, config, {}, !!opts.verbose);
|
|
134155
|
+
}
|
|
134156
|
+
function endpointHintForYandexSection(def) {
|
|
134157
|
+
return `GET \u2026/yandex-analysis/${def.path}?account=&start=&end=`;
|
|
134158
|
+
}
|
|
134159
|
+
|
|
134160
|
+
// src/commands/yandex-analysis/resolve-sections.ts
|
|
134161
|
+
function normalizeSectionToken4(raw) {
|
|
134162
|
+
const t = raw.trim();
|
|
134163
|
+
if (!t) return null;
|
|
134164
|
+
if (YANDEX_SECTION_NAMES.includes(t)) {
|
|
134165
|
+
return t;
|
|
134166
|
+
}
|
|
134167
|
+
return YANDEX_SECTION_ALIASES[t] ?? null;
|
|
134168
|
+
}
|
|
134169
|
+
function resolveSectionList5(sections, exclude) {
|
|
134170
|
+
const splitClean = (s) => (s ?? "").split(",").map((x) => x.trim()).filter(Boolean);
|
|
134171
|
+
const include = splitClean(sections);
|
|
134172
|
+
const dropRaw = splitClean(exclude);
|
|
134173
|
+
const unknown = [...include, ...dropRaw].filter((n) => normalizeSectionToken4(n) === null);
|
|
134174
|
+
if (unknown.length > 0) {
|
|
134175
|
+
console.error(
|
|
134176
|
+
`
|
|
134177
|
+
\u274C \u672A\u77E5\u7684 section \u540D\u79F0\uFF1A${unknown.join(", ")}
|
|
134178
|
+
\u53EF\u9009\uFF1A${YANDEX_SECTION_NAMES.join(", ")}
|
|
134179
|
+
\u522B\u540D\uFF1A${Object.keys(YANDEX_SECTION_ALIASES).join(", ")}
|
|
134180
|
+
`
|
|
134181
|
+
);
|
|
134182
|
+
process.exit(1);
|
|
134183
|
+
}
|
|
134184
|
+
const includeCanonical = new Set(include.map((n) => normalizeSectionToken4(n)).filter(Boolean));
|
|
134185
|
+
const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken4(n)).filter(Boolean));
|
|
134186
|
+
const base = include.length > 0 ? YANDEX_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...YANDEX_SECTIONS];
|
|
134187
|
+
return base.filter((s) => !dropCanonical.has(s.name));
|
|
134188
|
+
}
|
|
134189
|
+
|
|
134190
|
+
// src/commands/yandex-analysis/run-batch.ts
|
|
134191
|
+
async function runWithConcurrency6(tasks, concurrency) {
|
|
134192
|
+
const results = new Array(tasks.length);
|
|
134193
|
+
let cursor = 0;
|
|
134194
|
+
const workers = new Array(Math.max(1, Math.min(concurrency, tasks.length))).fill(0).map(async () => {
|
|
134195
|
+
while (true) {
|
|
134196
|
+
const i = cursor++;
|
|
134197
|
+
if (i >= tasks.length) return;
|
|
134198
|
+
results[i] = await tasks[i]();
|
|
134199
|
+
}
|
|
134200
|
+
});
|
|
134201
|
+
await Promise.all(workers);
|
|
134202
|
+
return results;
|
|
134203
|
+
}
|
|
134204
|
+
async function runAllYandexSections(opts) {
|
|
134205
|
+
const id = assertYandexAccountId(opts.account);
|
|
134206
|
+
const config = loadConfig(opts.token);
|
|
134207
|
+
if (!opts.jsonOut?.trim()) {
|
|
134208
|
+
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");
|
|
134209
|
+
process.exit(1);
|
|
134210
|
+
}
|
|
134211
|
+
const targets = resolveSectionList5(opts.sections, opts.exclude);
|
|
134212
|
+
if (targets.length === 0) {
|
|
134213
|
+
console.error("\n\u274C \u6CA1\u6709\u8981\u6267\u884C\u7684 section\uFF08\u8BF7\u68C0\u67E5 --sections / --exclude\uFF09\u3002\n");
|
|
134214
|
+
process.exit(1);
|
|
134215
|
+
}
|
|
134216
|
+
const { startDate, endDate } = resolveYandexDateRange(opts.start, opts.end);
|
|
134217
|
+
const concurrency = Math.max(
|
|
134218
|
+
1,
|
|
134219
|
+
Math.min(typeof opts.concurrency === "number" ? opts.concurrency : 5, 16)
|
|
134220
|
+
);
|
|
134221
|
+
const cliVersion = getCurrentVersion2();
|
|
134222
|
+
const overallT0 = performance8.now();
|
|
134223
|
+
const tasks = targets.map((def) => async () => {
|
|
134224
|
+
const t0 = performance8.now();
|
|
134225
|
+
const hint = endpointHintForYandexSection(def);
|
|
134226
|
+
try {
|
|
134227
|
+
const payload = await fetchYandexSectionPayload(
|
|
134228
|
+
def,
|
|
134229
|
+
{ ...opts, start: startDate, end: endDate },
|
|
134230
|
+
config,
|
|
134231
|
+
id
|
|
134232
|
+
);
|
|
134233
|
+
const summary2 = await writeReportAnalysisSnapshot({
|
|
134234
|
+
snapshotDir: opts.jsonOut,
|
|
134235
|
+
section: def.name,
|
|
134236
|
+
accountId: id,
|
|
134237
|
+
dateRange: { start: startDate, end: endDate },
|
|
134238
|
+
payload,
|
|
134239
|
+
cliVersion
|
|
134240
|
+
});
|
|
134241
|
+
return {
|
|
134242
|
+
section: def.name,
|
|
134243
|
+
ok: true,
|
|
134244
|
+
elapsedMs: performance8.now() - t0,
|
|
134245
|
+
file: summary2.writtenFiles[0],
|
|
134246
|
+
endpointHint: hint
|
|
134247
|
+
};
|
|
134248
|
+
} catch (err) {
|
|
134249
|
+
return {
|
|
134250
|
+
section: def.name,
|
|
134251
|
+
ok: false,
|
|
134252
|
+
elapsedMs: performance8.now() - t0,
|
|
134253
|
+
error: err instanceof Error ? err.message : String(err),
|
|
134254
|
+
endpointHint: hint
|
|
134255
|
+
};
|
|
134256
|
+
}
|
|
134257
|
+
});
|
|
134258
|
+
const results = await runWithConcurrency6(tasks, concurrency);
|
|
134259
|
+
const succeeded = results.filter((r) => r.ok).length;
|
|
134260
|
+
const failed = results.length - succeeded;
|
|
134261
|
+
const absoluteSnapshotDir = path43.resolve(opts.jsonOut);
|
|
134262
|
+
const summary = {
|
|
134263
|
+
kind: "siluzan-tso-yandex-analysis-snapshot-batch",
|
|
134264
|
+
absoluteSnapshotDir,
|
|
134265
|
+
manifestFile: reportManifestFile(id),
|
|
134266
|
+
accountId: id,
|
|
134267
|
+
totalSections: results.length,
|
|
134268
|
+
succeeded,
|
|
134269
|
+
failed,
|
|
134270
|
+
concurrency,
|
|
134271
|
+
elapsedMs: performance8.now() - overallT0,
|
|
134272
|
+
results
|
|
134273
|
+
};
|
|
134274
|
+
console.log(JSON.stringify(summary));
|
|
134275
|
+
if (failed > 0) process.exit(2);
|
|
134276
|
+
}
|
|
134277
|
+
|
|
134278
|
+
// src/commands/yandex-analysis/render-report.ts
|
|
134279
|
+
import fs34 from "fs";
|
|
134280
|
+
import fsPromises7 from "fs/promises";
|
|
134281
|
+
import path45 from "path";
|
|
134282
|
+
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
134283
|
+
|
|
134284
|
+
// src/commands/yandex-analysis/merge-snapshot.ts
|
|
134285
|
+
import * as fs33 from "fs/promises";
|
|
134286
|
+
import * as path44 from "path";
|
|
134287
|
+
function asRecord26(value) {
|
|
134288
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
134289
|
+
return value;
|
|
134290
|
+
}
|
|
134291
|
+
return null;
|
|
134292
|
+
}
|
|
134293
|
+
function num10(value) {
|
|
134294
|
+
const n = Number(value);
|
|
134295
|
+
return Number.isFinite(n) ? n : void 0;
|
|
134296
|
+
}
|
|
134297
|
+
function round25(value) {
|
|
134298
|
+
return value == null ? void 0 : Math.round(value * 100) / 100;
|
|
134299
|
+
}
|
|
134300
|
+
function asItems(payload) {
|
|
134301
|
+
const obj = asRecord26(payload);
|
|
134302
|
+
if (!obj) return [];
|
|
134303
|
+
const items2 = obj.items;
|
|
134304
|
+
if (!Array.isArray(items2)) return [];
|
|
134305
|
+
return items2.filter((r) => asRecord26(r) !== null);
|
|
134306
|
+
}
|
|
134307
|
+
function pickMetrics2(row, extras = []) {
|
|
134308
|
+
const out = {
|
|
134309
|
+
spend: num10(row.spend) ?? 0,
|
|
134310
|
+
impressions: num10(row.impressions) ?? 0,
|
|
134311
|
+
clicks: num10(row.clicks) ?? 0,
|
|
134312
|
+
ctr: num10(row.ctr),
|
|
134313
|
+
averageCpc: num10(row.averageCpc),
|
|
134314
|
+
conversions: num10(row.conversions) ?? 0,
|
|
134315
|
+
conversionRate: num10(row.conversionRate),
|
|
134316
|
+
costPerConversion: num10(row.costPerConversion),
|
|
134317
|
+
roi: num10(row.roi)
|
|
134318
|
+
};
|
|
134319
|
+
for (const f of extras) {
|
|
134320
|
+
if (row[f] !== void 0 && row[f] !== null) out[f] = row[f];
|
|
134321
|
+
}
|
|
134322
|
+
return out;
|
|
134323
|
+
}
|
|
134324
|
+
async function loadSectionPayload3(snapshotDir, file) {
|
|
134325
|
+
try {
|
|
134326
|
+
const raw = await fs33.readFile(path44.join(snapshotDir, file), "utf8");
|
|
134327
|
+
return JSON.parse(raw);
|
|
134328
|
+
} catch {
|
|
134329
|
+
return null;
|
|
134330
|
+
}
|
|
134331
|
+
}
|
|
134332
|
+
async function readManifest6(snapshotDir, accountId) {
|
|
134333
|
+
const candidates = [];
|
|
134334
|
+
if (accountId) candidates.push(reportManifestFile(accountId));
|
|
134335
|
+
try {
|
|
134336
|
+
const entries = await fs33.readdir(snapshotDir);
|
|
134337
|
+
for (const name2 of entries.filter(
|
|
134338
|
+
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
134339
|
+
)) {
|
|
134340
|
+
if (!candidates.includes(name2)) candidates.push(name2);
|
|
134341
|
+
}
|
|
134342
|
+
} catch {
|
|
134343
|
+
}
|
|
134344
|
+
for (const name2 of candidates) {
|
|
134345
|
+
try {
|
|
134346
|
+
const raw = await fs33.readFile(path44.join(snapshotDir, name2), "utf8");
|
|
134347
|
+
const parsed = JSON.parse(raw);
|
|
134348
|
+
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
134349
|
+
} catch {
|
|
134350
|
+
}
|
|
134351
|
+
}
|
|
134352
|
+
return null;
|
|
134353
|
+
}
|
|
134354
|
+
function parseYmd2(value) {
|
|
134355
|
+
const s = String(value ?? "").trim().slice(0, 10);
|
|
134356
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
134357
|
+
if (!m) return null;
|
|
134358
|
+
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
134359
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
134360
|
+
}
|
|
134361
|
+
function formatYmd2(d) {
|
|
134362
|
+
const y = d.getFullYear();
|
|
134363
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
134364
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
134365
|
+
return `${y}-${m}-${day}`;
|
|
134366
|
+
}
|
|
134367
|
+
function isoWeekKey(d) {
|
|
134368
|
+
const day = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
134369
|
+
const dow = (day.getDay() + 6) % 7;
|
|
134370
|
+
const weekStart = new Date(day);
|
|
134371
|
+
weekStart.setDate(weekStart.getDate() - dow);
|
|
134372
|
+
const thursday = new Date(weekStart);
|
|
134373
|
+
thursday.setDate(thursday.getDate() + 3);
|
|
134374
|
+
const yearStart = new Date(thursday.getFullYear(), 0, 1);
|
|
134375
|
+
const week = Math.floor((thursday.getTime() - yearStart.getTime()) / 864e5 / 7) + 1;
|
|
134376
|
+
const label = `W${String(week).padStart(2, "0")}`;
|
|
134377
|
+
return { key: `${thursday.getFullYear()}-${label}`, label, weekStart };
|
|
134378
|
+
}
|
|
134379
|
+
function aggregateDailyToWeekly(dailyRows) {
|
|
134380
|
+
const map = /* @__PURE__ */ new Map();
|
|
134381
|
+
for (const row of dailyRows) {
|
|
134382
|
+
const d = parseYmd2(row.date);
|
|
134383
|
+
if (!d) continue;
|
|
134384
|
+
const { key, label, weekStart } = isoWeekKey(d);
|
|
134385
|
+
let acc = map.get(key);
|
|
134386
|
+
if (!acc) {
|
|
134387
|
+
acc = {
|
|
134388
|
+
label,
|
|
134389
|
+
weekStart,
|
|
134390
|
+
minDate: d,
|
|
134391
|
+
maxDate: d,
|
|
134392
|
+
spend: 0,
|
|
134393
|
+
impressions: 0,
|
|
134394
|
+
clicks: 0,
|
|
134395
|
+
conversions: 0
|
|
134396
|
+
};
|
|
134397
|
+
map.set(key, acc);
|
|
134398
|
+
}
|
|
134399
|
+
if (d < acc.minDate) acc.minDate = d;
|
|
134400
|
+
if (d > acc.maxDate) acc.maxDate = d;
|
|
134401
|
+
acc.spend += num10(row.spend) ?? 0;
|
|
134402
|
+
acc.impressions += num10(row.impressions) ?? 0;
|
|
134403
|
+
acc.clicks += num10(row.clicks) ?? 0;
|
|
134404
|
+
acc.conversions += num10(row.conversions) ?? 0;
|
|
134405
|
+
}
|
|
134406
|
+
return [...map.values()].sort((a, b) => a.weekStart.getTime() - b.weekStart.getTime()).map((acc) => {
|
|
134407
|
+
const days = Math.floor((acc.maxDate.getTime() - acc.minDate.getTime()) / 864e5) + 1;
|
|
134408
|
+
return {
|
|
134409
|
+
weekLabel: acc.label,
|
|
134410
|
+
startDate: formatYmd2(acc.minDate),
|
|
134411
|
+
endDate: formatYmd2(acc.maxDate),
|
|
134412
|
+
days,
|
|
134413
|
+
spend: round25(acc.spend),
|
|
134414
|
+
impressions: Math.round(acc.impressions),
|
|
134415
|
+
clicks: Math.round(acc.clicks),
|
|
134416
|
+
conversions: round25(acc.conversions),
|
|
134417
|
+
ctr: acc.impressions > 0 ? acc.clicks / acc.impressions : void 0,
|
|
134418
|
+
averageCpc: acc.clicks > 0 ? round25(acc.spend / acc.clicks) : void 0,
|
|
134419
|
+
costPerConversion: acc.conversions > 0 ? round25(acc.spend / acc.conversions) : void 0
|
|
134420
|
+
};
|
|
134421
|
+
});
|
|
134422
|
+
}
|
|
134423
|
+
function mapDailyRows(payload) {
|
|
134424
|
+
return asItems(payload).map((r) => {
|
|
134425
|
+
const dateRaw = r.date;
|
|
134426
|
+
const date = typeof dateRaw === "string" ? dateRaw.slice(0, 10) : dateRaw != null ? String(dateRaw).slice(0, 10) : "";
|
|
134427
|
+
return pickMetrics2({ ...r, date }, ["date"]);
|
|
134428
|
+
});
|
|
134429
|
+
}
|
|
134430
|
+
function mapSearchRows(payload) {
|
|
134431
|
+
return asItems(payload).map((r) => pickMetrics2(r, ["network"]));
|
|
134432
|
+
}
|
|
134433
|
+
function mapCampaignRows2(payload) {
|
|
134434
|
+
return asItems(payload).map(
|
|
134435
|
+
(r) => pickMetrics2(r, [
|
|
134436
|
+
"campaignId",
|
|
134437
|
+
"campaignName",
|
|
134438
|
+
"status",
|
|
134439
|
+
"state",
|
|
134440
|
+
"campaignType",
|
|
134441
|
+
"budget",
|
|
134442
|
+
"strategy",
|
|
134443
|
+
"targetCpa",
|
|
134444
|
+
"network"
|
|
134445
|
+
])
|
|
134446
|
+
);
|
|
134447
|
+
}
|
|
134448
|
+
function mapKeywordRows2(payload) {
|
|
134449
|
+
return asItems(payload).map(
|
|
134450
|
+
(r) => pickMetrics2(r, [
|
|
134451
|
+
"campaignId",
|
|
134452
|
+
"campaignName",
|
|
134453
|
+
"adGroupId",
|
|
134454
|
+
"keyword",
|
|
134455
|
+
"criteriaType",
|
|
134456
|
+
"network"
|
|
134457
|
+
])
|
|
134458
|
+
);
|
|
134459
|
+
}
|
|
134460
|
+
function mapSearchTermRows2(payload) {
|
|
134461
|
+
return asItems(payload).map(
|
|
134462
|
+
(r) => pickMetrics2(r, [
|
|
134463
|
+
"searchQuery",
|
|
134464
|
+
"matchedKeyword",
|
|
134465
|
+
"campaignId",
|
|
134466
|
+
"campaignName",
|
|
134467
|
+
"adGroupId"
|
|
134468
|
+
])
|
|
134469
|
+
);
|
|
134470
|
+
}
|
|
134471
|
+
function mapGeoRows(payload) {
|
|
134472
|
+
return asItems(payload).map(
|
|
134473
|
+
(r) => pickMetrics2(r, ["locationName", "targetingLocationName", "network"])
|
|
134474
|
+
);
|
|
134475
|
+
}
|
|
134476
|
+
function mapDeviceRows2(payload) {
|
|
134477
|
+
return asItems(payload).map((r) => pickMetrics2(r, ["device", "network"]));
|
|
134478
|
+
}
|
|
134479
|
+
async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
134480
|
+
const absDir = path44.resolve(snapshotDir);
|
|
134481
|
+
const metaAccountId = typeof asRecord26(payload.meta)?.accountId === "string" ? asRecord26(payload.meta)?.accountId : void 0;
|
|
134482
|
+
const manifest = await readManifest6(snapshotDir, metaAccountId);
|
|
134483
|
+
if (!manifest) {
|
|
134484
|
+
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C yandex-analysis --json-out`);
|
|
134485
|
+
}
|
|
134486
|
+
const sectionMap = /* @__PURE__ */ new Map();
|
|
134487
|
+
for (const art of manifest.artifacts ?? []) {
|
|
134488
|
+
const data = await loadSectionPayload3(absDir, art.file);
|
|
134489
|
+
if (data != null) sectionMap.set(art.section, data);
|
|
134490
|
+
}
|
|
134491
|
+
const overview = asRecord26(sectionMap.get("overview"));
|
|
134492
|
+
const totals = asRecord26(overview?.totals);
|
|
134493
|
+
const accountId = manifest.accountId ?? metaAccountId;
|
|
134494
|
+
const meta = { ...payload.meta ?? {} };
|
|
134495
|
+
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
134496
|
+
if (!meta.currency && typeof overview?.currency === "string") meta.currency = overview.currency;
|
|
134497
|
+
if (!meta.startDate && manifest.dateRange) meta.startDate = manifest.dateRange.start;
|
|
134498
|
+
if (!meta.endDate && manifest.dateRange) meta.endDate = manifest.dateRange.end;
|
|
134499
|
+
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
134500
|
+
if (!meta.platform) meta.platform = "Yandex Direct";
|
|
134501
|
+
const kpis = { ...payload.kpis ?? {} };
|
|
134502
|
+
if (totals) {
|
|
134503
|
+
if (num10(totals.spend) != null) kpis.spend = round25(num10(totals.spend));
|
|
134504
|
+
if (num10(totals.impressions) != null) kpis.impressions = Math.round(num10(totals.impressions));
|
|
134505
|
+
if (num10(totals.clicks) != null) kpis.clicks = Math.round(num10(totals.clicks));
|
|
134506
|
+
if (num10(totals.conversions) != null) kpis.conversions = round25(num10(totals.conversions));
|
|
134507
|
+
if (num10(totals.ctr) != null) kpis.ctr = num10(totals.ctr);
|
|
134508
|
+
if (num10(totals.averageCpc) != null) kpis.averageCpc = round25(num10(totals.averageCpc));
|
|
134509
|
+
if (num10(totals.costPerConversion) != null) {
|
|
134510
|
+
kpis.costPerConversion = round25(num10(totals.costPerConversion));
|
|
134511
|
+
}
|
|
134512
|
+
if (num10(totals.conversionRate) != null) kpis.conversionRate = num10(totals.conversionRate);
|
|
134513
|
+
if (num10(totals.roi) != null) kpis.roi = num10(totals.roi);
|
|
134514
|
+
}
|
|
134515
|
+
if (overview) {
|
|
134516
|
+
if (num10(overview.balance) != null) kpis.balance = round25(num10(overview.balance));
|
|
134517
|
+
if (num10(overview.avgDailySpend) != null) kpis.avgDailySpend = round25(num10(overview.avgDailySpend));
|
|
134518
|
+
if (num10(overview.activeDays) != null) kpis.activeDays = num10(overview.activeDays);
|
|
134519
|
+
if (overview.balanceAsOf != null) kpis.balanceAsOf = overview.balanceAsOf;
|
|
134520
|
+
}
|
|
134521
|
+
if (kpis.balance != null && kpis.avgDailySpend != null && Number(kpis.avgDailySpend) > 0) {
|
|
134522
|
+
kpis.runwayDays = Math.round(Number(kpis.balance) / Number(kpis.avgDailySpend));
|
|
134523
|
+
}
|
|
134524
|
+
const tables = { ...payload.tables ?? {} };
|
|
134525
|
+
const dailyRows = mapDailyRows(sectionMap.get("daily"));
|
|
134526
|
+
if (dailyRows.length > 0) {
|
|
134527
|
+
tables.daily = dailyRows;
|
|
134528
|
+
tables.weekly = aggregateDailyToWeekly(dailyRows);
|
|
134529
|
+
}
|
|
134530
|
+
{
|
|
134531
|
+
const rows = mapSearchRows(sectionMap.get("search"));
|
|
134532
|
+
if (rows.length > 0) tables.search = rows;
|
|
134533
|
+
}
|
|
134534
|
+
{
|
|
134535
|
+
const rows = mapCampaignRows2(sectionMap.get("campaigns"));
|
|
134536
|
+
if (rows.length > 0) tables.campaigns = rows;
|
|
134537
|
+
}
|
|
134538
|
+
{
|
|
134539
|
+
const rows = mapKeywordRows2(sectionMap.get("keywords"));
|
|
134540
|
+
if (rows.length > 0) tables.keywords = rows;
|
|
134541
|
+
}
|
|
134542
|
+
{
|
|
134543
|
+
const rows = mapSearchTermRows2(sectionMap.get("search-terms"));
|
|
134544
|
+
if (rows.length > 0) tables.searchTerms = rows;
|
|
134545
|
+
}
|
|
134546
|
+
{
|
|
134547
|
+
const rows = mapGeoRows(sectionMap.get("geo"));
|
|
134548
|
+
if (rows.length > 0) tables.geo = rows;
|
|
134549
|
+
}
|
|
134550
|
+
{
|
|
134551
|
+
const rows = mapDeviceRows2(sectionMap.get("devices"));
|
|
134552
|
+
if (rows.length > 0) tables.devices = rows;
|
|
134553
|
+
}
|
|
134554
|
+
return { ...payload, meta, kpis, tables };
|
|
134555
|
+
}
|
|
134556
|
+
|
|
134557
|
+
// src/commands/yandex-analysis/report-content.ts
|
|
134558
|
+
var SECTION_KEYS4 = [
|
|
134559
|
+
"overview",
|
|
134560
|
+
"search",
|
|
134561
|
+
"campaigns",
|
|
134562
|
+
"keywords",
|
|
134563
|
+
"searchTerms",
|
|
134564
|
+
"geo",
|
|
134565
|
+
"devices",
|
|
134566
|
+
"daily"
|
|
134567
|
+
];
|
|
134568
|
+
var SECTION_LABELS5 = {
|
|
134569
|
+
overview: "\u2460\u8D26\u6237\u603B\u89C8",
|
|
134570
|
+
search: "\u2461Search \u7F51\u7EDC",
|
|
134571
|
+
campaigns: "\u2462Campaign",
|
|
134572
|
+
keywords: "\u2463\u5173\u952E\u8BCD",
|
|
134573
|
+
searchTerms: "\u2464\u641C\u7D22\u8BCD",
|
|
134574
|
+
geo: "\u2465\u5730\u57DF",
|
|
134575
|
+
devices: "\u2466\u8BBE\u5907",
|
|
134576
|
+
daily: "\u2467\u65E5\u671F/\u5468\u62A5"
|
|
134577
|
+
};
|
|
134578
|
+
function textLen7(value) {
|
|
134579
|
+
return typeof value === "string" ? value.trim().length : 0;
|
|
134580
|
+
}
|
|
134581
|
+
function asArray7(value) {
|
|
134582
|
+
return Array.isArray(value) ? value : [];
|
|
134583
|
+
}
|
|
134584
|
+
function asRecord27(value) {
|
|
134585
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
134586
|
+
return value;
|
|
134587
|
+
}
|
|
134588
|
+
return null;
|
|
134589
|
+
}
|
|
134590
|
+
function pushMissing6(missing, id, chapter, dimension, hint) {
|
|
134591
|
+
missing.push({ id, chapter, dimension, hint });
|
|
134592
|
+
}
|
|
134593
|
+
function validateYandexPeriodReportContent(data) {
|
|
134594
|
+
const missing = [];
|
|
134595
|
+
const meta = asRecord27(data.meta) ?? {};
|
|
134596
|
+
const narrative = asRecord27(data.narrative) ?? {};
|
|
134597
|
+
const sections = asRecord27(narrative.sections) ?? {};
|
|
134598
|
+
const kpis = asRecord27(data.kpis) ?? {};
|
|
134599
|
+
if (!textLen7(meta.accountId)) {
|
|
134600
|
+
pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
|
|
134601
|
+
}
|
|
134602
|
+
const executiveSummary = asArray7(narrative.executiveSummary).filter((p) => textLen7(p) > 0);
|
|
134603
|
+
if (executiveSummary.length < 1) {
|
|
134604
|
+
pushMissing6(
|
|
134605
|
+
missing,
|
|
134606
|
+
"narrative-executive-summary",
|
|
134607
|
+
"\u6267\u884C\u6458\u8981",
|
|
134608
|
+
"narrative.executiveSummary",
|
|
134609
|
+
"\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u70B9\u51FB/\u8F6C\u5316/CTR/CPC \u8D70\u52BF"
|
|
134610
|
+
);
|
|
134611
|
+
}
|
|
134612
|
+
const sectionAnalysisCounts = {};
|
|
134613
|
+
const sectionSuggestionCounts = {};
|
|
134614
|
+
for (const key of SECTION_KEYS4) {
|
|
134615
|
+
const section = asRecord27(sections[key]);
|
|
134616
|
+
const analysis = asArray7(section?.analysis).filter((s) => textLen7(s) > 0);
|
|
134617
|
+
const suggestions = asArray7(section?.suggestions).filter((s) => textLen7(s) > 0);
|
|
134618
|
+
sectionAnalysisCounts[key] = analysis.length;
|
|
134619
|
+
sectionSuggestionCounts[key] = suggestions.length;
|
|
134620
|
+
if (analysis.length < 1) {
|
|
134621
|
+
pushMissing6(
|
|
134622
|
+
missing,
|
|
134623
|
+
`section-${key}-analysis`,
|
|
134624
|
+
SECTION_LABELS5[key],
|
|
134625
|
+
`narrative.sections.${key}.analysis`,
|
|
134626
|
+
`\u22651 \u6761\u603B\u7ED3\uFF08\u5F53\u524D ${analysis.length} \u6761\uFF09\uFF0C\u987B\u5199\u6E05\u73B0\u8C61+\u4F9D\u636E\u6570\u5B57`
|
|
134627
|
+
);
|
|
134628
|
+
}
|
|
134629
|
+
if (suggestions.length < 1) {
|
|
134630
|
+
pushMissing6(
|
|
134631
|
+
missing,
|
|
134632
|
+
`section-${key}-suggestions`,
|
|
134633
|
+
SECTION_LABELS5[key],
|
|
134634
|
+
`narrative.sections.${key}.suggestions`,
|
|
134635
|
+
`\u22651 \u6761\u53EF\u6267\u884C\u5EFA\u8BAE\uFF08\u5F53\u524D ${suggestions.length} \u6761\uFF09`
|
|
134636
|
+
);
|
|
134637
|
+
}
|
|
134638
|
+
}
|
|
134639
|
+
const recommendations = asArray7(narrative.recommendations).filter((r) => {
|
|
134640
|
+
if (typeof r === "string") return textLen7(r) > 0;
|
|
134641
|
+
const rec = asRecord27(r);
|
|
134642
|
+
return textLen7(rec?.content) > 0 || textLen7(rec?.text) > 0;
|
|
134643
|
+
});
|
|
134644
|
+
if (recommendations.length < 3) {
|
|
134645
|
+
pushMissing6(
|
|
134646
|
+
missing,
|
|
134647
|
+
"narrative-recommendations",
|
|
134648
|
+
"\u540E\u7EED\u4F18\u5316\u52A8\u4F5C",
|
|
134649
|
+
"narrative.recommendations",
|
|
134650
|
+
`\u22653 \u6761\u8DE8\u7EF4\u5EA6\u4F18\u5316\u5EFA\u8BAE\uFF08\u5F53\u524D ${recommendations.length} \u6761\uFF1B\u53EF\u7528 {priority,text,anchor}\uFF09`
|
|
134651
|
+
);
|
|
134652
|
+
}
|
|
134653
|
+
const hasKpi = Number.isFinite(Number(kpis.spend)) || Number.isFinite(Number(kpis.clicks)) || Number.isFinite(Number(kpis.impressions));
|
|
134654
|
+
if (!hasKpi) {
|
|
134655
|
+
pushMissing6(
|
|
134656
|
+
missing,
|
|
134657
|
+
"kpis-core",
|
|
134658
|
+
"KPI",
|
|
134659
|
+
"kpis.spend|clicks|impressions",
|
|
134660
|
+
"\u81F3\u5C11\u4E00\u9879\u6709\u6548\u6570\u5B57\uFF08\u8BF7\u4F20 --snapshot-dir \u7531 CLI \u4ECE overview \u5408\u5E76\uFF09"
|
|
134661
|
+
);
|
|
134662
|
+
}
|
|
134663
|
+
return {
|
|
134664
|
+
ok: missing.length === 0,
|
|
134665
|
+
missing,
|
|
134666
|
+
stats: {
|
|
134667
|
+
executiveSummaryCount: executiveSummary.length,
|
|
134668
|
+
recommendationCount: recommendations.length,
|
|
134669
|
+
sectionAnalysisCounts,
|
|
134670
|
+
sectionSuggestionCounts
|
|
134671
|
+
}
|
|
134672
|
+
};
|
|
134673
|
+
}
|
|
134674
|
+
function formatYandexPeriodReportErrors(result) {
|
|
134675
|
+
if (result.ok) return "";
|
|
134676
|
+
const lines = result.missing.map((m) => ` - [${m.chapter}] ${m.dimension}\uFF1A${m.hint}`);
|
|
134677
|
+
return [
|
|
134678
|
+
`\u62A5\u544A JSON \u7F3A\u5C11 ${result.missing.length} \u9879\u5FC5\u542B\u5185\u5BB9\uFF08\u5BF9\u9F50 yandex-period-report.md\uFF09\uFF1A`,
|
|
134679
|
+
...lines,
|
|
134680
|
+
"",
|
|
134681
|
+
"\u8BF7\u8865\u5168 narrative.sections.<dimension>.{analysis,suggestions} \u4E0E narrative.recommendations \u540E\u91CD\u65B0\u6267\u884C render\u3002",
|
|
134682
|
+
"\u6570\u503C\u7C7B\u5B57\u6BB5\uFF08kpis/tables\uFF09\u987B\u7531 --snapshot-dir \u4ECE\u843D\u76D8 JSON \u5408\u5E76\uFF1BAgent \u53EA\u64B0\u5199\u53D9\u4E8B\uFF0C\u7981\u6B62\u624B\u5199 HTML\u3002"
|
|
134683
|
+
].join("\n");
|
|
134684
|
+
}
|
|
134685
|
+
|
|
134686
|
+
// src/commands/yandex-analysis/render-report.ts
|
|
134687
|
+
var TEMPLATE_BASENAME5 = "yandex-period-report.html";
|
|
134688
|
+
var INJECT_MARKER6 = "window.__YANDEX_PERIOD_REPORT__ = window.__YANDEX_PERIOD_REPORT__ || null;";
|
|
134689
|
+
function resolveSkillTemplatePath8(basename11) {
|
|
134690
|
+
const dir = path45.dirname(fileURLToPath11(import.meta.url));
|
|
134691
|
+
const candidates = [
|
|
134692
|
+
path45.join(dir, "skill", "report-templates", basename11),
|
|
134693
|
+
path45.join(dir, "skill", "siluzan-ads", "report-templates", basename11),
|
|
134694
|
+
path45.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename11)
|
|
134695
|
+
];
|
|
134696
|
+
for (const p of candidates) {
|
|
134697
|
+
if (fs34.existsSync(p)) return p;
|
|
134698
|
+
}
|
|
134699
|
+
return candidates[0];
|
|
134700
|
+
}
|
|
134701
|
+
function yandexPeriodReportTemplatePath() {
|
|
134702
|
+
return resolveSkillTemplatePath8(TEMPLATE_BASENAME5);
|
|
134703
|
+
}
|
|
134704
|
+
async function readJsonFile7(filePath) {
|
|
134705
|
+
const text = await fsPromises7.readFile(filePath, "utf8");
|
|
134706
|
+
try {
|
|
134707
|
+
return JSON.parse(text);
|
|
134708
|
+
} catch {
|
|
134709
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
134710
|
+
}
|
|
134711
|
+
}
|
|
134712
|
+
function asRecord28(value) {
|
|
134713
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
134714
|
+
return value;
|
|
134715
|
+
}
|
|
134716
|
+
throw new Error("\u62A5\u544A\u6570\u636E\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
134717
|
+
}
|
|
134718
|
+
function injectReportData7(html, payload) {
|
|
134719
|
+
const json = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
134720
|
+
if (!html.includes(INJECT_MARKER6)) {
|
|
134721
|
+
throw new Error("\u62A5\u544A\u6A21\u677F\u7F3A\u5C11\u6570\u636E\u6CE8\u5165\u951A\u70B9\uFF0C\u8BF7\u66F4\u65B0 yandex-period-report.html");
|
|
134722
|
+
}
|
|
134723
|
+
return html.replace(INJECT_MARKER6, `window.__YANDEX_PERIOD_REPORT__ = ${json};`);
|
|
134724
|
+
}
|
|
134725
|
+
async function runYandexAnalysisRender(opts) {
|
|
134726
|
+
const dataPath = path45.resolve(opts.dataFile);
|
|
134727
|
+
let data = asRecord28(await readJsonFile7(dataPath));
|
|
134728
|
+
if (opts.snapshotDir?.trim()) {
|
|
134729
|
+
data = await mergeYandexAnalysisSnapshotIntoReport(data, path45.resolve(opts.snapshotDir));
|
|
134730
|
+
}
|
|
134731
|
+
const contentCheck = validateYandexPeriodReportContent(data);
|
|
134732
|
+
if (!contentCheck.ok) {
|
|
134733
|
+
console.error(`
|
|
134734
|
+
\u274C ${formatYandexPeriodReportErrors(contentCheck)}
|
|
134735
|
+
`);
|
|
134736
|
+
const { stats: stats2 } = contentCheck;
|
|
134737
|
+
const sectionSummary = Object.entries(stats2.sectionAnalysisCounts).map(([key, count]) => `${key} \u603B\u7ED3${count}/\u5EFA\u8BAE${stats2.sectionSuggestionCounts[key] ?? 0}`).join("\uFF5C");
|
|
134738
|
+
console.error(
|
|
134739
|
+
` \u7EDF\u8BA1\uFF1A\u6267\u884C\u6458\u8981 ${stats2.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats2.recommendationCount} \u6761\uFF5C${sectionSummary}
|
|
134740
|
+
`
|
|
134741
|
+
);
|
|
134742
|
+
process.exit(1);
|
|
134743
|
+
}
|
|
134744
|
+
const templatePath = yandexPeriodReportTemplatePath();
|
|
134745
|
+
let html;
|
|
134746
|
+
try {
|
|
134747
|
+
html = await fsPromises7.readFile(templatePath, "utf8");
|
|
134748
|
+
} catch {
|
|
134749
|
+
console.error(`
|
|
134750
|
+
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
134751
|
+
\u8BF7\u5148\u6267\u884C npm run build
|
|
134752
|
+
`);
|
|
134753
|
+
process.exit(1);
|
|
134754
|
+
}
|
|
134755
|
+
const outPath = path45.resolve(
|
|
134756
|
+
opts.out ?? path45.join(path45.dirname(dataPath), "yandex-period-report.html")
|
|
134757
|
+
);
|
|
134758
|
+
const outDir = path45.dirname(outPath);
|
|
134759
|
+
await fsPromises7.mkdir(outDir, { recursive: true });
|
|
134760
|
+
await fsPromises7.writeFile(outPath, injectReportData7(html, data), "utf8");
|
|
134761
|
+
const { stats } = contentCheck;
|
|
134762
|
+
console.log(`
|
|
134763
|
+
\u2705 Yandex \u5E7F\u544A\u8D26\u6237\u5206\u6790 HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
134764
|
+
`);
|
|
134765
|
+
console.log(
|
|
134766
|
+
` \u5FC5\u542B\u5B57\u6BB5\u5DF2\u5168\u90E8\u8986\u76D6\uFF5C\u6267\u884C\u6458\u8981 ${stats.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats.recommendationCount} \u6761\uFF5C8 \u4E2A\u5206\u6790\u7AE0\u8282\u5747\u5DF2\u9F50\u5168
|
|
134767
|
+
`
|
|
134768
|
+
);
|
|
134769
|
+
console.log("\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 HTML \u6587\u4EF6\u5373\u53EF\u67E5\u770B\u5B8C\u6574\u7AE0\u8282\uFF08\u6837\u5F0F\u5BF9\u9F50\u5F00\u53D1\u6837\u4F8B\uFF09\u3002\n");
|
|
134770
|
+
}
|
|
134771
|
+
|
|
134772
|
+
// src/commands/yandex-analysis/register-cli.ts
|
|
134773
|
+
function registerBatchCommand4(sectionHelp, aliasHelp) {
|
|
134774
|
+
return new Command5("run").description(
|
|
134775
|
+
"\u6279\u91CF\u62C9\u53D6 YandexAPI /yandex-analysis \u5404\u7EF4\u5EA6\uFF08\u7701\u7565\u5B50\u547D\u4EE4\u540D\u65F6\u9ED8\u8BA4\u6267\u884C\u672C\u547D\u4EE4\uFF09"
|
|
134776
|
+
).requiredOption(
|
|
134777
|
+
"-a, --account <id>",
|
|
134778
|
+
"Yandex Client-Login / mediaCustomerId\uFF08\u5982 porg-xxx\uFF0C\u4E0E list-accounts -m Yandex \u4E00\u81F4\uFF09"
|
|
134779
|
+
).requiredOption(
|
|
134780
|
+
"--json-out <dir>",
|
|
134781
|
+
"\u7ED3\u679C\u843D\u76D8\u76EE\u5F55\uFF1B\u6BCF\u7EF4\u5EA6 `<section>-<accountId>.json` + `report-manifest-<accountId>.json`"
|
|
134782
|
+
).option("-t, --token <token>", "Auth Token").option(
|
|
134783
|
+
"--start <date>",
|
|
134784
|
+
"\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF1B\u4E0D\u80FD\u665A\u4E8E\u4ECA\u5929\uFF1B\u9ED8\u8BA4\u8FD1 7 \u5929\u542B\u4ECA\u5929\uFF09"
|
|
134785
|
+
).option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
|
|
134786
|
+
"--sections <list>",
|
|
134787
|
+
`\u4EC5\u6267\u884C\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u5982 overview,campaigns,keywords\uFF1B\u7701\u7565=\u5168\u90E8 8 \u4E2A\u3002\u53EF\u9009\uFF1A${sectionHelp}\uFF1B\u522B\u540D\uFF1A${aliasHelp}`
|
|
134788
|
+
).option("--exclude <list>", "\u6392\u9664\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0E --sections \u53EF\u53E0\u52A0").option(
|
|
134789
|
+
"--limit <n>",
|
|
134790
|
+
"\u4EC5 campaigns / keywords / search-terms / geo\uFF1A\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF0C\u6700\u5927 10000\uFF09",
|
|
134791
|
+
(v) => parseInt(v, 10)
|
|
134792
|
+
).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) => {
|
|
134793
|
+
await runAllYandexSections(opts);
|
|
134794
|
+
});
|
|
134795
|
+
}
|
|
134796
|
+
function registerYandexAnalysisCommands(program2) {
|
|
134797
|
+
const sectionHelp = YANDEX_SECTION_NAMES.join(", ");
|
|
134798
|
+
const aliasHelp = Object.keys(YANDEX_SECTION_ALIASES).join(", ");
|
|
134799
|
+
const root = program2.command("yandex-analysis").description(
|
|
134800
|
+
"Yandex \u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6 /yandex-analysis \u53EA\u8BFB\u6570\u636E\uFF08\u9ED8\u8BA4 run\uFF09\uFF0C\u6216\u7531 render \u751F\u6210 yandex-period-report.html \u7EC8\u7A3F\uFF08\u91D1\u989D\u5DF2\u4E3A\u8D26\u6237\u5E01\u79CD\u5C0F\u6570\uFF1Bsearch-terms \u4EC5\u8FD1 180 \u5929\uFF09"
|
|
134801
|
+
);
|
|
134802
|
+
root.addCommand(registerBatchCommand4(sectionHelp, aliasHelp), { isDefault: true });
|
|
134803
|
+
root.command("render").description(
|
|
134804
|
+
"\u6839\u636E Agent \u64B0\u5199\u7684\u62A5\u544A JSON \u751F\u6210 Yandex \u5E7F\u544A\u8D26\u6237\u5206\u6790 HTML \u7EC8\u7A3F\uFF08\u6821\u9A8C 8 \u4E2A\u5206\u6790\u7AE0\u8282\u5FC5\u542B\u5B57\u6BB5\uFF0C\u7F3A\u9879\u62D2\u7EDD\u6E32\u67D3\uFF09"
|
|
134805
|
+
).requiredOption("--data <file>", "Agent \u4EA7\u51FA\u7684 yandex-period-report.json").option(
|
|
134806
|
+
"--snapshot-dir <dir>",
|
|
134807
|
+
"\u53EF\u9009\uFF1Ayandex-analysis --json-out \u76EE\u5F55\uFF0C\u81EA\u52A8\u8865\u5168 meta / kpis / tables"
|
|
134808
|
+
).option("--out <file>", "\u8F93\u51FA HTML \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\uFF09").action(async (opts) => {
|
|
134809
|
+
await runYandexAnalysisRender({
|
|
134810
|
+
dataFile: opts.data,
|
|
134811
|
+
snapshotDir: opts.snapshotDir,
|
|
134812
|
+
out: opts.out
|
|
134813
|
+
});
|
|
134814
|
+
});
|
|
134815
|
+
}
|
|
134816
|
+
|
|
133964
134817
|
// src/index.ts
|
|
133965
134818
|
init_version();
|
|
133966
134819
|
init_cli_json_snapshot();
|
|
@@ -134035,9 +134888,9 @@ function interceptAgentCompatArgv(argv) {
|
|
|
134035
134888
|
installProcessHandlers();
|
|
134036
134889
|
function getVersion() {
|
|
134037
134890
|
try {
|
|
134038
|
-
const __dirname3 =
|
|
134039
|
-
const pkgPath =
|
|
134040
|
-
const pkg = JSON.parse(
|
|
134891
|
+
const __dirname3 = path46.dirname(fileURLToPath12(import.meta.url));
|
|
134892
|
+
const pkgPath = path46.join(__dirname3, "..", "package.json");
|
|
134893
|
+
const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf8"));
|
|
134041
134894
|
return pkg.version ?? "0.0.0";
|
|
134042
134895
|
} catch {
|
|
134043
134896
|
return "0.0.0";
|
|
@@ -134056,9 +134909,9 @@ configureCliJsonSnapshot({
|
|
|
134056
134909
|
]
|
|
134057
134910
|
});
|
|
134058
134911
|
configureSiluzanClientIdentity({ client: "tso-cli", resolveVersion: getVersion });
|
|
134059
|
-
var program = new
|
|
134912
|
+
var program = new Command6();
|
|
134060
134913
|
program.name("siluzan-tso").description(
|
|
134061
|
-
"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\
|
|
134914
|
+
"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/Meta/TikTok/Bing/Yandex \u8D26\u6237\u5206\u6790\u3001Google \u5E7F\u544A\u8BCA\u65AD\u62A5\u544A\uFF08google-ads-diagnosis render\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"
|
|
134062
134915
|
).version(getVersion());
|
|
134063
134916
|
program.option("--commit <text>", "\u5199\u64CD\u4F5C\u8BF4\u660E\uFF1B\u8BB0\u5165\u672C\u673A\u5199\u5BA1\u8BA1 JSONL");
|
|
134064
134917
|
program.hook("preAction", async () => {
|
|
@@ -134093,6 +134946,7 @@ var REGISTRARS = [
|
|
|
134093
134946
|
registerFacebookAnalysisCommands,
|
|
134094
134947
|
registerBingAnalysisCommands,
|
|
134095
134948
|
registerTikTokAnalysisCommands,
|
|
134949
|
+
registerYandexAnalysisCommands,
|
|
134096
134950
|
register15,
|
|
134097
134951
|
register16,
|
|
134098
134952
|
register17,
|