siluzan-tso-cli 1.1.64-beta.2 → 1.1.64-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +689 -561
- package/dist/skill/SKILL.md +3 -2
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +1 -0
- package/dist/skill/references/analytics/account-analytics.md +2 -0
- package/dist/skill/references/core/intent-routing.md +5 -2
- package/dist/skill/references/core/playbooks.md +17 -0
- package/dist/skill/references/google-ads/demand-gen-api.md +1 -1
- package/dist/skill/references/report-templates/README.md +2 -0
- package/dist/skill/references/report-templates/REPORT-WORKFLOW.md +5 -2
- package/dist/skill/references/report-templates/demand-gen-analysis-report-excel.md +122 -0
- package/dist/skill/references/report-templates/demand-gen-analysis-report.md +166 -0
- package/dist/skill/report-templates/README.md +2 -0
- package/dist/skill/report-templates/REPORT-WORKFLOW.md +5 -2
- package/dist/skill/report-templates/demand-gen-analysis-report-excel.md +122 -0
- package/dist/skill/report-templates/demand-gen-analysis-report.html +402 -0
- package/dist/skill/report-templates/demand-gen-analysis-report.md +166 -0
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2172,8 +2172,8 @@ function jsonParseReviverStringifyIds(key, value) {
|
|
|
2172
2172
|
}
|
|
2173
2173
|
return value;
|
|
2174
2174
|
}
|
|
2175
|
-
function parseJsonWithStringIds(
|
|
2176
|
-
return JSON.parse(
|
|
2175
|
+
function parseJsonWithStringIds(text4) {
|
|
2176
|
+
return JSON.parse(text4, jsonParseReviverStringifyIds);
|
|
2177
2177
|
}
|
|
2178
2178
|
function hasSiluzanAgentCredentials() {
|
|
2179
2179
|
const apiKey = process.env.SILUZAN_API_KEY?.trim();
|
|
@@ -2414,7 +2414,7 @@ function rawRequest(url, options) {
|
|
|
2414
2414
|
});
|
|
2415
2415
|
stream.on("end", () => {
|
|
2416
2416
|
if (failed) return;
|
|
2417
|
-
const
|
|
2417
|
+
const text4 = Buffer.concat(chunks).toString("utf8");
|
|
2418
2418
|
const responseHeaders = {};
|
|
2419
2419
|
for (const [key, val] of Object.entries(res.headers)) {
|
|
2420
2420
|
if (val !== void 0) {
|
|
@@ -2432,7 +2432,7 @@ function rawRequest(url, options) {
|
|
|
2432
2432
|
ok: status >= 200 && status < 300
|
|
2433
2433
|
});
|
|
2434
2434
|
}
|
|
2435
|
-
resolve52({ status, text:
|
|
2435
|
+
resolve52({ status, text: text4, headers: responseHeaders });
|
|
2436
2436
|
});
|
|
2437
2437
|
});
|
|
2438
2438
|
req.on("timeout", () => {
|
|
@@ -2483,8 +2483,8 @@ function redactSensitive(input) {
|
|
|
2483
2483
|
);
|
|
2484
2484
|
return output;
|
|
2485
2485
|
}
|
|
2486
|
-
function trimDetail(
|
|
2487
|
-
const t =
|
|
2486
|
+
function trimDetail(text4, maxLen) {
|
|
2487
|
+
const t = text4.trim();
|
|
2488
2488
|
if (t.length <= maxLen) return t;
|
|
2489
2489
|
return `${t.slice(0, maxLen)}\u2026`;
|
|
2490
2490
|
}
|
|
@@ -2530,25 +2530,25 @@ function messageFromJsonValue(value) {
|
|
|
2530
2530
|
return void 0;
|
|
2531
2531
|
}
|
|
2532
2532
|
function extractHttpErrorDetail(rawBody) {
|
|
2533
|
-
const
|
|
2534
|
-
if (!
|
|
2535
|
-
if (
|
|
2533
|
+
const text4 = rawBody?.trim();
|
|
2534
|
+
if (!text4) return void 0;
|
|
2535
|
+
if (text4.startsWith('"')) {
|
|
2536
2536
|
try {
|
|
2537
|
-
const parsed = JSON.parse(
|
|
2537
|
+
const parsed = JSON.parse(text4);
|
|
2538
2538
|
if (typeof parsed === "string" && parsed.trim()) return parsed.trim();
|
|
2539
2539
|
} catch {
|
|
2540
2540
|
}
|
|
2541
2541
|
}
|
|
2542
|
-
if (
|
|
2542
|
+
if (text4.startsWith("{") || text4.startsWith("[")) {
|
|
2543
2543
|
try {
|
|
2544
|
-
const parsed = JSON.parse(
|
|
2544
|
+
const parsed = JSON.parse(text4);
|
|
2545
2545
|
const msg = messageFromJsonValue(parsed);
|
|
2546
2546
|
if (msg) return msg;
|
|
2547
2547
|
} catch {
|
|
2548
2548
|
}
|
|
2549
2549
|
}
|
|
2550
|
-
if (
|
|
2551
|
-
return
|
|
2550
|
+
if (text4.startsWith("<")) return void 0;
|
|
2551
|
+
return text4;
|
|
2552
2552
|
}
|
|
2553
2553
|
function formatHttpError(status, rawBody, opts) {
|
|
2554
2554
|
const verbose = opts?.verbose === true;
|
|
@@ -2565,20 +2565,20 @@ function formatHttpError(status, rawBody, opts) {
|
|
|
2565
2565
|
function buildAuthHeaders(config) {
|
|
2566
2566
|
return buildSiluzanAuthHeaders(config);
|
|
2567
2567
|
}
|
|
2568
|
-
async function parseApiResponse(status,
|
|
2568
|
+
async function parseApiResponse(status, text4, verbose) {
|
|
2569
2569
|
if (status < 200 || status >= 300) {
|
|
2570
|
-
const err = new Error(formatHttpError(status,
|
|
2571
|
-
Object.assign(err, { status, rawBody:
|
|
2570
|
+
const err = new Error(formatHttpError(status, text4, { verbose }));
|
|
2571
|
+
Object.assign(err, { status, rawBody: text4 });
|
|
2572
2572
|
throw err;
|
|
2573
2573
|
}
|
|
2574
|
-
if (!
|
|
2574
|
+
if (!text4.trim()) return null;
|
|
2575
2575
|
try {
|
|
2576
|
-
return parseJsonWithStringIds(
|
|
2576
|
+
return parseJsonWithStringIds(text4);
|
|
2577
2577
|
} catch {
|
|
2578
2578
|
if (verbose) {
|
|
2579
|
-
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(
|
|
2579
|
+
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text4).slice(0, 200)}`);
|
|
2580
2580
|
}
|
|
2581
|
-
return
|
|
2581
|
+
return text4;
|
|
2582
2582
|
}
|
|
2583
2583
|
}
|
|
2584
2584
|
function isTransientNetworkError(err) {
|
|
@@ -2634,18 +2634,18 @@ async function apiFetchWithHeaders(url, config, options = {}, verbose = false) {
|
|
|
2634
2634
|
};
|
|
2635
2635
|
const body = typeof options.body === "string" ? options.body : void 0;
|
|
2636
2636
|
const res = await requestWithReadRetry(url, { method, headers: reqHeaders, body });
|
|
2637
|
-
const
|
|
2637
|
+
const text4 = res.text;
|
|
2638
2638
|
if (res.status < 200 || res.status >= 300) {
|
|
2639
|
-
throw new Error(formatHttpError(res.status,
|
|
2639
|
+
throw new Error(formatHttpError(res.status, text4, { verbose }));
|
|
2640
2640
|
}
|
|
2641
2641
|
let data;
|
|
2642
|
-
if (!
|
|
2642
|
+
if (!text4.trim()) {
|
|
2643
2643
|
data = null;
|
|
2644
2644
|
} else {
|
|
2645
2645
|
try {
|
|
2646
|
-
data = parseJsonWithStringIds(
|
|
2646
|
+
data = parseJsonWithStringIds(text4);
|
|
2647
2647
|
} catch {
|
|
2648
|
-
data =
|
|
2648
|
+
data = text4;
|
|
2649
2649
|
}
|
|
2650
2650
|
}
|
|
2651
2651
|
return { data, headers: res.headers };
|
|
@@ -3247,9 +3247,9 @@ function pickCompanyId(data) {
|
|
|
3247
3247
|
}
|
|
3248
3248
|
return void 0;
|
|
3249
3249
|
}
|
|
3250
|
-
function parseMeResponse(
|
|
3250
|
+
function parseMeResponse(text4) {
|
|
3251
3251
|
try {
|
|
3252
|
-
const json = JSON.parse(
|
|
3252
|
+
const json = JSON.parse(text4);
|
|
3253
3253
|
const data = json?.data && typeof json.data === "object" ? json.data : json;
|
|
3254
3254
|
const id = pickStr(data, "entityId") ?? pickStr(data, "id") ?? pickStr(data, "userId") ?? pickStr(data, "accountId");
|
|
3255
3255
|
const email = pickStr(data, "email");
|
|
@@ -4395,12 +4395,12 @@ async function apiDeleteRaw(url, config, options = {}) {
|
|
|
4395
4395
|
if (res.status < 200 || res.status >= 300) {
|
|
4396
4396
|
throw new Error(formatHttpError(res.status, res.text, { verbose: options.verbose }));
|
|
4397
4397
|
}
|
|
4398
|
-
const
|
|
4399
|
-
const value = !
|
|
4398
|
+
const text4 = res.text;
|
|
4399
|
+
const value = !text4.trim() ? null : (() => {
|
|
4400
4400
|
try {
|
|
4401
|
-
return JSON.parse(
|
|
4401
|
+
return JSON.parse(text4);
|
|
4402
4402
|
} catch {
|
|
4403
|
-
return
|
|
4403
|
+
return text4;
|
|
4404
4404
|
}
|
|
4405
4405
|
})();
|
|
4406
4406
|
return { value, httpStatus: res.status };
|
|
@@ -5497,13 +5497,13 @@ function skippedNoSpendCampaignTypes() {
|
|
|
5497
5497
|
};
|
|
5498
5498
|
}
|
|
5499
5499
|
function errorCampaignTypes(message) {
|
|
5500
|
-
const
|
|
5500
|
+
const text4 = message.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
5501
5501
|
return {
|
|
5502
5502
|
campaignTypesStatus: "error",
|
|
5503
5503
|
campaignTypes: null,
|
|
5504
5504
|
hasDisplay: null,
|
|
5505
5505
|
hasPmax: null,
|
|
5506
|
-
campaignTypesError:
|
|
5506
|
+
campaignTypesError: text4 || "unknown error"
|
|
5507
5507
|
};
|
|
5508
5508
|
}
|
|
5509
5509
|
function errorMessage(err) {
|
|
@@ -5565,8 +5565,8 @@ function negativeKeywordSlimListUrl(googleApiUrl, accountId, query) {
|
|
|
5565
5565
|
if (query?.appliedLevel) params.set("appliedlevel", query.appliedLevel);
|
|
5566
5566
|
if (query?.readDeleted) params.set("readDeleted", "true");
|
|
5567
5567
|
if (query?.excludePaused) params.set("excludePaused", "true");
|
|
5568
|
-
const
|
|
5569
|
-
if (
|
|
5568
|
+
const text4 = query?.keywordText?.trim();
|
|
5569
|
+
if (text4) params.set("keywordtext", text4);
|
|
5570
5570
|
if (query?.matchType) params.set("matchtype", query.matchType);
|
|
5571
5571
|
const qs = params.toString();
|
|
5572
5572
|
return `${googleApiUrl}/negativekeywordmanagement/v2/list/${accountId}/slim${qs ? `?${qs}` : ""}`;
|
|
@@ -6837,8 +6837,8 @@ function relLuminance(hex) {
|
|
|
6837
6837
|
function textColorFor(bgHex) {
|
|
6838
6838
|
return relLuminance(bgHex) > 0.55 ? NEUTRAL.textDark : NEUTRAL.white;
|
|
6839
6839
|
}
|
|
6840
|
-
function xmlEscape(
|
|
6841
|
-
return
|
|
6840
|
+
function xmlEscape(text4) {
|
|
6841
|
+
return text4.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6842
6842
|
}
|
|
6843
6843
|
function colLetter(index) {
|
|
6844
6844
|
let n = index + 1;
|
|
@@ -6960,8 +6960,8 @@ function sheetRelsXml(sheet) {
|
|
|
6960
6960
|
).join("");
|
|
6961
6961
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${rels}</Relationships>`;
|
|
6962
6962
|
}
|
|
6963
|
-
function estimateWrapHeight(
|
|
6964
|
-
const str3 = String(
|
|
6963
|
+
function estimateWrapHeight(text4, colWidthChars) {
|
|
6964
|
+
const str3 = String(text4 ?? "");
|
|
6965
6965
|
if (!str3) return void 0;
|
|
6966
6966
|
const lines = str3.split("\n").reduce((sum, line) => {
|
|
6967
6967
|
const width = Math.max(colWidthChars || 20, 8);
|
|
@@ -7109,7 +7109,7 @@ var init_xlsx_style_engine = __esm({
|
|
|
7109
7109
|
for (let i = 0; i < n; i++) this.pushRow([]);
|
|
7110
7110
|
return this;
|
|
7111
7111
|
}
|
|
7112
|
-
titleBar(
|
|
7112
|
+
titleBar(text4, opts = {}) {
|
|
7113
7113
|
const fill = opts.fill === null ? void 0 : opts.fill ?? NEUTRAL.titleFill;
|
|
7114
7114
|
const fontColor = opts.fontColor ?? (fill ? textColorFor(fill) : NEUTRAL.textDark);
|
|
7115
7115
|
const s = this.registry.resolve({
|
|
@@ -7120,22 +7120,22 @@ var init_xlsx_style_engine = __esm({
|
|
|
7120
7120
|
border: opts.border ?? false,
|
|
7121
7121
|
hAlign: opts.hAlign ?? "left"
|
|
7122
7122
|
});
|
|
7123
|
-
this.pushRow([{ value:
|
|
7123
|
+
this.pushRow([{ value: text4, styleId: s }], { height: 28 });
|
|
7124
7124
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
7125
7125
|
return this;
|
|
7126
7126
|
}
|
|
7127
|
-
subtitleBar(
|
|
7127
|
+
subtitleBar(text4, opts = {}) {
|
|
7128
7128
|
const s = this.registry.resolve({
|
|
7129
7129
|
fontSize: 10.5,
|
|
7130
7130
|
fontColor: NEUTRAL.subtitleText,
|
|
7131
7131
|
fill: NEUTRAL.subtitleFill,
|
|
7132
7132
|
border: false
|
|
7133
7133
|
});
|
|
7134
|
-
this.pushRow([{ value:
|
|
7134
|
+
this.pushRow([{ value: text4, styleId: s }], { height: 20 });
|
|
7135
7135
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
7136
7136
|
return this;
|
|
7137
7137
|
}
|
|
7138
|
-
sectionBar(
|
|
7138
|
+
sectionBar(text4, opts = {}) {
|
|
7139
7139
|
const fill = opts.fill ?? this.accentHex;
|
|
7140
7140
|
const s = this.registry.resolve({
|
|
7141
7141
|
fontSize: 11,
|
|
@@ -7145,11 +7145,11 @@ var init_xlsx_style_engine = __esm({
|
|
|
7145
7145
|
border: false,
|
|
7146
7146
|
hAlign: "center"
|
|
7147
7147
|
});
|
|
7148
|
-
this.pushRow([{ value:
|
|
7148
|
+
this.pushRow([{ value: text4, styleId: s }], { height: 22 });
|
|
7149
7149
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
7150
7150
|
return this;
|
|
7151
7151
|
}
|
|
7152
|
-
noteRow(
|
|
7152
|
+
noteRow(text4, span) {
|
|
7153
7153
|
const s = this.registry.resolve({
|
|
7154
7154
|
fontSize: 9,
|
|
7155
7155
|
fontColor: NEUTRAL.textMuted,
|
|
@@ -7157,8 +7157,8 @@ var init_xlsx_style_engine = __esm({
|
|
|
7157
7157
|
border: true,
|
|
7158
7158
|
vAlign: "top"
|
|
7159
7159
|
});
|
|
7160
|
-
const height = estimateWrapHeight(
|
|
7161
|
-
this.pushRow([{ value:
|
|
7160
|
+
const height = estimateWrapHeight(text4, this.colWidths.reduce((a, b) => a + b, 0) || 60);
|
|
7161
|
+
this.pushRow([{ value: text4, styleId: s }], { height });
|
|
7162
7162
|
this.mergeCurrentRow(span || this.colCount);
|
|
7163
7163
|
return this;
|
|
7164
7164
|
}
|
|
@@ -104178,6 +104178,121 @@ var init_fetch = __esm({
|
|
|
104178
104178
|
}
|
|
104179
104179
|
});
|
|
104180
104180
|
|
|
104181
|
+
// src/commands/google-analysis/demand-gen-report-content.ts
|
|
104182
|
+
function isRecord4(value) {
|
|
104183
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
104184
|
+
}
|
|
104185
|
+
function text3(value) {
|
|
104186
|
+
return typeof value === "string" ? value.trim() : "";
|
|
104187
|
+
}
|
|
104188
|
+
function asDemandGenReport(value) {
|
|
104189
|
+
if (!isRecord4(value)) throw new Error("\u62A5\u544A\u6570\u636E\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
104190
|
+
return value;
|
|
104191
|
+
}
|
|
104192
|
+
function validateDemandGenReport(payload) {
|
|
104193
|
+
const errors = [];
|
|
104194
|
+
const meta = payload.meta;
|
|
104195
|
+
const narrative = payload.narrative;
|
|
104196
|
+
if (!meta || !narrative) {
|
|
104197
|
+
return { ok: false, errors: ["JSON \u987B\u542B meta \u4E0E narrative"] };
|
|
104198
|
+
}
|
|
104199
|
+
if (!text3(meta.accountId)) errors.push("meta.accountId \u5FC5\u586B");
|
|
104200
|
+
if (!text3(meta.currency)) errors.push("meta.currency \u5FC5\u586B");
|
|
104201
|
+
if (!text3(meta.startDate) || !text3(meta.endDate)) errors.push("meta.startDate / meta.endDate \u5FC5\u586B");
|
|
104202
|
+
if (!text3(narrative.headline)) errors.push("narrative.headline \u5FC5\u586B");
|
|
104203
|
+
const kpiCount = (narrative.headlineKpis?.length ?? 0) + (narrative.kpiGroups ?? []).reduce((sum, group) => sum + (group.items?.length ?? 0), 0);
|
|
104204
|
+
if (kpiCount < 1) errors.push("\u81F3\u5C11 1 \u4E2A\u6838\u5FC3\u6307\u6807\uFF08headlineKpis \u6216 kpiGroups\uFF09");
|
|
104205
|
+
if ((narrative.funnel?.stages?.length ?? 0) < 1) errors.push("narrative.funnel.stages \u81F3\u5C11 1 \u7EA7");
|
|
104206
|
+
if ((narrative.dimensions?.length ?? 0) < 1) errors.push("narrative.dimensions \u81F3\u5C11 1 \u4E2A\u7EF4\u5EA6");
|
|
104207
|
+
if ((narrative.actions?.length ?? 0) < 1) errors.push("narrative.actions \u81F3\u5C11 1 \u6761");
|
|
104208
|
+
if ((narrative.tests?.length ?? 0) < 1) errors.push("narrative.tests \u81F3\u5C11 1 \u6761");
|
|
104209
|
+
for (const dimension of narrative.dimensions ?? []) {
|
|
104210
|
+
if (!text3(dimension.title)) errors.push("\u7EF4\u5EA6\u7F3A\u5C11 title");
|
|
104211
|
+
if (!dimension.columns?.length) errors.push(`\u7EF4\u5EA6\u300C${dimension.title || "\u672A\u547D\u540D"}\u300D\u7F3A\u5C11 columns`);
|
|
104212
|
+
}
|
|
104213
|
+
return { ok: errors.length === 0, errors };
|
|
104214
|
+
}
|
|
104215
|
+
function formatDemandGenReportErrors(check) {
|
|
104216
|
+
return check.errors.map((item) => `- ${item}`).join("\n");
|
|
104217
|
+
}
|
|
104218
|
+
var init_demand_gen_report_content = __esm({
|
|
104219
|
+
"src/commands/google-analysis/demand-gen-report-content.ts"() {
|
|
104220
|
+
"use strict";
|
|
104221
|
+
}
|
|
104222
|
+
});
|
|
104223
|
+
|
|
104224
|
+
// src/commands/google-analysis/demand-gen-render.ts
|
|
104225
|
+
import fs28 from "fs";
|
|
104226
|
+
import fsPromises2 from "fs/promises";
|
|
104227
|
+
import path33 from "path";
|
|
104228
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
104229
|
+
function resolveSkillTemplatePath3(basename13) {
|
|
104230
|
+
const dir = path33.dirname(fileURLToPath9(import.meta.url));
|
|
104231
|
+
const candidates = [
|
|
104232
|
+
path33.join(dir, "skill", "report-templates", basename13),
|
|
104233
|
+
path33.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
104234
|
+
path33.join(dir, "..", "..", "..", "assets", "siluzan-ads", "report-templates", basename13),
|
|
104235
|
+
path33.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
104236
|
+
];
|
|
104237
|
+
for (const candidate of candidates) {
|
|
104238
|
+
if (fs28.existsSync(candidate)) return candidate;
|
|
104239
|
+
}
|
|
104240
|
+
return path33.join(dir, "skill", "report-templates", basename13);
|
|
104241
|
+
}
|
|
104242
|
+
function demandGenReportTemplatePath() {
|
|
104243
|
+
return resolveSkillTemplatePath3(TEMPLATE_BASENAME);
|
|
104244
|
+
}
|
|
104245
|
+
async function readJsonFile2(filePath) {
|
|
104246
|
+
const text4 = await fsPromises2.readFile(filePath, "utf8");
|
|
104247
|
+
try {
|
|
104248
|
+
return JSON.parse(text4);
|
|
104249
|
+
} catch {
|
|
104250
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
104251
|
+
}
|
|
104252
|
+
}
|
|
104253
|
+
function injectDemandGenReport(html, payload) {
|
|
104254
|
+
if (!html.includes(DEMAND_GEN_INJECT_MARKER)) {
|
|
104255
|
+
throw new Error("\u62A5\u544A\u6A21\u677F\u7F3A\u5C11\u6570\u636E\u6CE8\u5165\u951A\u70B9\uFF0C\u8BF7\u66F4\u65B0 demand-gen-analysis-report.html");
|
|
104256
|
+
}
|
|
104257
|
+
const json = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
104258
|
+
return html.replace(DEMAND_GEN_INJECT_MARKER, `window.__DEMAND_GEN_REPORT__ = ${json};`);
|
|
104259
|
+
}
|
|
104260
|
+
async function runDemandGenRender(opts) {
|
|
104261
|
+
const dataPath = path33.resolve(opts.dataFile);
|
|
104262
|
+
const data = asDemandGenReport(await readJsonFile2(dataPath));
|
|
104263
|
+
if (opts.lang?.trim()) data.meta.lang = opts.lang.trim();
|
|
104264
|
+
const check = validateDemandGenReport(data);
|
|
104265
|
+
if (!check.ok) {
|
|
104266
|
+
throw new Error(`Demand Gen \u62A5\u544A\u7F3A\u5FC5\u586B\u5185\u5BB9\uFF1A
|
|
104267
|
+
${formatDemandGenReportErrors(check)}`);
|
|
104268
|
+
}
|
|
104269
|
+
const templatePath = demandGenReportTemplatePath();
|
|
104270
|
+
let html;
|
|
104271
|
+
try {
|
|
104272
|
+
html = await fsPromises2.readFile(templatePath, "utf8");
|
|
104273
|
+
} catch {
|
|
104274
|
+
throw new Error(`\u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}\u3002\u8BF7\u5148\u6267\u884C npm run build`);
|
|
104275
|
+
}
|
|
104276
|
+
const outPath = path33.resolve(
|
|
104277
|
+
opts.out ?? path33.join(path33.dirname(dataPath), "demand-gen-analysis-report.html")
|
|
104278
|
+
);
|
|
104279
|
+
await fsPromises2.mkdir(path33.dirname(outPath), { recursive: true });
|
|
104280
|
+
await fsPromises2.writeFile(outPath, injectDemandGenReport(html, data), "utf8");
|
|
104281
|
+
console.log(`
|
|
104282
|
+
\u2705 Demand Gen \u6295\u653E\u6570\u636E\u5206\u6790 HTML \u5DF2\u751F\u6210\uFF1A${outPath}
|
|
104283
|
+
`);
|
|
104284
|
+
return outPath;
|
|
104285
|
+
}
|
|
104286
|
+
var TEMPLATE_BASENAME, DEMAND_GEN_INJECT_MARKER;
|
|
104287
|
+
var init_demand_gen_render = __esm({
|
|
104288
|
+
"src/commands/google-analysis/demand-gen-render.ts"() {
|
|
104289
|
+
"use strict";
|
|
104290
|
+
init_demand_gen_report_content();
|
|
104291
|
+
TEMPLATE_BASENAME = "demand-gen-analysis-report.html";
|
|
104292
|
+
DEMAND_GEN_INJECT_MARKER = "window.__DEMAND_GEN_REPORT__ = window.__DEMAND_GEN_REPORT__ || null;";
|
|
104293
|
+
}
|
|
104294
|
+
});
|
|
104295
|
+
|
|
104181
104296
|
// src/commands/google-analysis/okki-display.ts
|
|
104182
104297
|
function num3(value) {
|
|
104183
104298
|
const n = typeof value === "number" ? value : Number(value);
|
|
@@ -104267,8 +104382,8 @@ function summarizeOkkiDeviceSpend(rows) {
|
|
|
104267
104382
|
otherConversions: conv.other
|
|
104268
104383
|
};
|
|
104269
104384
|
}
|
|
104270
|
-
function narrativeClaimsMobileSpendLeads(
|
|
104271
|
-
const t =
|
|
104385
|
+
function narrativeClaimsMobileSpendLeads(text4) {
|
|
104386
|
+
const t = text4.replace(/\s+/g, "");
|
|
104272
104387
|
if (!t.includes("\u79FB\u52A8")) return false;
|
|
104273
104388
|
return /移动(?:端|设备)?(?:为|是)主要消耗/.test(t) || /移动(?:端|设备)?为主要(?:消耗)?设备/.test(t) || /移动(?:端|设备)?(?:消耗|花费|费用|流量)?占比高/.test(t);
|
|
104274
104389
|
}
|
|
@@ -104304,8 +104419,8 @@ var init_okki_display = __esm({
|
|
|
104304
104419
|
});
|
|
104305
104420
|
|
|
104306
104421
|
// src/commands/google-analysis/merge-snapshot.ts
|
|
104307
|
-
import * as
|
|
104308
|
-
import * as
|
|
104422
|
+
import * as fs29 from "fs/promises";
|
|
104423
|
+
import * as path34 from "path";
|
|
104309
104424
|
function asRecord21(value) {
|
|
104310
104425
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
104311
104426
|
return value;
|
|
@@ -104323,7 +104438,7 @@ async function readManifest(snapshotDir, accountId) {
|
|
|
104323
104438
|
const candidates = [];
|
|
104324
104439
|
if (accountId) candidates.push(googleAnalysisManifestFile(accountId));
|
|
104325
104440
|
try {
|
|
104326
|
-
const entries = await
|
|
104441
|
+
const entries = await fs29.readdir(snapshotDir);
|
|
104327
104442
|
const manifestNames = entries.filter((n) => n.startsWith("manifest") && n.endsWith(".json"));
|
|
104328
104443
|
for (const name2 of manifestNames) {
|
|
104329
104444
|
if (!candidates.includes(name2)) candidates.push(name2);
|
|
@@ -104332,7 +104447,7 @@ async function readManifest(snapshotDir, accountId) {
|
|
|
104332
104447
|
}
|
|
104333
104448
|
for (const name2 of candidates) {
|
|
104334
104449
|
try {
|
|
104335
|
-
const raw = await
|
|
104450
|
+
const raw = await fs29.readFile(path34.join(snapshotDir, name2), "utf8");
|
|
104336
104451
|
const parsed = JSON.parse(raw);
|
|
104337
104452
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
104338
104453
|
} catch {
|
|
@@ -104342,7 +104457,7 @@ async function readManifest(snapshotDir, accountId) {
|
|
|
104342
104457
|
}
|
|
104343
104458
|
async function loadSectionFile(snapshotDir, file) {
|
|
104344
104459
|
try {
|
|
104345
|
-
const raw = await
|
|
104460
|
+
const raw = await fs29.readFile(path34.join(snapshotDir, file), "utf8");
|
|
104346
104461
|
const parsed = JSON.parse(raw);
|
|
104347
104462
|
if (parsed && typeof parsed === "object") return parsed;
|
|
104348
104463
|
return null;
|
|
@@ -104351,12 +104466,12 @@ async function loadSectionFile(snapshotDir, file) {
|
|
|
104351
104466
|
}
|
|
104352
104467
|
}
|
|
104353
104468
|
function negativeKeywordText(row) {
|
|
104354
|
-
const
|
|
104355
|
-
if (Array.isArray(
|
|
104356
|
-
const parts =
|
|
104469
|
+
const text4 = row.keywordText;
|
|
104470
|
+
if (Array.isArray(text4)) {
|
|
104471
|
+
const parts = text4.map((part) => String(part).trim()).filter(Boolean);
|
|
104357
104472
|
if (parts.length > 0) return parts.join(", ");
|
|
104358
104473
|
}
|
|
104359
|
-
if (typeof
|
|
104474
|
+
if (typeof text4 === "string" && text4.trim()) return text4.trim();
|
|
104360
104475
|
if (typeof row.keyword === "string" && row.keyword.trim()) return row.keyword.trim();
|
|
104361
104476
|
return "\u2014";
|
|
104362
104477
|
}
|
|
@@ -104411,7 +104526,7 @@ async function recoverMissingReportSections(sectionMap, absDir, accountId, prefe
|
|
|
104411
104526
|
if (!accountId) return;
|
|
104412
104527
|
let entries;
|
|
104413
104528
|
try {
|
|
104414
|
-
entries = await
|
|
104529
|
+
entries = await fs29.readdir(absDir);
|
|
104415
104530
|
} catch {
|
|
104416
104531
|
return;
|
|
104417
104532
|
}
|
|
@@ -104483,7 +104598,7 @@ function sumCampaignRowsToPeriodKpis(rows) {
|
|
|
104483
104598
|
};
|
|
104484
104599
|
}
|
|
104485
104600
|
async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
104486
|
-
const absDir =
|
|
104601
|
+
const absDir = path34.resolve(snapshotDir);
|
|
104487
104602
|
const metaAccountId = typeof asRecord21(payload.meta)?.accountId === "string" ? asRecord21(payload.meta)?.accountId : void 0;
|
|
104488
104603
|
const manifest = await readManifest(snapshotDir, metaAccountId);
|
|
104489
104604
|
if (!manifest) {
|
|
@@ -104839,8 +104954,8 @@ var init_okki_report_content = __esm({
|
|
|
104839
104954
|
});
|
|
104840
104955
|
|
|
104841
104956
|
// src/commands/google-analysis/okki-merge-snapshot.ts
|
|
104842
|
-
import * as
|
|
104843
|
-
import * as
|
|
104957
|
+
import * as fs30 from "fs/promises";
|
|
104958
|
+
import * as path35 from "path";
|
|
104844
104959
|
function num5(value) {
|
|
104845
104960
|
const n = Number(value);
|
|
104846
104961
|
return Number.isFinite(n) ? n : void 0;
|
|
@@ -104866,7 +104981,7 @@ async function readManifest2(snapshotDir, accountId) {
|
|
|
104866
104981
|
const candidates = [];
|
|
104867
104982
|
if (accountId) candidates.push(googleAnalysisManifestFile(accountId));
|
|
104868
104983
|
try {
|
|
104869
|
-
const entries = await
|
|
104984
|
+
const entries = await fs30.readdir(snapshotDir);
|
|
104870
104985
|
for (const name2 of entries.filter((n) => n.startsWith("manifest") && n.endsWith(".json"))) {
|
|
104871
104986
|
if (!candidates.includes(name2)) candidates.push(name2);
|
|
104872
104987
|
}
|
|
@@ -104874,7 +104989,7 @@ async function readManifest2(snapshotDir, accountId) {
|
|
|
104874
104989
|
}
|
|
104875
104990
|
for (const name2 of candidates) {
|
|
104876
104991
|
try {
|
|
104877
|
-
const raw = await
|
|
104992
|
+
const raw = await fs30.readFile(path35.join(snapshotDir, name2), "utf8");
|
|
104878
104993
|
const parsed = JSON.parse(raw);
|
|
104879
104994
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
104880
104995
|
} catch {
|
|
@@ -104884,7 +104999,7 @@ async function readManifest2(snapshotDir, accountId) {
|
|
|
104884
104999
|
}
|
|
104885
105000
|
async function loadSectionFile2(snapshotDir, file) {
|
|
104886
105001
|
try {
|
|
104887
|
-
const raw = await
|
|
105002
|
+
const raw = await fs30.readFile(path35.join(snapshotDir, file), "utf8");
|
|
104888
105003
|
const parsed = JSON.parse(raw);
|
|
104889
105004
|
if (parsed && typeof parsed === "object") return parsed;
|
|
104890
105005
|
return null;
|
|
@@ -104893,7 +105008,7 @@ async function loadSectionFile2(snapshotDir, file) {
|
|
|
104893
105008
|
}
|
|
104894
105009
|
}
|
|
104895
105010
|
async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
|
|
104896
|
-
const absDir =
|
|
105011
|
+
const absDir = path35.resolve(snapshotDir);
|
|
104897
105012
|
const metaAccountId = typeof asRecord22(payload.meta)?.accountId === "string" ? asRecord22(payload.meta)?.accountId : void 0;
|
|
104898
105013
|
const manifest = await readManifest2(absDir, metaAccountId);
|
|
104899
105014
|
if (!manifest) {
|
|
@@ -104910,7 +105025,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
|
|
|
104910
105025
|
if (accountId) {
|
|
104911
105026
|
let entries = [];
|
|
104912
105027
|
try {
|
|
104913
|
-
entries = await
|
|
105028
|
+
entries = await fs30.readdir(absDir);
|
|
104914
105029
|
} catch {
|
|
104915
105030
|
entries = [];
|
|
104916
105031
|
}
|
|
@@ -105078,9 +105193,9 @@ function sortBySpendDesc(rows) {
|
|
|
105078
105193
|
return [...rows].sort((a, b) => (num6(b.spend) ?? 0) - (num6(a.spend) ?? 0));
|
|
105079
105194
|
}
|
|
105080
105195
|
function prefixLines(items3, firstPrefix) {
|
|
105081
|
-
return items3.map((
|
|
105082
|
-
if (idx === 0 && !
|
|
105083
|
-
return
|
|
105196
|
+
return items3.map((text4, idx) => {
|
|
105197
|
+
if (idx === 0 && !text4.startsWith(firstPrefix)) return `${firstPrefix}${text4}`;
|
|
105198
|
+
return text4;
|
|
105084
105199
|
});
|
|
105085
105200
|
}
|
|
105086
105201
|
function analysisLines(data, key) {
|
|
@@ -105355,13 +105470,13 @@ function buildOkkiWeeklySheetDrafts(data, lang = "zh") {
|
|
|
105355
105470
|
}
|
|
105356
105471
|
function localizeOkkiDraft(draft, lang) {
|
|
105357
105472
|
if (lang !== "en") return draft;
|
|
105358
|
-
const
|
|
105473
|
+
const text4 = (value) => applyEnglishPhrases(value);
|
|
105359
105474
|
return {
|
|
105360
105475
|
...draft,
|
|
105361
|
-
name:
|
|
105362
|
-
title:
|
|
105363
|
-
headers: draft.headers.map(
|
|
105364
|
-
reviewTitle: draft.reviewTitle ?
|
|
105476
|
+
name: text4(draft.name),
|
|
105477
|
+
title: text4(draft.title),
|
|
105478
|
+
headers: draft.headers.map(text4),
|
|
105479
|
+
reviewTitle: draft.reviewTitle ? text4(draft.reviewTitle) : draft.reviewTitle
|
|
105365
105480
|
};
|
|
105366
105481
|
}
|
|
105367
105482
|
function writeOkkiWeeklyExcel(outPath, data, lang = "zh") {
|
|
@@ -105433,12 +105548,12 @@ var init_okki_render_excel = __esm({
|
|
|
105433
105548
|
});
|
|
105434
105549
|
|
|
105435
105550
|
// src/commands/google-analysis/okki-render-report.ts
|
|
105436
|
-
import
|
|
105437
|
-
import
|
|
105438
|
-
async function
|
|
105439
|
-
const
|
|
105551
|
+
import fs31 from "fs/promises";
|
|
105552
|
+
import path36 from "path";
|
|
105553
|
+
async function readJsonFile3(filePath) {
|
|
105554
|
+
const text4 = await fs31.readFile(filePath, "utf8");
|
|
105440
105555
|
try {
|
|
105441
|
-
return JSON.parse(
|
|
105556
|
+
return JSON.parse(text4);
|
|
105442
105557
|
} catch {
|
|
105443
105558
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
105444
105559
|
}
|
|
@@ -105450,15 +105565,15 @@ function asPayload(value) {
|
|
|
105450
105565
|
throw new Error("\u62A5\u544A\u6570\u636E\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
105451
105566
|
}
|
|
105452
105567
|
async function runGoogleAnalysisOkkiRender(opts) {
|
|
105453
|
-
const dataPath =
|
|
105568
|
+
const dataPath = path36.resolve(opts.dataFile);
|
|
105454
105569
|
const snapshotDir = opts.snapshotDir?.trim();
|
|
105455
105570
|
if (!snapshotDir) {
|
|
105456
105571
|
console.error("\n\u274C okki-render \u5FC5\u987B\u4F20 --snapshot-dir\uFF08google-analysis --json-out \u76EE\u5F55\uFF09\n");
|
|
105457
105572
|
process.exit(1);
|
|
105458
105573
|
}
|
|
105459
|
-
let data = asPayload(await
|
|
105574
|
+
let data = asPayload(await readJsonFile3(dataPath));
|
|
105460
105575
|
try {
|
|
105461
|
-
data = await mergeOkkiSnapshotIntoReport(data,
|
|
105576
|
+
data = await mergeOkkiSnapshotIntoReport(data, path36.resolve(snapshotDir));
|
|
105462
105577
|
} catch (err) {
|
|
105463
105578
|
console.error(`
|
|
105464
105579
|
\u274C ${err instanceof Error ? err.message : String(err)}
|
|
@@ -105478,10 +105593,10 @@ async function runGoogleAnalysisOkkiRender(opts) {
|
|
|
105478
105593
|
);
|
|
105479
105594
|
process.exit(1);
|
|
105480
105595
|
}
|
|
105481
|
-
const outPath =
|
|
105482
|
-
opts.out ??
|
|
105596
|
+
const outPath = path36.resolve(
|
|
105597
|
+
opts.out ?? path36.join(path36.dirname(dataPath), "okki-weekly-report.xlsx")
|
|
105483
105598
|
);
|
|
105484
|
-
await
|
|
105599
|
+
await fs31.mkdir(path36.dirname(outPath), { recursive: true });
|
|
105485
105600
|
writeOkkiWeeklyExcel(outPath, data, lang);
|
|
105486
105601
|
console.log(`
|
|
105487
105602
|
\u2705 OKKI \u5468\u62A5\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
@@ -105654,29 +105769,29 @@ var init_report_content = __esm({
|
|
|
105654
105769
|
});
|
|
105655
105770
|
|
|
105656
105771
|
// src/commands/google-analysis/render-report.ts
|
|
105657
|
-
import
|
|
105658
|
-
import
|
|
105659
|
-
import
|
|
105660
|
-
import { fileURLToPath as
|
|
105661
|
-
function
|
|
105662
|
-
const dir =
|
|
105772
|
+
import fs32 from "fs";
|
|
105773
|
+
import fsPromises3 from "fs/promises";
|
|
105774
|
+
import path37 from "path";
|
|
105775
|
+
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
105776
|
+
function resolveSkillTemplatePath4(basename13) {
|
|
105777
|
+
const dir = path37.dirname(fileURLToPath10(import.meta.url));
|
|
105663
105778
|
const candidates = [
|
|
105664
|
-
|
|
105665
|
-
|
|
105666
|
-
|
|
105779
|
+
path37.join(dir, "skill", "report-templates", basename13),
|
|
105780
|
+
path37.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
105781
|
+
path37.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
105667
105782
|
];
|
|
105668
105783
|
for (const p of candidates) {
|
|
105669
|
-
if (
|
|
105784
|
+
if (fs32.existsSync(p)) return p;
|
|
105670
105785
|
}
|
|
105671
105786
|
return candidates[0];
|
|
105672
105787
|
}
|
|
105673
105788
|
function googlePeriodReportTemplatePath() {
|
|
105674
|
-
return
|
|
105789
|
+
return resolveSkillTemplatePath4(TEMPLATE_BASENAME2);
|
|
105675
105790
|
}
|
|
105676
|
-
async function
|
|
105677
|
-
const
|
|
105791
|
+
async function readJsonFile4(filePath) {
|
|
105792
|
+
const text4 = await fsPromises3.readFile(filePath, "utf8");
|
|
105678
105793
|
try {
|
|
105679
|
-
return JSON.parse(
|
|
105794
|
+
return JSON.parse(text4);
|
|
105680
105795
|
} catch {
|
|
105681
105796
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
105682
105797
|
}
|
|
@@ -105696,10 +105811,10 @@ function injectReportData2(html, payload, lang) {
|
|
|
105696
105811
|
return localized.replace(INJECT_MARKER, `window.__GOOGLE_PERIOD_REPORT__ = ${json};`);
|
|
105697
105812
|
}
|
|
105698
105813
|
async function runGoogleAnalysisRender(opts) {
|
|
105699
|
-
const dataPath =
|
|
105700
|
-
let data = asRecord24(await
|
|
105814
|
+
const dataPath = path37.resolve(opts.dataFile);
|
|
105815
|
+
let data = asRecord24(await readJsonFile4(dataPath));
|
|
105701
105816
|
if (opts.snapshotDir?.trim()) {
|
|
105702
|
-
data = await mergeGoogleAnalysisSnapshotIntoReport(data,
|
|
105817
|
+
data = await mergeGoogleAnalysisSnapshotIntoReport(data, path37.resolve(opts.snapshotDir));
|
|
105703
105818
|
}
|
|
105704
105819
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
105705
105820
|
const contentCheck = validateGooglePeriodReportContent(data);
|
|
@@ -105718,7 +105833,7 @@ async function runGoogleAnalysisRender(opts) {
|
|
|
105718
105833
|
const templatePath = googlePeriodReportTemplatePath();
|
|
105719
105834
|
let html;
|
|
105720
105835
|
try {
|
|
105721
|
-
html = await
|
|
105836
|
+
html = await fsPromises3.readFile(templatePath, "utf8");
|
|
105722
105837
|
} catch {
|
|
105723
105838
|
console.error(`
|
|
105724
105839
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -105726,12 +105841,12 @@ async function runGoogleAnalysisRender(opts) {
|
|
|
105726
105841
|
`);
|
|
105727
105842
|
process.exit(1);
|
|
105728
105843
|
}
|
|
105729
|
-
const outPath =
|
|
105730
|
-
opts.out ??
|
|
105844
|
+
const outPath = path37.resolve(
|
|
105845
|
+
opts.out ?? path37.join(path37.dirname(dataPath), "google-period-report.html")
|
|
105731
105846
|
);
|
|
105732
|
-
const outDir =
|
|
105733
|
-
await
|
|
105734
|
-
await
|
|
105847
|
+
const outDir = path37.dirname(outPath);
|
|
105848
|
+
await fsPromises3.mkdir(outDir, { recursive: true });
|
|
105849
|
+
await fsPromises3.writeFile(outPath, injectReportData2(html, data, lang), "utf8");
|
|
105735
105850
|
const { stats } = contentCheck;
|
|
105736
105851
|
const cover = periodWord(attachPeriodChrome(data).periodChrome.unit, "\u5468\u671F");
|
|
105737
105852
|
console.log(`
|
|
@@ -105745,7 +105860,7 @@ async function runGoogleAnalysisRender(opts) {
|
|
|
105745
105860
|
"\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 HTML \u6587\u4EF6\u5373\u53EF\u67E5\u770B\u56FE\u8868\u4E0E\u5B8C\u6574\u7AE0\u8282\uFF08ECharts\uFF1Astaticpn.siluzan.com/homeCDN/echarts.min.js\uFF09\u3002\n"
|
|
105746
105861
|
);
|
|
105747
105862
|
}
|
|
105748
|
-
var
|
|
105863
|
+
var TEMPLATE_BASENAME2, INJECT_MARKER;
|
|
105749
105864
|
var init_render_report = __esm({
|
|
105750
105865
|
"src/commands/google-analysis/render-report.ts"() {
|
|
105751
105866
|
"use strict";
|
|
@@ -105754,14 +105869,14 @@ var init_render_report = __esm({
|
|
|
105754
105869
|
init_report_period();
|
|
105755
105870
|
init_lang();
|
|
105756
105871
|
init_html();
|
|
105757
|
-
|
|
105872
|
+
TEMPLATE_BASENAME2 = "google-period-report.html";
|
|
105758
105873
|
INJECT_MARKER = "window.__GOOGLE_PERIOD_REPORT__ = window.__GOOGLE_PERIOD_REPORT__ || null;";
|
|
105759
105874
|
}
|
|
105760
105875
|
});
|
|
105761
105876
|
|
|
105762
105877
|
// src/utils/batch-manifest.ts
|
|
105763
|
-
import * as
|
|
105764
|
-
import * as
|
|
105878
|
+
import * as fs33 from "fs/promises";
|
|
105879
|
+
import * as path38 from "path";
|
|
105765
105880
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
105766
105881
|
function generateRunId(now = /* @__PURE__ */ new Date()) {
|
|
105767
105882
|
const pad3 = (n) => String(n).padStart(2, "0");
|
|
@@ -105775,26 +105890,26 @@ function isValidRunId(id) {
|
|
|
105775
105890
|
}
|
|
105776
105891
|
function resolveBatchPaths(baseDir, runId) {
|
|
105777
105892
|
if (!isValidRunId(runId)) throw new Error(`\u975E\u6CD5 runId\uFF1A${runId}`);
|
|
105778
|
-
const runDir =
|
|
105779
|
-
const stateDir =
|
|
105893
|
+
const runDir = path38.resolve(baseDir, runId);
|
|
105894
|
+
const stateDir = path38.join(runDir, "state");
|
|
105780
105895
|
return {
|
|
105781
105896
|
runDir,
|
|
105782
|
-
runManifestFile:
|
|
105783
|
-
progressFile:
|
|
105784
|
-
accountsFile:
|
|
105785
|
-
resultsDir:
|
|
105786
|
-
errorsDir:
|
|
105897
|
+
runManifestFile: path38.join(runDir, "run-manifest.json"),
|
|
105898
|
+
progressFile: path38.join(runDir, "progress.json"),
|
|
105899
|
+
accountsFile: path38.join(runDir, "accounts.json"),
|
|
105900
|
+
resultsDir: path38.join(runDir, "results"),
|
|
105901
|
+
errorsDir: path38.join(runDir, "errors"),
|
|
105787
105902
|
stateDir,
|
|
105788
|
-
tasksLogFile:
|
|
105789
|
-
lockFile:
|
|
105903
|
+
tasksLogFile: path38.join(stateDir, "tasks.jsonl"),
|
|
105904
|
+
lockFile: path38.join(stateDir, "tasks.lock")
|
|
105790
105905
|
};
|
|
105791
105906
|
}
|
|
105792
105907
|
async function ensureAccountDirs(paths, accountId) {
|
|
105793
105908
|
const safe = sanitizeAccountSegment(accountId);
|
|
105794
|
-
const results =
|
|
105795
|
-
const errors =
|
|
105796
|
-
await
|
|
105797
|
-
await
|
|
105909
|
+
const results = path38.join(paths.resultsDir, safe);
|
|
105910
|
+
const errors = path38.join(paths.errorsDir, safe);
|
|
105911
|
+
await fs33.mkdir(results, { recursive: true });
|
|
105912
|
+
await fs33.mkdir(errors, { recursive: true });
|
|
105798
105913
|
return { results, errors };
|
|
105799
105914
|
}
|
|
105800
105915
|
function sanitizeAccountSegment(accountId) {
|
|
@@ -105809,20 +105924,20 @@ function sanitizeAccountSegment(accountId) {
|
|
|
105809
105924
|
return slug;
|
|
105810
105925
|
}
|
|
105811
105926
|
async function atomicWriteFile(target, content) {
|
|
105812
|
-
const dir =
|
|
105813
|
-
await
|
|
105814
|
-
const tmp =
|
|
105927
|
+
const dir = path38.dirname(target);
|
|
105928
|
+
await fs33.mkdir(dir, { recursive: true });
|
|
105929
|
+
const tmp = path38.join(dir, `.tmp-${randomUUID2()}-${path38.basename(target)}`);
|
|
105815
105930
|
try {
|
|
105816
|
-
await
|
|
105817
|
-
await
|
|
105931
|
+
await fs33.writeFile(tmp, content, "utf8");
|
|
105932
|
+
await fs33.rename(tmp, target);
|
|
105818
105933
|
} catch (e) {
|
|
105819
|
-
await
|
|
105934
|
+
await fs33.rm(tmp, { force: true }).catch(() => void 0);
|
|
105820
105935
|
throw e;
|
|
105821
105936
|
}
|
|
105822
105937
|
}
|
|
105823
105938
|
async function readJsonIfExists(file) {
|
|
105824
105939
|
try {
|
|
105825
|
-
const raw = await
|
|
105940
|
+
const raw = await fs33.readFile(file, "utf8");
|
|
105826
105941
|
return JSON.parse(raw);
|
|
105827
105942
|
} catch (e) {
|
|
105828
105943
|
if (e.code === "ENOENT") return null;
|
|
@@ -105865,8 +105980,8 @@ function isTaskLogEntry(value) {
|
|
|
105865
105980
|
return typeof row.at === "string" && typeof row.id === "string" && typeof row.accountId === "string" && typeof row.section === "string" && typeof row.state === "string" && TASK_LOG_STATES.has(row.state) && typeof row.attempts === "number";
|
|
105866
105981
|
}
|
|
105867
105982
|
async function writeTaskLogLine(paths, entry) {
|
|
105868
|
-
await
|
|
105869
|
-
await
|
|
105983
|
+
await fs33.mkdir(paths.stateDir, { recursive: true });
|
|
105984
|
+
await fs33.appendFile(paths.tasksLogFile, JSON.stringify(clampTaskLogEntry(entry)) + "\n", "utf8");
|
|
105870
105985
|
}
|
|
105871
105986
|
async function appendTaskLog(paths, entry) {
|
|
105872
105987
|
const file = paths.tasksLogFile;
|
|
@@ -105884,7 +105999,7 @@ async function appendTaskLog(paths, entry) {
|
|
|
105884
105999
|
async function readTaskLog(paths) {
|
|
105885
106000
|
let raw;
|
|
105886
106001
|
try {
|
|
105887
|
-
raw = await
|
|
106002
|
+
raw = await fs33.readFile(paths.tasksLogFile, "utf8");
|
|
105888
106003
|
} catch (e) {
|
|
105889
106004
|
if (e.code === "ENOENT") return [];
|
|
105890
106005
|
throw e;
|
|
@@ -105892,10 +106007,10 @@ async function readTaskLog(paths) {
|
|
|
105892
106007
|
const entries = [];
|
|
105893
106008
|
let skipped = 0;
|
|
105894
106009
|
for (const line of raw.split("\n")) {
|
|
105895
|
-
const
|
|
105896
|
-
if (!
|
|
106010
|
+
const text4 = line.trim();
|
|
106011
|
+
if (!text4) continue;
|
|
105897
106012
|
try {
|
|
105898
|
-
const parsed = JSON.parse(
|
|
106013
|
+
const parsed = JSON.parse(text4);
|
|
105899
106014
|
if (!isTaskLogEntry(parsed)) {
|
|
105900
106015
|
skipped += 1;
|
|
105901
106016
|
continue;
|
|
@@ -105962,9 +106077,9 @@ function emptyProgress(runId, totalTasks, accountConcurrency, sectionConcurrency
|
|
|
105962
106077
|
};
|
|
105963
106078
|
}
|
|
105964
106079
|
async function tryAcquireLock(paths) {
|
|
105965
|
-
await
|
|
106080
|
+
await fs33.mkdir(paths.stateDir, { recursive: true });
|
|
105966
106081
|
try {
|
|
105967
|
-
const handle = await
|
|
106082
|
+
const handle = await fs33.open(paths.lockFile, "wx");
|
|
105968
106083
|
await handle.writeFile(`${process.pid}@${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
105969
106084
|
await handle.close();
|
|
105970
106085
|
return true;
|
|
@@ -105974,7 +106089,7 @@ async function tryAcquireLock(paths) {
|
|
|
105974
106089
|
}
|
|
105975
106090
|
}
|
|
105976
106091
|
async function releaseLock(paths) {
|
|
105977
|
-
await
|
|
106092
|
+
await fs33.rm(paths.lockFile, { force: true }).catch(() => void 0);
|
|
105978
106093
|
}
|
|
105979
106094
|
var BATCH_SCHEMA_VERSION, MAX_TASK_LOG_ERROR_CHARS, TASK_LOG_STATES, taskLogAppendQueue;
|
|
105980
106095
|
var init_batch_manifest = __esm({
|
|
@@ -105996,8 +106111,8 @@ var init_batch_manifest = __esm({
|
|
|
105996
106111
|
|
|
105997
106112
|
// src/utils/batch-runner.ts
|
|
105998
106113
|
import { performance as performance2 } from "perf_hooks";
|
|
105999
|
-
import * as
|
|
106000
|
-
import * as
|
|
106114
|
+
import * as path39 from "path";
|
|
106115
|
+
import * as fs34 from "fs/promises";
|
|
106001
106116
|
async function runPool(items3, concurrencyRef, worker, signal) {
|
|
106002
106117
|
let cursor = 0;
|
|
106003
106118
|
const launch = () => {
|
|
@@ -106136,7 +106251,7 @@ async function runBatch(opts) {
|
|
|
106136
106251
|
}
|
|
106137
106252
|
const inner = {
|
|
106138
106253
|
...emptyProgress(
|
|
106139
|
-
opts.paths.runDir.split(
|
|
106254
|
+
opts.paths.runDir.split(path39.sep).pop() ?? "run",
|
|
106140
106255
|
allTasks.length,
|
|
106141
106256
|
opts.accountConcurrency,
|
|
106142
106257
|
opts.sectionConcurrency
|
|
@@ -106261,7 +106376,7 @@ async function runBatch(opts) {
|
|
|
106261
106376
|
signal: aborterToken.signal
|
|
106262
106377
|
});
|
|
106263
106378
|
await writer({
|
|
106264
|
-
snapshotDir:
|
|
106379
|
+
snapshotDir: path39.join(opts.paths.resultsDir, sanitizeAccountSegment(task.accountId)),
|
|
106265
106380
|
section: task.section,
|
|
106266
106381
|
accountId: task.accountId,
|
|
106267
106382
|
dateRange: result.dateRange,
|
|
@@ -106350,7 +106465,7 @@ async function runBatch(opts) {
|
|
|
106350
106465
|
};
|
|
106351
106466
|
}
|
|
106352
106467
|
async function writeTaskError(paths, errorsDir, task, err, cls) {
|
|
106353
|
-
const file =
|
|
106468
|
+
const file = path39.join(errorsDir, `${sanitizeSection(task.section)}.error.json`);
|
|
106354
106469
|
const payload = {
|
|
106355
106470
|
schemaVersion: 1,
|
|
106356
106471
|
taskId: task.id,
|
|
@@ -106396,10 +106511,10 @@ async function persistRunMetadata(input) {
|
|
|
106396
106511
|
accountsTotal: input.accounts.length,
|
|
106397
106512
|
invocation: input.invocation
|
|
106398
106513
|
};
|
|
106399
|
-
await
|
|
106400
|
-
await
|
|
106401
|
-
await
|
|
106402
|
-
await
|
|
106514
|
+
await fs34.mkdir(paths.runDir, { recursive: true });
|
|
106515
|
+
await fs34.mkdir(paths.stateDir, { recursive: true });
|
|
106516
|
+
await fs34.mkdir(paths.resultsDir, { recursive: true });
|
|
106517
|
+
await fs34.mkdir(paths.errorsDir, { recursive: true });
|
|
106403
106518
|
await writeRunManifest(paths, manifest);
|
|
106404
106519
|
await writeAccounts(paths, input.accounts);
|
|
106405
106520
|
return paths;
|
|
@@ -106462,7 +106577,7 @@ __export(google_analysis_batch_exports, {
|
|
|
106462
106577
|
parseAccountIds: () => parseAccountIds,
|
|
106463
106578
|
registerGoogleAnalysisBatchCommands: () => registerGoogleAnalysisBatchCommands
|
|
106464
106579
|
});
|
|
106465
|
-
import * as
|
|
106580
|
+
import * as path40 from "path";
|
|
106466
106581
|
import { performance as performance3 } from "perf_hooks";
|
|
106467
106582
|
function parseSections(input) {
|
|
106468
106583
|
if (!input || !input.trim()) return DEFAULT_SECTIONS;
|
|
@@ -106997,7 +107112,7 @@ var init_google_analysis_batch = __esm({
|
|
|
106997
107112
|
});
|
|
106998
107113
|
|
|
106999
107114
|
// src/commands/google-analysis/register-cli.ts
|
|
107000
|
-
import * as
|
|
107115
|
+
import * as path41 from "path";
|
|
107001
107116
|
import { performance as performance4 } from "perf_hooks";
|
|
107002
107117
|
import { Command } from "commander";
|
|
107003
107118
|
function normalizeAnalysisDateOpts(opts) {
|
|
@@ -107135,7 +107250,7 @@ async function runAllSections(opts) {
|
|
|
107135
107250
|
}
|
|
107136
107251
|
const succeeded = results.filter((r) => r.ok).length;
|
|
107137
107252
|
const failed = results.length - succeeded;
|
|
107138
|
-
const absoluteSnapshotDir =
|
|
107253
|
+
const absoluteSnapshotDir = path41.resolve(opts.jsonOut);
|
|
107139
107254
|
const summary = {
|
|
107140
107255
|
kind: "siluzan-tso-google-analysis-snapshot-batch",
|
|
107141
107256
|
absoluteSnapshotDir,
|
|
@@ -107332,7 +107447,7 @@ ${fixHint}
|
|
|
107332
107447
|
}
|
|
107333
107448
|
function registerGoogleAnalysisCommands(program2) {
|
|
107334
107449
|
const root = program2.command("google-analysis").description(
|
|
107335
|
-
"Google \u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6\u4E00\u4E2A\u6216\u591A\u4E2A\u7EF4\u5EA6\uFF08\u9ED8\u8BA4\uFF09\uFF0C\u6216\u7531 render \u751F\u6210\u5468\u671F HTML / okki-render \u751F\u6210 OKKI \u5468\u62A5 xlsx"
|
|
107450
|
+
"Google \u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6\u4E00\u4E2A\u6216\u591A\u4E2A\u7EF4\u5EA6\uFF08\u9ED8\u8BA4\uFF09\uFF0C\u6216\u7531 render \u751F\u6210\u5468\u671F HTML / okki-render \u751F\u6210 OKKI \u5468\u62A5 xlsx / demand-gen-render \u751F\u6210 Demand Gen \u6C47\u603B HTML"
|
|
107336
107451
|
);
|
|
107337
107452
|
root.addCommand(registerRunCommand(), { isDefault: true });
|
|
107338
107453
|
root.command("render").description(
|
|
@@ -107361,6 +107476,18 @@ function registerGoogleAnalysisCommands(program2) {
|
|
|
107361
107476
|
lang: opts.lang
|
|
107362
107477
|
});
|
|
107363
107478
|
});
|
|
107479
|
+
root.command("demand-gen-render").description(
|
|
107480
|
+
"\u6839\u636E Agent \u64B0\u5199\u7684 Demand Gen \u6C47\u603B JSON \u751F\u6210 8 \u8282 HTML\uFF08\u4E0D\u5408\u5E76\u5FEB\u7167\uFF1BExcel \u4E0D\u8D70\u672C\u547D\u4EE4\uFF09"
|
|
107481
|
+
).requiredOption("--data <file>", "Agent \u4EA7\u51FA\u7684 demand-gen-analysis-report.json").option("--out <file>", "\u8F93\u51FA HTML \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\uFF09").option("--lang <lang>", "\u7EC8\u7A3F\u8BED\u8A00\uFF1Azh \u6216 en\u3002\u8986\u76D6 JSON meta.lang").action(async (opts) => {
|
|
107482
|
+
try {
|
|
107483
|
+
await runDemandGenRender({ dataFile: opts.data, out: opts.out, lang: opts.lang });
|
|
107484
|
+
} catch (err) {
|
|
107485
|
+
console.error(`
|
|
107486
|
+
\u274C ${err instanceof Error ? err.message : String(err)}
|
|
107487
|
+
`);
|
|
107488
|
+
process.exit(1);
|
|
107489
|
+
}
|
|
107490
|
+
});
|
|
107364
107491
|
}
|
|
107365
107492
|
var init_register_cli = __esm({
|
|
107366
107493
|
"src/commands/google-analysis/register-cli.ts"() {
|
|
@@ -107372,6 +107499,7 @@ var init_register_cli = __esm({
|
|
|
107372
107499
|
init_http_retry();
|
|
107373
107500
|
init_sections();
|
|
107374
107501
|
init_fetch();
|
|
107502
|
+
init_demand_gen_render();
|
|
107375
107503
|
init_okki_render_report();
|
|
107376
107504
|
init_render_report();
|
|
107377
107505
|
}
|
|
@@ -107404,9 +107532,9 @@ var init_google_analysis3 = __esm({
|
|
|
107404
107532
|
// src/index.ts
|
|
107405
107533
|
init_dist();
|
|
107406
107534
|
init_dist();
|
|
107407
|
-
import * as
|
|
107408
|
-
import * as
|
|
107409
|
-
import { fileURLToPath as
|
|
107535
|
+
import * as fs45 from "fs";
|
|
107536
|
+
import * as path56 from "path";
|
|
107537
|
+
import { fileURLToPath as fileURLToPath16 } from "url";
|
|
107410
107538
|
import { Command as Command6 } from "commander";
|
|
107411
107539
|
|
|
107412
107540
|
// src/commands/login/urls.ts
|
|
@@ -107895,8 +108023,8 @@ function deriveWebUrl(apiBaseUrl) {
|
|
|
107895
108023
|
}
|
|
107896
108024
|
var TSO_UMI_ROUTE_PREFIX = "/v3umijs/tso";
|
|
107897
108025
|
function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
107898
|
-
const
|
|
107899
|
-
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${
|
|
108026
|
+
const path57 = tsoSubRoute.replace(/^\/+/, "");
|
|
108027
|
+
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${path57}`;
|
|
107900
108028
|
const q = new URLSearchParams({ tso: umiPath });
|
|
107901
108029
|
if (extraQuery) {
|
|
107902
108030
|
for (const [key, value] of Object.entries(extraQuery)) {
|
|
@@ -107904,7 +108032,7 @@ function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
|
107904
108032
|
if (v) q.set(key, v);
|
|
107905
108033
|
}
|
|
107906
108034
|
}
|
|
107907
|
-
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${
|
|
108035
|
+
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${path57}?${q.toString()}`;
|
|
107908
108036
|
}
|
|
107909
108037
|
function cmdConfigShow() {
|
|
107910
108038
|
const shared = readSharedConfig();
|
|
@@ -114793,27 +114921,27 @@ function validateCalloutProperties(prefix, rec, errors, _warnings, lengthViolati
|
|
|
114793
114921
|
);
|
|
114794
114922
|
return;
|
|
114795
114923
|
}
|
|
114796
|
-
const
|
|
114797
|
-
if (typeof
|
|
114924
|
+
const text4 = raw["Text"];
|
|
114925
|
+
if (typeof text4 !== "string" || !text4.trim()) {
|
|
114798
114926
|
pushErr(
|
|
114799
114927
|
errors,
|
|
114800
114928
|
`${prefix}.Properties.Text \u4E0D\u80FD\u4E3A\u7A7A\uFF08CALLOUT \u5FC5\u586B\uFF0C\u540E\u7AEF CreateCalloutFeedItem \u8BFB\u53D6 Properties["Text"]\uFF09`
|
|
114801
114929
|
);
|
|
114802
114930
|
return;
|
|
114803
114931
|
}
|
|
114804
|
-
if (
|
|
114932
|
+
if (text4.length > CALLOUT_TEXT_MAX_LEN) {
|
|
114805
114933
|
pushLengthViolation(lengthViolations, {
|
|
114806
114934
|
path: `${prefix}.Properties.Text`,
|
|
114807
114935
|
field: "Text",
|
|
114808
114936
|
kind: "callout_text",
|
|
114809
114937
|
limit: CALLOUT_TEXT_MAX_LEN,
|
|
114810
|
-
actual:
|
|
114938
|
+
actual: text4.length,
|
|
114811
114939
|
countMode: "ascii",
|
|
114812
|
-
text:
|
|
114940
|
+
text: text4
|
|
114813
114941
|
});
|
|
114814
114942
|
pushErr(
|
|
114815
114943
|
errors,
|
|
114816
|
-
`${prefix}.Properties.Text \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${
|
|
114944
|
+
`${prefix}.Properties.Text \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${text4.length}\uFF0CGoogle \u786C\u7EA6\u675F\uFF09\uFF1A"${text4}"`
|
|
114817
114945
|
);
|
|
114818
114946
|
}
|
|
114819
114947
|
}
|
|
@@ -115127,8 +115255,8 @@ function judgeBudgetAfterFailedPut(input) {
|
|
|
115127
115255
|
}
|
|
115128
115256
|
return { kind: "unchanged" };
|
|
115129
115257
|
}
|
|
115130
|
-
function coreKeyword(
|
|
115131
|
-
const t =
|
|
115258
|
+
function coreKeyword(text4) {
|
|
115259
|
+
const t = text4.trim();
|
|
115132
115260
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("[") && t.endsWith("]"))) {
|
|
115133
115261
|
return t.slice(1, -1).trim();
|
|
115134
115262
|
}
|
|
@@ -115171,8 +115299,8 @@ function summarizeNegativeKeywordCreate(requested, response, listItems) {
|
|
|
115171
115299
|
const pools = listItems == null ? responseRecords : [...responseRecords, ...listItems];
|
|
115172
115300
|
const matched = [];
|
|
115173
115301
|
const pending = [];
|
|
115174
|
-
for (const
|
|
115175
|
-
const core = coreKeyword(
|
|
115302
|
+
for (const text4 of requested) {
|
|
115303
|
+
const core = coreKeyword(text4);
|
|
115176
115304
|
const hit = pools.find((item) => {
|
|
115177
115305
|
const cores = [
|
|
115178
115306
|
...collectKeywordCores(item["keywordText"]),
|
|
@@ -115182,11 +115310,11 @@ function summarizeNegativeKeywordCreate(requested, response, listItems) {
|
|
|
115182
115310
|
return cores.includes(core);
|
|
115183
115311
|
});
|
|
115184
115312
|
if (!hit) {
|
|
115185
|
-
pending.push(
|
|
115313
|
+
pending.push(text4);
|
|
115186
115314
|
continue;
|
|
115187
115315
|
}
|
|
115188
115316
|
const idRaw = hit["id"] ?? hit["Id"];
|
|
115189
|
-
matched.push({ text:
|
|
115317
|
+
matched.push({ text: text4, id: typeof idRaw === "string" ? idRaw : void 0 });
|
|
115190
115318
|
}
|
|
115191
115319
|
let verification;
|
|
115192
115320
|
if (requested.length > 0 && matched.length === requested.length) verification = "verified";
|
|
@@ -115298,10 +115426,10 @@ function firstKeywordTextFromRecord(k) {
|
|
|
115298
115426
|
return "";
|
|
115299
115427
|
}
|
|
115300
115428
|
function negativeKeywordWriteBody(row) {
|
|
115301
|
-
const
|
|
115429
|
+
const text4 = firstKeywordTextFromRecord(row);
|
|
115302
115430
|
const body = {
|
|
115303
115431
|
id: row["id"],
|
|
115304
|
-
keywordText:
|
|
115432
|
+
keywordText: text4 ? [text4] : [],
|
|
115305
115433
|
matchTypeV2: row["matchTypeV2"],
|
|
115306
115434
|
negativeLevel: row["negativeLevel"]
|
|
115307
115435
|
};
|
|
@@ -115934,8 +116062,8 @@ async function runAdNegativeKeywordDelete(opts) {
|
|
|
115934
116062
|
|
|
115935
116063
|
// src/commands/ad/campaign-keywords.ts
|
|
115936
116064
|
var GOOGLE_KEYWORD_MAX_CORE_LENGTH = 80;
|
|
115937
|
-
function collapseDuplicateSpacesInKeywordText(
|
|
115938
|
-
return
|
|
116065
|
+
function collapseDuplicateSpacesInKeywordText(text4) {
|
|
116066
|
+
return text4.replace(/\s{2,}/g, " ");
|
|
115939
116067
|
}
|
|
115940
116068
|
var VALID_CORE_REGEX = /^[\p{L}\p{N}\s.\-]+$/u;
|
|
115941
116069
|
function matchTypeV2ToUi(raw) {
|
|
@@ -115960,8 +116088,8 @@ function matchTypeUiToV2(ui) {
|
|
|
115960
116088
|
}
|
|
115961
116089
|
}
|
|
115962
116090
|
}
|
|
115963
|
-
function inferMatchTypeFromDisplayText(
|
|
115964
|
-
const t =
|
|
116091
|
+
function inferMatchTypeFromDisplayText(text4) {
|
|
116092
|
+
const t = text4.trim();
|
|
115965
116093
|
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return "Phrase";
|
|
115966
116094
|
if (t.length >= 2 && t.startsWith("[") && t.endsWith("]")) return "Exact";
|
|
115967
116095
|
return "Broad";
|
|
@@ -116002,7 +116130,7 @@ function cloneKeywordBlockShell(block) {
|
|
|
116002
116130
|
delete shell["matchTypeV2"];
|
|
116003
116131
|
return shell;
|
|
116004
116132
|
}
|
|
116005
|
-
function splitKeywordsForBatchJobBlockIfMixed(block,
|
|
116133
|
+
function splitKeywordsForBatchJobBlockIfMixed(block, path57, warnings) {
|
|
116006
116134
|
const declaredUi = matchTypeV2ToUi(readBlockMatchTypeRaw(block));
|
|
116007
116135
|
const entries = collectKeywordEntriesFromBlock(block);
|
|
116008
116136
|
if (entries.length === 0) return [block];
|
|
@@ -116021,7 +116149,7 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path56, warnings) {
|
|
|
116021
116149
|
(ui) => matchTypeUiToV2(ui)
|
|
116022
116150
|
);
|
|
116023
116151
|
warnings.push(
|
|
116024
|
-
`${
|
|
116152
|
+
`${path57} \u542B\u591A\u79CD\u5339\u914D\u7C7B\u578B\uFF0C\u5DF2\u81EA\u52A8\u62C6\u5206\u4E3A ${groups.size} \u4E2A KeywordsForBatchJob \u5757\uFF08${labels.join("\u3001")}\uFF09`
|
|
116025
116153
|
);
|
|
116026
116154
|
const shell = cloneKeywordBlockShell(block);
|
|
116027
116155
|
const splitBlocks = [];
|
|
@@ -116041,16 +116169,16 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path56, warnings) {
|
|
|
116041
116169
|
}
|
|
116042
116170
|
return splitBlocks;
|
|
116043
116171
|
}
|
|
116044
|
-
function validateKeywordCore(core,
|
|
116172
|
+
function validateKeywordCore(core, path57, errors, lengthViolations) {
|
|
116045
116173
|
const trimmed = core.trim();
|
|
116046
116174
|
if (!trimmed) {
|
|
116047
|
-
errors.push(`${
|
|
116175
|
+
errors.push(`${path57} \u5173\u952E\u8BCD\u8BCD\u5E72\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
116048
116176
|
return false;
|
|
116049
116177
|
}
|
|
116050
116178
|
if (trimmed.length > GOOGLE_KEYWORD_MAX_CORE_LENGTH) {
|
|
116051
116179
|
if (lengthViolations) {
|
|
116052
116180
|
pushLengthViolation(lengthViolations, {
|
|
116053
|
-
path:
|
|
116181
|
+
path: path57,
|
|
116054
116182
|
field: "KeywordText",
|
|
116055
116183
|
kind: "keyword_core",
|
|
116056
116184
|
limit: GOOGLE_KEYWORD_MAX_CORE_LENGTH,
|
|
@@ -116060,13 +116188,13 @@ function validateKeywordCore(core, path56, errors, lengthViolations) {
|
|
|
116060
116188
|
});
|
|
116061
116189
|
}
|
|
116062
116190
|
errors.push(
|
|
116063
|
-
`${
|
|
116191
|
+
`${path57} \u5173\u952E\u8BCD\u8BCD\u5E72\u8D85\u8FC7 ${GOOGLE_KEYWORD_MAX_CORE_LENGTH} \u5B57\u7B26\uFF08\u5F53\u524D ${trimmed.length}\uFF09\uFF1A"${trimmed}"`
|
|
116064
116192
|
);
|
|
116065
116193
|
return false;
|
|
116066
116194
|
}
|
|
116067
116195
|
if (!VALID_CORE_REGEX.test(trimmed)) {
|
|
116068
116196
|
errors.push(
|
|
116069
|
-
`${
|
|
116197
|
+
`${path57} \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" : ""}"`
|
|
116070
116198
|
);
|
|
116071
116199
|
return false;
|
|
116072
116200
|
}
|
|
@@ -116123,10 +116251,10 @@ function canonicalizeKeywordBatchBlock(block, resolvedMatchV2, normalizedTexts,
|
|
|
116123
116251
|
}
|
|
116124
116252
|
}
|
|
116125
116253
|
}
|
|
116126
|
-
function pushKeywordAutoFixWarning(warnings,
|
|
116254
|
+
function pushKeywordAutoFixWarning(warnings, path57, fieldLabel, trimmedRaw, formatted, declaredUi, beforeUi, matchType, inferredMatchType) {
|
|
116127
116255
|
if (inferredMatchType) {
|
|
116128
116256
|
warnings.push(
|
|
116129
|
-
`${
|
|
116257
|
+
`${path57}.${fieldLabel} \u672A\u6307\u5B9A MatchTypeV2\uFF0C\u5DF2\u6309\u8BCD\u9762\u63A8\u65AD\u4E3A ${matchTypeUiToV2(matchType)}`
|
|
116130
116258
|
);
|
|
116131
116259
|
return false;
|
|
116132
116260
|
}
|
|
@@ -116135,16 +116263,16 @@ function pushKeywordAutoFixWarning(warnings, path56, fieldLabel, trimmedRaw, for
|
|
|
116135
116263
|
}
|
|
116136
116264
|
if (declaredUi && beforeUi !== declaredUi) {
|
|
116137
116265
|
warnings.push(
|
|
116138
|
-
`${
|
|
116266
|
+
`${path57}.${fieldLabel} MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u4E0E\u8BCD\u9762\u4E0D\u4E00\u81F4\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`
|
|
116139
116267
|
);
|
|
116140
116268
|
return false;
|
|
116141
116269
|
}
|
|
116142
116270
|
if (formatted !== trimmedRaw) {
|
|
116143
|
-
warnings.push(`${
|
|
116271
|
+
warnings.push(`${path57}.${fieldLabel} \u5DF2\u81EA\u52A8\u4FEE\u590D\u8BCD\u9762\uFF1A${trimmedRaw} \u2192 ${formatted}`);
|
|
116144
116272
|
}
|
|
116145
116273
|
return false;
|
|
116146
116274
|
}
|
|
116147
|
-
function normalizeKeywordTextList(texts, matchTypeRaw,
|
|
116275
|
+
function normalizeKeywordTextList(texts, matchTypeRaw, path57, fieldLabel, errors, warnings, lengthViolations) {
|
|
116148
116276
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
116149
116277
|
const normalized = [];
|
|
116150
116278
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -116153,7 +116281,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path56, fieldLabel, error
|
|
|
116153
116281
|
for (let k = 0; k < texts.length; k++) {
|
|
116154
116282
|
const raw = texts[k];
|
|
116155
116283
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
116156
|
-
errors.push(`${
|
|
116284
|
+
errors.push(`${path57}.${fieldLabel}[${k}] \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
116157
116285
|
continue;
|
|
116158
116286
|
}
|
|
116159
116287
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -116164,7 +116292,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path56, fieldLabel, error
|
|
|
116164
116292
|
);
|
|
116165
116293
|
if (pushKeywordAutoFixWarning(
|
|
116166
116294
|
warnings,
|
|
116167
|
-
|
|
116295
|
+
path57,
|
|
116168
116296
|
fieldLabel,
|
|
116169
116297
|
trimmedRaw,
|
|
116170
116298
|
formatted,
|
|
@@ -116176,11 +116304,11 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path56, fieldLabel, error
|
|
|
116176
116304
|
bareWrapped++;
|
|
116177
116305
|
}
|
|
116178
116306
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
116179
|
-
if (!validateKeywordCore(core, `${
|
|
116307
|
+
if (!validateKeywordCore(core, `${path57}.${fieldLabel}[${k}]`, errors, lengthViolations))
|
|
116180
116308
|
continue;
|
|
116181
116309
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
116182
116310
|
if (seen.has(dedupeKey)) {
|
|
116183
|
-
warnings.push(`${
|
|
116311
|
+
warnings.push(`${path57}.${fieldLabel}[${k}] \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
116184
116312
|
continue;
|
|
116185
116313
|
}
|
|
116186
116314
|
seen.add(dedupeKey);
|
|
@@ -116189,17 +116317,17 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path56, fieldLabel, error
|
|
|
116189
116317
|
}
|
|
116190
116318
|
if (bareWrapped > 0 && declaredUi) {
|
|
116191
116319
|
warnings.push(
|
|
116192
|
-
`${
|
|
116320
|
+
`${path57}.${fieldLabel}\uFF1A${bareWrapped} \u4E2A\u88F8\u8BCD\u5DF2\u6309 MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u81EA\u52A8\u4FEE\u590D\uFF08\u8865\u5168${declaredUi === "Exact" ? " [ ]" : "\u5F15\u53F7"}\uFF0C\u9884\u671F\u884C\u4E3A\uFF09`
|
|
116193
116321
|
);
|
|
116194
116322
|
}
|
|
116195
116323
|
return { normalized, resolvedUi };
|
|
116196
116324
|
}
|
|
116197
|
-
function normalizeKeywordsForBatchJobBlock(block,
|
|
116325
|
+
function normalizeKeywordsForBatchJobBlock(block, path57, errors, warnings, lengthViolations) {
|
|
116198
116326
|
const matchTypeRaw = readBlockMatchTypeRaw(block);
|
|
116199
116327
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
116200
116328
|
if (matchTypeRaw !== void 0 && declaredUi === null) {
|
|
116201
116329
|
errors.push(
|
|
116202
|
-
`${
|
|
116330
|
+
`${path57}.MatchTypeV2 \u65E0\u6548\uFF08${String(matchTypeRaw)}\uFF09\uFF0C\u5408\u6CD5\u503C\uFF1ABROAD | PHRASE | EXACT`
|
|
116203
116331
|
);
|
|
116204
116332
|
return;
|
|
116205
116333
|
}
|
|
@@ -116214,7 +116342,7 @@ function normalizeKeywordsForBatchJobBlock(block, path56, errors, warnings, leng
|
|
|
116214
116342
|
const result = normalizeKeywordTextList(
|
|
116215
116343
|
texts,
|
|
116216
116344
|
matchTypeRaw,
|
|
116217
|
-
|
|
116345
|
+
path57,
|
|
116218
116346
|
"KeywordText",
|
|
116219
116347
|
errors,
|
|
116220
116348
|
warnings,
|
|
@@ -116223,7 +116351,7 @@ function normalizeKeywordsForBatchJobBlock(block, path56, errors, warnings, leng
|
|
|
116223
116351
|
normalizedTexts = result.normalized;
|
|
116224
116352
|
if (result.resolvedUi) resolvedUi = result.resolvedUi;
|
|
116225
116353
|
if (normalizedTexts.length === 0 && texts.length > 0) {
|
|
116226
|
-
errors.push(`${
|
|
116354
|
+
errors.push(`${path57}.KeywordText \u7ECF\u6821\u9A8C\u540E\u65E0\u6709\u6548\u5173\u952E\u8BCD\uFF0C\u8BF7\u4FEE\u6B63\u8BCD\u9762\u6216 MatchTypeV2`);
|
|
116227
116355
|
}
|
|
116228
116356
|
}
|
|
116229
116357
|
if (hasItems && items3) {
|
|
@@ -116231,12 +116359,12 @@ function normalizeKeywordsForBatchJobBlock(block, path56, errors, warnings, leng
|
|
|
116231
116359
|
for (let k = 0; k < items3.length; k++) {
|
|
116232
116360
|
const item = items3[k];
|
|
116233
116361
|
if (!item || typeof item !== "object") {
|
|
116234
|
-
errors.push(`${
|
|
116362
|
+
errors.push(`${path57}.Items[${k}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
116235
116363
|
continue;
|
|
116236
116364
|
}
|
|
116237
116365
|
const raw = readItemText(item);
|
|
116238
116366
|
if (raw === null || !raw.trim()) {
|
|
116239
|
-
errors.push(`${
|
|
116367
|
+
errors.push(`${path57}.Items[${k}].Text \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
116240
116368
|
continue;
|
|
116241
116369
|
}
|
|
116242
116370
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -116247,7 +116375,7 @@ function normalizeKeywordsForBatchJobBlock(block, path56, errors, warnings, leng
|
|
|
116247
116375
|
);
|
|
116248
116376
|
if (pushKeywordAutoFixWarning(
|
|
116249
116377
|
warnings,
|
|
116250
|
-
|
|
116378
|
+
path57,
|
|
116251
116379
|
`Items[${k}].Text`,
|
|
116252
116380
|
trimmedRaw,
|
|
116253
116381
|
formatted,
|
|
@@ -116256,14 +116384,14 @@ function normalizeKeywordsForBatchJobBlock(block, path56, errors, warnings, leng
|
|
|
116256
116384
|
matchType,
|
|
116257
116385
|
inferredMatchType
|
|
116258
116386
|
)) {
|
|
116259
|
-
warnings.push(`${
|
|
116387
|
+
warnings.push(`${path57}.Items[${k}].Text \u5DF2\u6309\u5757\u7EA7\u5339\u914D\u7C7B\u578B\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`);
|
|
116260
116388
|
}
|
|
116261
116389
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
116262
|
-
if (!validateKeywordCore(core, `${
|
|
116390
|
+
if (!validateKeywordCore(core, `${path57}.Items[${k}].Text`, errors, lengthViolations))
|
|
116263
116391
|
continue;
|
|
116264
116392
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
116265
116393
|
if (seen.has(dedupeKey)) {
|
|
116266
|
-
warnings.push(`${
|
|
116394
|
+
warnings.push(`${path57}.Items[${k}].Text \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
116267
116395
|
continue;
|
|
116268
116396
|
}
|
|
116269
116397
|
seen.add(dedupeKey);
|
|
@@ -116409,16 +116537,16 @@ function warnIfNegativeKeywordsInPositiveKeywords(campaign, warnings) {
|
|
|
116409
116537
|
const raw = texts[ki];
|
|
116410
116538
|
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
116411
116539
|
const core = normalizeKeywordCoreForNegativeCheck(raw);
|
|
116412
|
-
const
|
|
116540
|
+
const path57 = `campaign.AdGroupsForBatchJob[${gi}].KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
116413
116541
|
if (plannedNegCores.has(core)) {
|
|
116414
116542
|
warnings.push(
|
|
116415
|
-
`${
|
|
116543
|
+
`${path57} \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`
|
|
116416
116544
|
);
|
|
116417
116545
|
continue;
|
|
116418
116546
|
}
|
|
116419
116547
|
if (looksLikeStandaloneNegativeKeyword(core)) {
|
|
116420
116548
|
warnings.push(
|
|
116421
|
-
`${
|
|
116549
|
+
`${path57} \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`
|
|
116422
116550
|
);
|
|
116423
116551
|
}
|
|
116424
116552
|
}
|
|
@@ -116499,9 +116627,9 @@ var POLICY_RISK_RULES = [
|
|
|
116499
116627
|
{ re: /\b(alcohol|whisk(e)?y|vodka|liquor)\b/i, label: "\u9152\u7CBE\uFF08\u5730\u57DF\u9650\u5236\uFF09" },
|
|
116500
116628
|
{ re: /(最好|第一|国家级|绝对|100%)/, label: "\u5E7F\u544A\u6CD5\u7EDD\u5BF9\u5316\u7528\u8BED" }
|
|
116501
116629
|
];
|
|
116502
|
-
function matchRisk(
|
|
116630
|
+
function matchRisk(text4) {
|
|
116503
116631
|
for (const r of POLICY_RISK_RULES) {
|
|
116504
|
-
if (r.re.test(
|
|
116632
|
+
if (r.re.test(text4)) return r.label;
|
|
116505
116633
|
}
|
|
116506
116634
|
return void 0;
|
|
116507
116635
|
}
|
|
@@ -116524,10 +116652,10 @@ function warnPolicyRiskTerms(campaign, warnings) {
|
|
|
116524
116652
|
const groups = campaign["AdGroupsForBatchJob"];
|
|
116525
116653
|
if (!Array.isArray(groups)) return;
|
|
116526
116654
|
const hitsByLabel = /* @__PURE__ */ new Map();
|
|
116527
|
-
const add = (label2,
|
|
116655
|
+
const add = (label2, text4) => {
|
|
116528
116656
|
let set = hitsByLabel.get(label2);
|
|
116529
116657
|
if (!set) hitsByLabel.set(label2, set = /* @__PURE__ */ new Set());
|
|
116530
|
-
set.add(
|
|
116658
|
+
set.add(text4.trim());
|
|
116531
116659
|
};
|
|
116532
116660
|
for (const g of groups) {
|
|
116533
116661
|
const gr = g;
|
|
@@ -116563,8 +116691,8 @@ function warnPolicyRiskTerms(campaign, warnings) {
|
|
|
116563
116691
|
}
|
|
116564
116692
|
|
|
116565
116693
|
// src/commands/ad/campaign-rsa.ts
|
|
116566
|
-
function normalizeRsaAssetKey(
|
|
116567
|
-
return
|
|
116694
|
+
function normalizeRsaAssetKey(text4) {
|
|
116695
|
+
return text4.trim().replace(/\s+/g, " ").toLowerCase();
|
|
116568
116696
|
}
|
|
116569
116697
|
function listRsaHeadlines(ad) {
|
|
116570
116698
|
const parts = [
|
|
@@ -116732,9 +116860,9 @@ function validateLocationsFidelity(cfg, campaign, errors) {
|
|
|
116732
116860
|
}
|
|
116733
116861
|
}
|
|
116734
116862
|
}
|
|
116735
|
-
function calcGoogleCharLength(
|
|
116863
|
+
function calcGoogleCharLength(text4) {
|
|
116736
116864
|
let len = 0;
|
|
116737
|
-
for (const ch of
|
|
116865
|
+
for (const ch of text4) {
|
|
116738
116866
|
const code = ch.codePointAt(0) ?? 0;
|
|
116739
116867
|
if (code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 131072 && code <= 173791 || code >= 12288 && code <= 12351 || code >= 65280 && code <= 65519) {
|
|
116740
116868
|
len += 2;
|
|
@@ -117537,8 +117665,8 @@ async function reportFailedCampaignPut(opts) {
|
|
|
117537
117665
|
async function reportCampaignWrite(opts) {
|
|
117538
117666
|
const nextQuery = `siluzan-tso ad campaigns -a ${opts.account} --json-out ./snap`;
|
|
117539
117667
|
const unmatched = describeUnmatchedChecks(opts.checks);
|
|
117540
|
-
const
|
|
117541
|
-
const headline = writeVerificationHeadline(opts.verification,
|
|
117668
|
+
const text4 = opts.verification === "verified" ? opts.detail : unmatched || opts.detail;
|
|
117669
|
+
const headline = writeVerificationHeadline(opts.verification, text4);
|
|
117542
117670
|
if (opts.verification !== "verified") {
|
|
117543
117671
|
console.error(`
|
|
117544
117672
|
${headline}
|
|
@@ -120214,14 +120342,14 @@ function buildExtensionRemediateCommandLine(opts) {
|
|
|
120214
120342
|
const campaignFlag = level === "Campaign" ? `--campaign-id ${campaignId}` : "";
|
|
120215
120343
|
const base2 = ["siluzan-tso", "ad", "extension"];
|
|
120216
120344
|
if (type === "SITELINK") {
|
|
120217
|
-
const
|
|
120345
|
+
const text4 = pickString(props["Text"], props["LinkText"]);
|
|
120218
120346
|
const url = pickString(props["DestinationUrl"]);
|
|
120219
|
-
if (!
|
|
120347
|
+
if (!text4 || !url) return null;
|
|
120220
120348
|
const parts = [
|
|
120221
120349
|
...base2,
|
|
120222
120350
|
"sitelink",
|
|
120223
120351
|
`-a ${accountId}`,
|
|
120224
|
-
`--text ${shellArg(
|
|
120352
|
+
`--text ${shellArg(text4)}`,
|
|
120225
120353
|
`--url ${shellArg(url)}`
|
|
120226
120354
|
];
|
|
120227
120355
|
const line2 = pickString(props["Line2"], props["Description1"]);
|
|
@@ -120235,9 +120363,9 @@ function buildExtensionRemediateCommandLine(opts) {
|
|
|
120235
120363
|
return parts.join(" ");
|
|
120236
120364
|
}
|
|
120237
120365
|
if (type === "CALLOUT") {
|
|
120238
|
-
const
|
|
120239
|
-
if (!
|
|
120240
|
-
const parts = [...base2, "callout", `-a ${accountId}`, `--text ${shellArg(
|
|
120366
|
+
const text4 = pickString(props["Text"], props["CalloutText"]);
|
|
120367
|
+
if (!text4) return null;
|
|
120368
|
+
const parts = [...base2, "callout", `-a ${accountId}`, `--text ${shellArg(text4)}`, levelFlag];
|
|
120241
120369
|
if (campaignFlag) parts.push(campaignFlag);
|
|
120242
120370
|
parts.push(`--json-out ${jsonOut}`);
|
|
120243
120371
|
parts.push(`--commit ${shellArg("batch-diff remediate extension")}`);
|
|
@@ -120326,7 +120454,7 @@ function buildBatchOperationSlots(cfg) {
|
|
|
120326
120454
|
const campaign = asRecord3(cfg.campaign) ?? {};
|
|
120327
120455
|
const names = Array.isArray(cfg.locations) ? cfg.locations : [];
|
|
120328
120456
|
const slots = [];
|
|
120329
|
-
const push = (kind,
|
|
120457
|
+
const push = (kind, path57, label2) => slots.push({ index: slots.length, kind, path: path57, label: label2 });
|
|
120330
120458
|
push("campaign_budget", "campaign.Budget", "\u7CFB\u5217\u9884\u7B97");
|
|
120331
120459
|
push("campaign", "campaign.Name", `\u7CFB\u5217\u300C${pickText(campaign, "Name", "name") || "\u2014"}\u300D`);
|
|
120332
120460
|
pickArray(campaign, "targetedLocations", "TargetedLocations").forEach((loc, i) => {
|
|
@@ -120397,11 +120525,11 @@ function buildBatchOperationSlots(cfg) {
|
|
|
120397
120525
|
return;
|
|
120398
120526
|
}
|
|
120399
120527
|
pickArray(block, "Items", "items").forEach((it, ii) => {
|
|
120400
|
-
const
|
|
120528
|
+
const text4 = pickText(asRecord3(it), "Text", "text");
|
|
120401
120529
|
push(
|
|
120402
120530
|
"ad_group_criterion",
|
|
120403
120531
|
`${groupPath}.KeywordsForBatchJob[${bi}].Items[${ii}]`,
|
|
120404
|
-
`\u5173\u952E\u8BCD\u300C${
|
|
120532
|
+
`\u5173\u952E\u8BCD\u300C${text4}\u300D\uFF08\u7EC4\u300C${groupName}\u300D\uFF09`
|
|
120405
120533
|
);
|
|
120406
120534
|
});
|
|
120407
120535
|
});
|
|
@@ -120434,9 +120562,9 @@ function buildSubmittedOperationSlots(cfg) {
|
|
|
120434
120562
|
return buildBatchOperationSlots(clone);
|
|
120435
120563
|
}
|
|
120436
120564
|
var OP_RE = /mutate_operations\[(\d+)\]\.([a-z_]+?)_operation\.([a-z_.]+)/;
|
|
120437
|
-
function parseBatchOperationErrors(
|
|
120565
|
+
function parseBatchOperationErrors(text4) {
|
|
120438
120566
|
const out = [];
|
|
120439
|
-
for (const seg of
|
|
120567
|
+
for (const seg of text4.split(/Processing error:\s*/).slice(1)) {
|
|
120440
120568
|
const m = OP_RE.exec(seg);
|
|
120441
120569
|
if (!m) continue;
|
|
120442
120570
|
const head = seg.slice(0, m.index);
|
|
@@ -120593,8 +120721,8 @@ function pickLiveAdForPlannedRsa(plannedHeadlines, primary, unmatchedLiveAds) {
|
|
|
120593
120721
|
const [picked] = unmatchedLiveAds.splice(bestIdx, 1);
|
|
120594
120722
|
return picked ?? null;
|
|
120595
120723
|
}
|
|
120596
|
-
function livePoolHasText(pool,
|
|
120597
|
-
const t =
|
|
120724
|
+
function livePoolHasText(pool, text4) {
|
|
120725
|
+
const t = text4.trim().toLowerCase();
|
|
120598
120726
|
return t.length > 0 && pool.has(t);
|
|
120599
120727
|
}
|
|
120600
120728
|
function listPlannedRsaAssets(ad, groupPath, adIndex, adGroupName) {
|
|
@@ -120809,13 +120937,13 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120809
120937
|
for (let ki = 0; ki < texts.length; ki++) {
|
|
120810
120938
|
const t = texts[ki];
|
|
120811
120939
|
if (typeof t !== "string" || !t.trim()) continue;
|
|
120812
|
-
const
|
|
120940
|
+
const path57 = `${groupPath}.KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
120813
120941
|
const key = keywordKey(t, matchTypeV2);
|
|
120814
120942
|
const plannedContent = `\u8BCD\u9762: ${t} | \u5339\u914D: ${matchTypeV2}`;
|
|
120815
120943
|
if (groupAbsent) {
|
|
120816
120944
|
pushItem(items3, {
|
|
120817
120945
|
layer: "keyword",
|
|
120818
|
-
path:
|
|
120946
|
+
path: path57,
|
|
120819
120947
|
adGroupName: groupName,
|
|
120820
120948
|
plannedContent,
|
|
120821
120949
|
status: "skipped",
|
|
@@ -120827,7 +120955,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120827
120955
|
if (!liveKwKeys.has(key)) {
|
|
120828
120956
|
pushItem(items3, {
|
|
120829
120957
|
layer: "keyword",
|
|
120830
|
-
path:
|
|
120958
|
+
path: path57,
|
|
120831
120959
|
adGroupName: groupName,
|
|
120832
120960
|
plannedContent,
|
|
120833
120961
|
status: "missing",
|
|
@@ -120837,7 +120965,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120837
120965
|
} else {
|
|
120838
120966
|
pushItem(items3, {
|
|
120839
120967
|
layer: "keyword",
|
|
120840
|
-
path:
|
|
120968
|
+
path: path57,
|
|
120841
120969
|
adGroupName: groupName,
|
|
120842
120970
|
plannedContent,
|
|
120843
120971
|
status: "ok",
|
|
@@ -120857,7 +120985,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120857
120985
|
for (let ai = 0; ai < ads.length; ai++) {
|
|
120858
120986
|
const ad = asRecord4(ads[ai]);
|
|
120859
120987
|
if (!ad) continue;
|
|
120860
|
-
const
|
|
120988
|
+
const path57 = `${groupPath}.AdsForBatchJob[${ai}]`;
|
|
120861
120989
|
const primary = pickString2(ad["headlinePart1"], ad["AdTitle"]);
|
|
120862
120990
|
const finalUrl = pickString2(ad["Finalurl"], ad["DestinationUrl"], ad["finalUrl"]);
|
|
120863
120991
|
const rsaAssets = listPlannedRsaAssets(ad, groupPath, ai, groupName);
|
|
@@ -120866,7 +120994,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120866
120994
|
if (groupAbsent) {
|
|
120867
120995
|
pushItem(items3, {
|
|
120868
120996
|
layer: "ad",
|
|
120869
|
-
path:
|
|
120997
|
+
path: path57,
|
|
120870
120998
|
adGroupName: groupName,
|
|
120871
120999
|
adLabel,
|
|
120872
121000
|
plannedContent: primary ? `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}` : `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF09`,
|
|
@@ -120895,7 +121023,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120895
121023
|
if (!primary) {
|
|
120896
121024
|
pushItem(items3, {
|
|
120897
121025
|
layer: "ad",
|
|
120898
|
-
path:
|
|
121026
|
+
path: path57,
|
|
120899
121027
|
adGroupName: groupName,
|
|
120900
121028
|
adLabel,
|
|
120901
121029
|
plannedContent: `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF0C\u65E0\u6CD5\u6BD4\u5BF9\u6574\u6761 RSA\uFF09`,
|
|
@@ -120923,7 +121051,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120923
121051
|
const rsaFound = matchedLive != null && liveAdHasHeadline(matchedLive, primary);
|
|
120924
121052
|
pushItem(items3, {
|
|
120925
121053
|
layer: "ad",
|
|
120926
|
-
path:
|
|
121054
|
+
path: path57,
|
|
120927
121055
|
adGroupName: groupName,
|
|
120928
121056
|
adLabel,
|
|
120929
121057
|
plannedContent: `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}`,
|
|
@@ -120991,11 +121119,11 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
120991
121119
|
for (let ei = 0; ei < extBlocks.length; ei++) {
|
|
120992
121120
|
const ext = asRecord4(extBlocks[ei]);
|
|
120993
121121
|
const plannedContent = formatExtensionPlanned(ext);
|
|
120994
|
-
const
|
|
121122
|
+
const path57 = `campaign.ExtensionsForBatchJob[${ei}]`;
|
|
120995
121123
|
if (campaignMissing) {
|
|
120996
121124
|
pushItem(items3, {
|
|
120997
121125
|
layer: "extension",
|
|
120998
|
-
path:
|
|
121126
|
+
path: path57,
|
|
120999
121127
|
plannedContent,
|
|
121000
121128
|
status: "skipped",
|
|
121001
121129
|
liveNote: "\u7CFB\u5217\u672A\u627E\u5230\uFF0C\u8DF3\u8FC7\u9644\u52A0\u4FE1\u606F\u6BD4\u5BF9",
|
|
@@ -121007,7 +121135,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
121007
121135
|
const remediateCommand = !found && ext && accountId && campaignId ? buildExtensionRemediateCommandLine({ accountId, campaignId, ext }) ?? void 0 : void 0;
|
|
121008
121136
|
pushItem(items3, {
|
|
121009
121137
|
layer: "extension",
|
|
121010
|
-
path:
|
|
121138
|
+
path: path57,
|
|
121011
121139
|
plannedContent,
|
|
121012
121140
|
status: found ? "ok" : "missing",
|
|
121013
121141
|
liveNote: `\u7CFB\u5217\u7EA7\u9644\u52A0\u4FE1\u606F\u8D26\u6237\u5185 ${liveExt}/${plannedExt} \u6761`,
|
|
@@ -121034,11 +121162,11 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
121034
121162
|
if (!id) continue;
|
|
121035
121163
|
const displayName = locationNames[li] || pickString2(loc["locationName"], loc["name"], loc["countryOrRegion"]) || "";
|
|
121036
121164
|
const plannedContent = `locationId: ${id}${displayName ? ` | \u540D\u79F0: ${displayName}` : ""}`;
|
|
121037
|
-
const
|
|
121165
|
+
const path57 = `campaign.targetedLocations[${li}]`;
|
|
121038
121166
|
if (campaignMissing) {
|
|
121039
121167
|
pushItem(items3, {
|
|
121040
121168
|
layer: "location",
|
|
121041
|
-
path:
|
|
121169
|
+
path: path57,
|
|
121042
121170
|
plannedContent,
|
|
121043
121171
|
status: "skipped",
|
|
121044
121172
|
liveNote: "\u7CFB\u5217\u672A\u627E\u5230\uFF0C\u8DF3\u8FC7\u5730\u57DF\u6BD4\u5BF9",
|
|
@@ -121050,7 +121178,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
121050
121178
|
const remediateCommand = !found && accountId && campaignId ? buildGeoRemediateCommandLine({ accountId, campaignId, locationId: id }) : void 0;
|
|
121051
121179
|
pushItem(items3, {
|
|
121052
121180
|
layer: "location",
|
|
121053
|
-
path:
|
|
121181
|
+
path: path57,
|
|
121054
121182
|
plannedContent,
|
|
121055
121183
|
status: found ? "ok" : "missing",
|
|
121056
121184
|
liveNote: `\u7CFB\u5217\u5DF2\u5B9A\u5411 ${liveLocIds.size}/${plannedLocCount} \u4E2A\u5730\u57DF`,
|
|
@@ -121070,12 +121198,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
121070
121198
|
const loc = asRecord4(plannedExcl[li]);
|
|
121071
121199
|
const id = loc ? pickString2(loc["id"], loc["Id"]) : "";
|
|
121072
121200
|
if (!id) continue;
|
|
121073
|
-
const
|
|
121201
|
+
const path57 = `campaign.excludedLocations[${li}]`;
|
|
121074
121202
|
const plannedContent = `\u6392\u9664 locationId: ${id}`;
|
|
121075
121203
|
if (campaignMissing) {
|
|
121076
121204
|
pushItem(items3, {
|
|
121077
121205
|
layer: "excluded_location",
|
|
121078
|
-
path:
|
|
121206
|
+
path: path57,
|
|
121079
121207
|
plannedContent,
|
|
121080
121208
|
status: "skipped",
|
|
121081
121209
|
liveNote: "\u7CFB\u5217\u672A\u627E\u5230\uFF0C\u8DF3\u8FC7\u6392\u9664\u5730\u57DF\u6BD4\u5BF9",
|
|
@@ -121086,7 +121214,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
121086
121214
|
const found = liveExclIds.has(id);
|
|
121087
121215
|
pushItem(items3, {
|
|
121088
121216
|
layer: "excluded_location",
|
|
121089
|
-
path:
|
|
121217
|
+
path: path57,
|
|
121090
121218
|
plannedContent,
|
|
121091
121219
|
status: found ? "ok" : "missing",
|
|
121092
121220
|
liveNote: `\u7CFB\u5217\u5DF2\u6392\u9664 ${liveExclIds.size}/${plannedExclCount} \u4E2A\u5730\u57DF`,
|
|
@@ -121493,8 +121621,8 @@ function printPlanItemsByAdGroup(configFile, layer, layerItems) {
|
|
|
121493
121621
|
}
|
|
121494
121622
|
}
|
|
121495
121623
|
}
|
|
121496
|
-
function mdCell(
|
|
121497
|
-
return
|
|
121624
|
+
function mdCell(text4) {
|
|
121625
|
+
return text4.replace(/\r?\n/g, " ").replace(/\|/g, "\uFF5C").trim();
|
|
121498
121626
|
}
|
|
121499
121627
|
function statusLabel(status, lang = "zh") {
|
|
121500
121628
|
if (lang === "en") {
|
|
@@ -122342,8 +122470,8 @@ function normalizeBidding(raw) {
|
|
|
122342
122470
|
return byNum[n] ?? null;
|
|
122343
122471
|
}
|
|
122344
122472
|
function validateTextLengths(errors, lengthViolations, texts, arrayField, kind, limit, label2) {
|
|
122345
|
-
texts.forEach((
|
|
122346
|
-
const len = calcGoogleCharLength(
|
|
122473
|
+
texts.forEach((text4, i) => {
|
|
122474
|
+
const len = calcGoogleCharLength(text4);
|
|
122347
122475
|
if (len > limit) {
|
|
122348
122476
|
const field = `${arrayField}[${i}]`;
|
|
122349
122477
|
pushLengthViolation(lengthViolations, {
|
|
@@ -122353,9 +122481,9 @@ function validateTextLengths(errors, lengthViolations, texts, arrayField, kind,
|
|
|
122353
122481
|
limit,
|
|
122354
122482
|
actual: len,
|
|
122355
122483
|
countMode: "google",
|
|
122356
|
-
text:
|
|
122484
|
+
text: text4
|
|
122357
122485
|
});
|
|
122358
|
-
pushErr3(errors, `${label2}[${i}] \u8D85\u8FC7 ${limit} \u5B57\u7B26\uFF08\u5F53\u524D ${len}\uFF0CCJK \u8BA1 2\uFF09\uFF1A"${
|
|
122486
|
+
pushErr3(errors, `${label2}[${i}] \u8D85\u8FC7 ${limit} \u5B57\u7B26\uFF08\u5F53\u524D ${len}\uFF0CCJK \u8BA1 2\uFF09\uFF1A"${text4}"`);
|
|
122359
122487
|
}
|
|
122360
122488
|
});
|
|
122361
122489
|
}
|
|
@@ -122766,8 +122894,8 @@ function pmaxChannelTypesUrl(googleApiUrl) {
|
|
|
122766
122894
|
}
|
|
122767
122895
|
function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
|
|
122768
122896
|
const base2 = googleApiUrl.replace(/\/$/, "");
|
|
122769
|
-
const
|
|
122770
|
-
return campaignId ? `${
|
|
122897
|
+
const path57 = `${base2}/accounts/${accountId}/campaign/pmax`;
|
|
122898
|
+
return campaignId ? `${path57}/${campaignId}` : path57;
|
|
122771
122899
|
}
|
|
122772
122900
|
function pmaxBrandAssetsUrl(googleApiUrl, accountId, campaignId) {
|
|
122773
122901
|
return `${pmaxCampaignUrl(googleApiUrl, accountId, campaignId)}/brand-assets`;
|
|
@@ -122777,8 +122905,8 @@ function pmaxBrandGuidelinesEnableUrl(googleApiUrl, accountId, campaignId) {
|
|
|
122777
122905
|
}
|
|
122778
122906
|
function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
|
|
122779
122907
|
const base2 = googleApiUrl.replace(/\/$/, "");
|
|
122780
|
-
const
|
|
122781
|
-
return suffix ? `${
|
|
122908
|
+
const path57 = `${base2}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
|
|
122909
|
+
return suffix ? `${path57}/${suffix.replace(/^\//, "")}` : path57;
|
|
122782
122910
|
}
|
|
122783
122911
|
function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
|
|
122784
122912
|
const base2 = googleApiUrl.replace(/\/$/, "");
|
|
@@ -122887,14 +123015,14 @@ async function uploadPmaxImageFileMultipart(config, googleApiUrl, accountId, abs
|
|
|
122887
123015
|
if (config.apiKey) headers["x-api-key"] = config.apiKey;
|
|
122888
123016
|
else headers.Authorization = `Bearer ${config.authToken}`;
|
|
122889
123017
|
const res = await fetch(url, { method: "POST", headers, body: form });
|
|
122890
|
-
const
|
|
123018
|
+
const text4 = await res.text();
|
|
122891
123019
|
if (!res.ok) {
|
|
122892
|
-
const detail = verbose ? `\uFF1A${
|
|
123020
|
+
const detail = verbose ? `\uFF1A${text4.slice(0, 300)}` : "";
|
|
122893
123021
|
throw new Error(`\u4E0A\u4F20\u56FE\u7247\u8D44\u4EA7 HTTP ${res.status}${detail}\uFF08${absImagePath}\uFF09`);
|
|
122894
123022
|
}
|
|
122895
123023
|
let data;
|
|
122896
123024
|
try {
|
|
122897
|
-
data = JSON.parse(
|
|
123025
|
+
data = JSON.parse(text4);
|
|
122898
123026
|
} catch {
|
|
122899
123027
|
throw new Error(`\u4E0A\u4F20\u56FE\u7247\u8D44\u4EA7\u54CD\u5E94\u975E JSON\uFF08${absImagePath}\uFF09`);
|
|
122900
123028
|
}
|
|
@@ -123034,9 +123162,9 @@ init_shared();
|
|
|
123034
123162
|
// src/commands/ad/pmax-create-http-error.ts
|
|
123035
123163
|
function normalizePmaxResumeId(value) {
|
|
123036
123164
|
if (value == null) return null;
|
|
123037
|
-
const
|
|
123038
|
-
if (!
|
|
123039
|
-
return
|
|
123165
|
+
const text4 = String(value).trim();
|
|
123166
|
+
if (!text4 || text4.toLowerCase() === "null") return null;
|
|
123167
|
+
return text4;
|
|
123040
123168
|
}
|
|
123041
123169
|
function quoteLongResumeIds(rawBody) {
|
|
123042
123170
|
return rawBody.replace(
|
|
@@ -123045,11 +123173,11 @@ function quoteLongResumeIds(rawBody) {
|
|
|
123045
123173
|
);
|
|
123046
123174
|
}
|
|
123047
123175
|
function parsePmaxCreateFailureBody(rawBody) {
|
|
123048
|
-
const
|
|
123049
|
-
if (!
|
|
123176
|
+
const text4 = rawBody.trim();
|
|
123177
|
+
if (!text4.startsWith("{")) return null;
|
|
123050
123178
|
let parsed;
|
|
123051
123179
|
try {
|
|
123052
|
-
parsed = JSON.parse(quoteLongResumeIds(
|
|
123180
|
+
parsed = JSON.parse(quoteLongResumeIds(text4));
|
|
123053
123181
|
} catch {
|
|
123054
123182
|
return null;
|
|
123055
123183
|
}
|
|
@@ -123169,19 +123297,19 @@ function validatePmaxSitelinkSpec(link, prefix, errors, warnings) {
|
|
|
123169
123297
|
errors.push(`${prefix} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
123170
123298
|
return;
|
|
123171
123299
|
}
|
|
123172
|
-
const
|
|
123300
|
+
const text4 = link.text?.trim();
|
|
123173
123301
|
const url = link.destinationUrl?.trim();
|
|
123174
|
-
if (!
|
|
123302
|
+
if (!text4) errors.push(`${prefix}.text \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
123175
123303
|
if (!url) {
|
|
123176
123304
|
errors.push(`${prefix}.destinationUrl \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
123177
123305
|
} else if (!/^https?:\/\/.+/i.test(url)) {
|
|
123178
123306
|
errors.push(`${prefix}.destinationUrl \u683C\u5F0F\u4E0D\u6B63\u786E\uFF1A${url}`);
|
|
123179
123307
|
}
|
|
123180
|
-
if (
|
|
123308
|
+
if (text4 && url) {
|
|
123181
123309
|
validateSitelinkProperties(
|
|
123182
123310
|
prefix,
|
|
123183
123311
|
{
|
|
123184
|
-
Text:
|
|
123312
|
+
Text: text4,
|
|
123185
123313
|
DestinationUrl: url,
|
|
123186
123314
|
Line2: link.line2?.trim() ?? "",
|
|
123187
123315
|
Line3: link.line3?.trim() ?? ""
|
|
@@ -123232,16 +123360,16 @@ function convertExtensionsForBatchJobToCampaignExtensions(items3) {
|
|
|
123232
123360
|
const type = String(ext.typeV2 ?? ext.TypeV2 ?? ext.AssetFieldType ?? "").toUpperCase();
|
|
123233
123361
|
const props = ext.Properties ?? {};
|
|
123234
123362
|
if (type === "CALLOUT") {
|
|
123235
|
-
const
|
|
123236
|
-
if (
|
|
123363
|
+
const text4 = String(props.Text ?? props.CalloutText ?? "").trim();
|
|
123364
|
+
if (text4) config.callouts.push(text4);
|
|
123237
123365
|
continue;
|
|
123238
123366
|
}
|
|
123239
123367
|
if (type === "SITELINK") {
|
|
123240
|
-
const
|
|
123368
|
+
const text4 = String(props.Text ?? props.LinkText ?? "").trim();
|
|
123241
123369
|
const destinationUrl = String(props.DestinationUrl ?? "").trim();
|
|
123242
|
-
if (
|
|
123370
|
+
if (text4 && destinationUrl) {
|
|
123243
123371
|
config.sitelinks.push({
|
|
123244
|
-
text:
|
|
123372
|
+
text: text4,
|
|
123245
123373
|
destinationUrl,
|
|
123246
123374
|
line2: String(props.Line2 ?? props.Description1 ?? "").trim() || void 0,
|
|
123247
123375
|
line3: String(props.Line3 ?? props.Description2 ?? "").trim() || void 0
|
|
@@ -123310,14 +123438,14 @@ function validatePmaxCampaignExtensions(ext, opts) {
|
|
|
123310
123438
|
}
|
|
123311
123439
|
const callouts = ext.callouts ?? [];
|
|
123312
123440
|
for (let i = 0; i < callouts.length; i++) {
|
|
123313
|
-
const
|
|
123314
|
-
if (!
|
|
123441
|
+
const text4 = callouts[i]?.trim();
|
|
123442
|
+
if (!text4) {
|
|
123315
123443
|
errors.push(`campaignExtensions.callouts[${i}] \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
123316
123444
|
continue;
|
|
123317
123445
|
}
|
|
123318
|
-
if (
|
|
123446
|
+
if (text4.length > CALLOUT_TEXT_MAX_LEN) {
|
|
123319
123447
|
errors.push(
|
|
123320
|
-
`campaignExtensions.callouts[${i}] \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${
|
|
123448
|
+
`campaignExtensions.callouts[${i}] \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${text4.length}\uFF09\uFF1A"${text4}"`
|
|
123321
123449
|
);
|
|
123322
123450
|
}
|
|
123323
123451
|
}
|
|
@@ -123390,14 +123518,14 @@ async function postExtension(config, googleApiUrl, accountId, body, verbose) {
|
|
|
123390
123518
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
123391
123519
|
}
|
|
123392
123520
|
}
|
|
123393
|
-
function buildCalloutBody(accountId, campaignId,
|
|
123521
|
+
function buildCalloutBody(accountId, campaignId, text4) {
|
|
123394
123522
|
return {
|
|
123395
123523
|
activeuseridg: accountId,
|
|
123396
123524
|
campaignId,
|
|
123397
123525
|
level: "Campaign",
|
|
123398
123526
|
typeV2: "CALLOUT",
|
|
123399
123527
|
assetFieldType: "CALLOUT",
|
|
123400
|
-
properties: { Text:
|
|
123528
|
+
properties: { Text: text4.trim() }
|
|
123401
123529
|
};
|
|
123402
123530
|
}
|
|
123403
123531
|
function buildSnippetBody(accountId, campaignId, header, values) {
|
|
@@ -123414,8 +123542,8 @@ function buildSnippetBody(accountId, campaignId, header, values) {
|
|
|
123414
123542
|
};
|
|
123415
123543
|
}
|
|
123416
123544
|
function buildSitelinkBody(accountId, campaignId, link) {
|
|
123417
|
-
const
|
|
123418
|
-
const line2 = link.line2?.trim() ||
|
|
123545
|
+
const text4 = link.text.trim();
|
|
123546
|
+
const line2 = link.line2?.trim() || text4;
|
|
123419
123547
|
const line3 = link.line3?.trim() || line2;
|
|
123420
123548
|
return {
|
|
123421
123549
|
activeuseridg: accountId,
|
|
@@ -123424,7 +123552,7 @@ function buildSitelinkBody(accountId, campaignId, link) {
|
|
|
123424
123552
|
typeV2: "SITELINK",
|
|
123425
123553
|
assetFieldType: "SITELINK",
|
|
123426
123554
|
properties: {
|
|
123427
|
-
Text:
|
|
123555
|
+
Text: text4,
|
|
123428
123556
|
Line2: line2,
|
|
123429
123557
|
Line3: line3,
|
|
123430
123558
|
DestinationUrl: link.destinationUrl.trim()
|
|
@@ -123452,26 +123580,26 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
123452
123580
|
allOk: true
|
|
123453
123581
|
};
|
|
123454
123582
|
for (const raw of ext.callouts ?? []) {
|
|
123455
|
-
const
|
|
123456
|
-
if (!
|
|
123583
|
+
const text4 = raw?.trim();
|
|
123584
|
+
if (!text4) continue;
|
|
123457
123585
|
if (opts.logProgress) console.log(`
|
|
123458
|
-
\u6302\u8F7D\u5BA3\u4F20\u4FE1\u606F\uFF1A${
|
|
123586
|
+
\u6302\u8F7D\u5BA3\u4F20\u4FE1\u606F\uFF1A${text4}`);
|
|
123459
123587
|
const posted = await postExtension(
|
|
123460
123588
|
opts.config,
|
|
123461
123589
|
opts.googleApiUrl,
|
|
123462
123590
|
opts.accountId,
|
|
123463
|
-
buildCalloutBody(opts.accountId, opts.campaignId,
|
|
123591
|
+
buildCalloutBody(opts.accountId, opts.campaignId, text4),
|
|
123464
123592
|
opts.verbose
|
|
123465
123593
|
);
|
|
123466
123594
|
if (posted.ok) {
|
|
123467
123595
|
result.callouts.push({
|
|
123468
123596
|
ok: true,
|
|
123469
123597
|
id: String(posted.data["id"] ?? ""),
|
|
123470
|
-
label:
|
|
123598
|
+
label: text4
|
|
123471
123599
|
});
|
|
123472
123600
|
} else {
|
|
123473
123601
|
result.allOk = false;
|
|
123474
|
-
result.callouts.push({ ok: false, error: posted.error, label:
|
|
123602
|
+
result.callouts.push({ ok: false, error: posted.error, label: text4 });
|
|
123475
123603
|
}
|
|
123476
123604
|
}
|
|
123477
123605
|
for (const s of ext.structuredSnippets ?? []) {
|
|
@@ -123500,11 +123628,11 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
123500
123628
|
}
|
|
123501
123629
|
}
|
|
123502
123630
|
for (const link of ext.sitelinks ?? []) {
|
|
123503
|
-
const
|
|
123631
|
+
const text4 = link?.text?.trim();
|
|
123504
123632
|
const url = link?.destinationUrl?.trim();
|
|
123505
|
-
if (!
|
|
123633
|
+
if (!text4 || !url) continue;
|
|
123506
123634
|
if (opts.logProgress) console.log(`
|
|
123507
|
-
\u6302\u8F7D\u7AD9\u5185\u94FE\u63A5\uFF1A${
|
|
123635
|
+
\u6302\u8F7D\u7AD9\u5185\u94FE\u63A5\uFF1A${text4} \u2192 ${url}`);
|
|
123508
123636
|
const posted = await postExtension(
|
|
123509
123637
|
opts.config,
|
|
123510
123638
|
opts.googleApiUrl,
|
|
@@ -123516,11 +123644,11 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
123516
123644
|
result.sitelinks.push({
|
|
123517
123645
|
ok: true,
|
|
123518
123646
|
id: String(posted.data["id"] ?? ""),
|
|
123519
|
-
label:
|
|
123647
|
+
label: text4
|
|
123520
123648
|
});
|
|
123521
123649
|
} else {
|
|
123522
123650
|
result.allOk = false;
|
|
123523
|
-
result.sitelinks.push({ ok: false, error: posted.error, label:
|
|
123651
|
+
result.sitelinks.push({ ok: false, error: posted.error, label: text4 });
|
|
123524
123652
|
}
|
|
123525
123653
|
}
|
|
123526
123654
|
if (ext.leadForm) {
|
|
@@ -123996,13 +124124,13 @@ function runPmaxVideoValidation(configFile, cfg) {
|
|
|
123996
124124
|
async function fetchVideoUploadStatus(config, googleApiUrl, mediaAccountId, resourceName, verbose) {
|
|
123997
124125
|
const url = pyapiVideoStatusUrl(googleApiUrl, mediaAccountId, resourceName);
|
|
123998
124126
|
const res = await fetch(url, { method: "GET", headers: authHeaders(config) });
|
|
123999
|
-
const
|
|
124127
|
+
const text4 = await res.text();
|
|
124000
124128
|
if (!res.ok) {
|
|
124001
|
-
const detail = verbose ? `\uFF1A${
|
|
124129
|
+
const detail = verbose ? `\uFF1A${text4.slice(0, 300)}` : "";
|
|
124002
124130
|
throw new Error(`\u67E5\u8BE2\u89C6\u9891\u5904\u7406\u72B6\u6001 HTTP ${res.status}${detail}`);
|
|
124003
124131
|
}
|
|
124004
124132
|
try {
|
|
124005
|
-
return JSON.parse(
|
|
124133
|
+
return JSON.parse(text4);
|
|
124006
124134
|
} catch {
|
|
124007
124135
|
throw new Error("\u67E5\u8BE2\u89C6\u9891\u5904\u7406\u72B6\u6001\u54CD\u5E94\u975E JSON");
|
|
124008
124136
|
}
|
|
@@ -124058,14 +124186,14 @@ async function uploadPmaxLocalVideo(opts) {
|
|
|
124058
124186
|
);
|
|
124059
124187
|
const url = pyapiVideoUploadUrl(opts.googleApiUrl);
|
|
124060
124188
|
const res = await fetch(url, { method: "POST", headers: authHeaders(opts.config), body: form });
|
|
124061
|
-
const
|
|
124189
|
+
const text4 = await res.text();
|
|
124062
124190
|
if (!res.ok) {
|
|
124063
|
-
const detail = opts.verbose ? `\uFF1A${
|
|
124191
|
+
const detail = opts.verbose ? `\uFF1A${text4.slice(0, 400)}` : "";
|
|
124064
124192
|
throw new Error(`\u4E0A\u4F20\u89C6\u9891 HTTP ${res.status}${detail}\uFF08${opts.absVideoPath}\uFF09`);
|
|
124065
124193
|
}
|
|
124066
124194
|
let data;
|
|
124067
124195
|
try {
|
|
124068
|
-
data = JSON.parse(
|
|
124196
|
+
data = JSON.parse(text4);
|
|
124069
124197
|
} catch {
|
|
124070
124198
|
throw new Error(`\u4E0A\u4F20\u89C6\u9891\u54CD\u5E94\u975E JSON\uFF08${opts.absVideoPath}\uFF09`);
|
|
124071
124199
|
}
|
|
@@ -125760,8 +125888,8 @@ async function runAdPmaxImageConvert(opts) {
|
|
|
125760
125888
|
}
|
|
125761
125889
|
|
|
125762
125890
|
// src/commands/ad/pmax-brand-mgmt.ts
|
|
125763
|
-
function loadBrandConfig(
|
|
125764
|
-
const cfg = loadPmaxJsonFile(
|
|
125891
|
+
function loadBrandConfig(path57, accountId, campaignId) {
|
|
125892
|
+
const cfg = loadPmaxJsonFile(path57);
|
|
125765
125893
|
return {
|
|
125766
125894
|
...cfg,
|
|
125767
125895
|
account: String(cfg["account"] ?? accountId).trim(),
|
|
@@ -125944,16 +126072,16 @@ function quoteLongResumeIds2(rawBody) {
|
|
|
125944
126072
|
}
|
|
125945
126073
|
function normalizeResumeId(value) {
|
|
125946
126074
|
if (value == null) return null;
|
|
125947
|
-
const
|
|
125948
|
-
if (!
|
|
125949
|
-
return
|
|
126075
|
+
const text4 = String(value).trim();
|
|
126076
|
+
if (!text4 || text4.toLowerCase() === "null") return null;
|
|
126077
|
+
return text4;
|
|
125950
126078
|
}
|
|
125951
126079
|
function parseDemandGenCreateFailure(rawBody) {
|
|
125952
|
-
const
|
|
125953
|
-
if (!
|
|
126080
|
+
const text4 = rawBody.trim();
|
|
126081
|
+
if (!text4.startsWith("{")) return null;
|
|
125954
126082
|
let parsed;
|
|
125955
126083
|
try {
|
|
125956
|
-
parsed = JSON.parse(quoteLongResumeIds2(
|
|
126084
|
+
parsed = JSON.parse(quoteLongResumeIds2(text4));
|
|
125957
126085
|
} catch {
|
|
125958
126086
|
return null;
|
|
125959
126087
|
}
|
|
@@ -126009,10 +126137,10 @@ function decorateDemandGenRead(value) {
|
|
|
126009
126137
|
}
|
|
126010
126138
|
function normalizeCampaignStatus(raw) {
|
|
126011
126139
|
if (raw == null || String(raw).trim() === "") return null;
|
|
126012
|
-
const
|
|
126013
|
-
if (
|
|
126014
|
-
if (
|
|
126015
|
-
if (
|
|
126140
|
+
const text4 = String(raw).trim().toLowerCase();
|
|
126141
|
+
if (text4 === "enabled" || text4 === "2") return "Enabled";
|
|
126142
|
+
if (text4 === "paused" || text4 === "3") return "Paused";
|
|
126143
|
+
if (text4 === "removed" || text4 === "4") return "Removed";
|
|
126016
126144
|
return null;
|
|
126017
126145
|
}
|
|
126018
126146
|
function normalizeAdStatus(raw) {
|
|
@@ -126116,12 +126244,12 @@ function demandGenConversionsValidateUrl(googleApiUrl, accountId) {
|
|
|
126116
126244
|
return `${demandGenCollectionUrl(googleApiUrl, accountId)}/conversions/validate`;
|
|
126117
126245
|
}
|
|
126118
126246
|
function demandGenAdGroupUrl(googleApiUrl, accountId, campaignId, adGroupId, suffix) {
|
|
126119
|
-
const
|
|
126120
|
-
return suffix ? `${
|
|
126247
|
+
const path57 = `${demandGenCampaignUrl(googleApiUrl, accountId, campaignId)}/ad-groups/${adGroupId}`;
|
|
126248
|
+
return suffix ? `${path57}/${suffix.replace(/^\//, "")}` : path57;
|
|
126121
126249
|
}
|
|
126122
126250
|
function demandGenAdUrl(googleApiUrl, accountId, campaignId, adGroupId, adId, suffix) {
|
|
126123
|
-
const
|
|
126124
|
-
return suffix ? `${
|
|
126251
|
+
const path57 = `${demandGenAdGroupUrl(googleApiUrl, accountId, campaignId, adGroupId)}/ads/${adId}`;
|
|
126252
|
+
return suffix ? `${path57}/${suffix.replace(/^\//, "")}` : path57;
|
|
126125
126253
|
}
|
|
126126
126254
|
function demandGenChannelReportUrl(googleApiUrl, accountId, campaignId, startDate, endDate) {
|
|
126127
126255
|
const params = new URLSearchParams({ startDate, endDate });
|
|
@@ -126225,7 +126353,7 @@ function explainCreateError(err) {
|
|
|
126225
126353
|
if (failure) return demandGenResumeHint(failure);
|
|
126226
126354
|
return err instanceof Error ? err.message : String(err);
|
|
126227
126355
|
}
|
|
126228
|
-
async function postCreate(opts,
|
|
126356
|
+
async function postCreate(opts, path57, commandLabel) {
|
|
126229
126357
|
const accountId = requireAccountId(opts.account);
|
|
126230
126358
|
const raw = loadBody(opts.configFile);
|
|
126231
126359
|
await withGoogleApi(opts, async (config, googleApiUrl) => {
|
|
@@ -126237,7 +126365,7 @@ async function postCreate(opts, path56, commandLabel) {
|
|
|
126237
126365
|
fail(err instanceof Error ? err.message : String(err));
|
|
126238
126366
|
}
|
|
126239
126367
|
printIssues(demandGenCreateIssues(body));
|
|
126240
|
-
const url =
|
|
126368
|
+
const url = path57 ? `${demandGenCollectionUrl(googleApiUrl, accountId)}/${path57}` : demandGenCollectionUrl(googleApiUrl, accountId);
|
|
126241
126369
|
let data;
|
|
126242
126370
|
try {
|
|
126243
126371
|
data = await pmaxApiFetch(
|
|
@@ -126250,7 +126378,7 @@ async function postCreate(opts, path56, commandLabel) {
|
|
|
126250
126378
|
fail(explainCreateError(err));
|
|
126251
126379
|
}
|
|
126252
126380
|
const payload = decorateDemandGenRead(data);
|
|
126253
|
-
if (await emit({ ...opts, account: accountId }, `ad-demand-gen-${
|
|
126381
|
+
if (await emit({ ...opts, account: accountId }, `ad-demand-gen-${path57 || "create"}`, commandLabel, payload, accountId)) {
|
|
126254
126382
|
return;
|
|
126255
126383
|
}
|
|
126256
126384
|
console.log(`
|
|
@@ -128392,15 +128520,15 @@ function formatMetaAdError(err) {
|
|
|
128392
128520
|
}
|
|
128393
128521
|
return appendMetaAdErrorHint(raw);
|
|
128394
128522
|
}
|
|
128395
|
-
function appendMetaAdErrorHint(
|
|
128396
|
-
if (!/advantage_audience|targeting_automation/i.test(
|
|
128397
|
-
return `${
|
|
128523
|
+
function appendMetaAdErrorHint(text4) {
|
|
128524
|
+
if (!/advantage_audience|targeting_automation/i.test(text4)) return text4;
|
|
128525
|
+
return `${text4}
|
|
128398
128526
|
\u63D0\u793A\uFF1Acreate / adset-create \u5DF2\u63D0\u4EA4 targeting_automation.advantage_audience\uFF08\u9ED8\u8BA4 1\uFF1B\u6709 flexibleSpec \u65F6\u9ED8\u8BA4 0\uFF09\u3002
|
|
128399
128527
|
\u4E0D\u8981\u65B0\u5EFA\u7CFB\u5217\u3002\u7528 --json-out \u91CC\u5DF2\u5EFA\u6210\u7684 campaignId \u8DD1 adset-create \u7EED\u8DD1\uFF1B\u7EC6\u5B9A\u5411\u53EF\u663E\u5F0F\u8BBE adset.advantageAudience=0\u3002`;
|
|
128400
128528
|
}
|
|
128401
128529
|
function isBidAmountRequired(err) {
|
|
128402
|
-
const
|
|
128403
|
-
return /BID_AMOUNT_REQUIRED/i.test(
|
|
128530
|
+
const text4 = formatMetaAdError(err);
|
|
128531
|
+
return /BID_AMOUNT_REQUIRED/i.test(text4) || /缺少竞价金额/.test(text4) || /必须提供 bid_amount/.test(text4) || /必须在 bid_amount/.test(text4);
|
|
128404
128532
|
}
|
|
128405
128533
|
function failMetaAd(action, err) {
|
|
128406
128534
|
console.error(`
|
|
@@ -128469,9 +128597,9 @@ function metaAdContext(token) {
|
|
|
128469
128597
|
const config = loadConfig(token);
|
|
128470
128598
|
return { config, facebookApiUrl: requireFacebookApi(config) };
|
|
128471
128599
|
}
|
|
128472
|
-
function adsUrl(facebookApiUrl, account,
|
|
128600
|
+
function adsUrl(facebookApiUrl, account, path57) {
|
|
128473
128601
|
const base2 = metaAdsBaseUrl(facebookApiUrl, account);
|
|
128474
|
-
const p =
|
|
128602
|
+
const p = path57.startsWith("/") ? path57 : `/${path57}`;
|
|
128475
128603
|
return `${base2}${p}`;
|
|
128476
128604
|
}
|
|
128477
128605
|
async function metaAdGet(url, config, verbose, action) {
|
|
@@ -129678,9 +129806,9 @@ async function runMetaAdForms(opts) {
|
|
|
129678
129806
|
if (opts.after) params.set("after", opts.after);
|
|
129679
129807
|
if (opts.before) params.set("before", opts.before);
|
|
129680
129808
|
const qs = params.toString();
|
|
129681
|
-
const
|
|
129809
|
+
const path57 = `/pages/${encodeURIComponent(opts.pageId)}/forms${qs ? `?${qs}` : ""}`;
|
|
129682
129810
|
const raw = await metaAdGet(
|
|
129683
|
-
adsUrl(facebookApiUrl, digits,
|
|
129811
|
+
adsUrl(facebookApiUrl, digits, path57),
|
|
129684
129812
|
config,
|
|
129685
129813
|
opts.verbose,
|
|
129686
129814
|
"\u5217\u8868\u5355\u5931\u8D25"
|
|
@@ -129799,8 +129927,8 @@ var QUESTION_TYPE_LABEL = {
|
|
|
129799
129927
|
JOB_TITLE: "Job Title",
|
|
129800
129928
|
CUSTOM: "Custom"
|
|
129801
129929
|
};
|
|
129802
|
-
function chrome(
|
|
129803
|
-
return lang === "en" ? applyEnglishPhrases(
|
|
129930
|
+
function chrome(text4, lang) {
|
|
129931
|
+
return lang === "en" ? applyEnglishPhrases(text4) : text4;
|
|
129804
129932
|
}
|
|
129805
129933
|
function text2(value) {
|
|
129806
129934
|
if (value == null) return PENDING;
|
|
@@ -131185,9 +131313,9 @@ async function fetchAccountPositiveKeywordNormSet(config, googleApiUrl, accountI
|
|
|
131185
131313
|
if (seenIds.has(id)) continue;
|
|
131186
131314
|
seenIds.add(id);
|
|
131187
131315
|
}
|
|
131188
|
-
const
|
|
131189
|
-
if (!
|
|
131190
|
-
const norm = normalizeKeywordForAccountMatch(
|
|
131316
|
+
const text4 = extractKeywordTextFromManagementRow(row);
|
|
131317
|
+
if (!text4) continue;
|
|
131318
|
+
const norm = normalizeKeywordForAccountMatch(text4);
|
|
131191
131319
|
if (norm) normSet.add(norm);
|
|
131192
131320
|
}
|
|
131193
131321
|
return normSet;
|
|
@@ -131781,8 +131909,8 @@ function similarityPercent(score) {
|
|
|
131781
131909
|
const s = Math.min(1, Math.max(0, score));
|
|
131782
131910
|
return `${Math.round(s * 100)}%`;
|
|
131783
131911
|
}
|
|
131784
|
-
function blockquoteMarkdown(
|
|
131785
|
-
return
|
|
131912
|
+
function blockquoteMarkdown(text4) {
|
|
131913
|
+
return text4.split("\n").map((line) => `> ${line}`).join("\n");
|
|
131786
131914
|
}
|
|
131787
131915
|
function formatTime(iso) {
|
|
131788
131916
|
if (!iso) return "";
|
|
@@ -132450,8 +132578,8 @@ function assertGoogleMediaCustomerId(raw) {
|
|
|
132450
132578
|
process.exit(1);
|
|
132451
132579
|
}
|
|
132452
132580
|
}
|
|
132453
|
-
function parseCustomerAccessPermissionBody(
|
|
132454
|
-
const trimmed =
|
|
132581
|
+
function parseCustomerAccessPermissionBody(text4) {
|
|
132582
|
+
const trimmed = text4.trim();
|
|
132455
132583
|
if (!trimmed) return null;
|
|
132456
132584
|
try {
|
|
132457
132585
|
const parsed = JSON.parse(trimmed);
|
|
@@ -132493,8 +132621,8 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
|
|
|
132493
132621
|
};
|
|
132494
132622
|
}
|
|
132495
132623
|
if (httpStatus === 403) {
|
|
132496
|
-
const
|
|
132497
|
-
if (
|
|
132624
|
+
const text4 = typeof rawBody === "string" ? rawBody : rawBody == null ? "" : String(rawBody);
|
|
132625
|
+
if (text4.includes("token\u4E0D\u80FD\u4E3A\u7A7A") || text4.toLowerCase().includes("token") && text4.includes("\u7A7A")) {
|
|
132498
132626
|
return {
|
|
132499
132627
|
...base2,
|
|
132500
132628
|
status: "google_not_bound",
|
|
@@ -134409,12 +134537,12 @@ async function uploadAttachment(filePath, apiBaseUrl, config, verbose) {
|
|
|
134409
134537
|
headers,
|
|
134410
134538
|
body: form
|
|
134411
134539
|
});
|
|
134412
|
-
const
|
|
134540
|
+
const text4 = await res.text();
|
|
134413
134541
|
if (!res.ok) {
|
|
134414
|
-
const detail = verbose ? `\uFF1A${
|
|
134542
|
+
const detail = verbose ? `\uFF1A${text4.slice(0, 300)}` : "";
|
|
134415
134543
|
throw new Error(`\u4E0A\u4F20\u6587\u4EF6 HTTP ${res.status}${detail}`);
|
|
134416
134544
|
}
|
|
134417
|
-
const data = JSON.parse(
|
|
134545
|
+
const data = JSON.parse(text4);
|
|
134418
134546
|
if (!data.id) {
|
|
134419
134547
|
throw new Error("\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25\uFF1A\u54CD\u5E94\u4E2D\u672A\u5305\u542B\u6587\u4EF6 ID");
|
|
134420
134548
|
}
|
|
@@ -136160,9 +136288,9 @@ init_cli_json_snapshot();
|
|
|
136160
136288
|
import fs15 from "fs";
|
|
136161
136289
|
import path20 from "path";
|
|
136162
136290
|
function readJson(filePath) {
|
|
136163
|
-
const
|
|
136291
|
+
const text4 = fs15.readFileSync(filePath, "utf8");
|
|
136164
136292
|
try {
|
|
136165
|
-
const v = JSON.parse(
|
|
136293
|
+
const v = JSON.parse(text4);
|
|
136166
136294
|
if (!v || typeof v !== "object" || Array.isArray(v)) {
|
|
136167
136295
|
throw new Error("\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
136168
136296
|
}
|
|
@@ -136271,9 +136399,9 @@ function websiteDiagnosisRuntimePath() {
|
|
|
136271
136399
|
}
|
|
136272
136400
|
function readJsonFile(filePath) {
|
|
136273
136401
|
const raw = fsPromises.readFile(filePath, "utf8");
|
|
136274
|
-
return raw.then((
|
|
136402
|
+
return raw.then((text4) => {
|
|
136275
136403
|
try {
|
|
136276
|
-
return JSON.parse(
|
|
136404
|
+
return JSON.parse(text4);
|
|
136277
136405
|
} catch {
|
|
136278
136406
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
136279
136407
|
}
|
|
@@ -138655,9 +138783,9 @@ function asRecord12(value) {
|
|
|
138655
138783
|
}
|
|
138656
138784
|
return null;
|
|
138657
138785
|
}
|
|
138658
|
-
function getNestedValue(root,
|
|
138786
|
+
function getNestedValue(root, path57) {
|
|
138659
138787
|
let cur = root;
|
|
138660
|
-
for (const key of
|
|
138788
|
+
for (const key of path57) {
|
|
138661
138789
|
const rec = asRecord12(cur);
|
|
138662
138790
|
if (!rec) return void 0;
|
|
138663
138791
|
cur = rec[key];
|
|
@@ -139049,7 +139177,7 @@ function collectGoldClaimTexts(data) {
|
|
|
139049
139177
|
if (rec) texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
|
|
139050
139178
|
}
|
|
139051
139179
|
}
|
|
139052
|
-
return texts.filter((
|
|
139180
|
+
return texts.filter((text4) => text4.trim().length > 0);
|
|
139053
139181
|
}
|
|
139054
139182
|
function findIdenticalTexts(texts, minCount) {
|
|
139055
139183
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -139057,8 +139185,8 @@ function findIdenticalTexts(texts, minCount) {
|
|
|
139057
139185
|
if (!t) continue;
|
|
139058
139186
|
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
139059
139187
|
}
|
|
139060
|
-
for (const [
|
|
139061
|
-
if (count2 >= minCount) return
|
|
139188
|
+
for (const [text4, count2] of counts) {
|
|
139189
|
+
if (count2 >= minCount) return text4;
|
|
139062
139190
|
}
|
|
139063
139191
|
return null;
|
|
139064
139192
|
}
|
|
@@ -139131,20 +139259,20 @@ function asRecord15(value) {
|
|
|
139131
139259
|
}
|
|
139132
139260
|
return null;
|
|
139133
139261
|
}
|
|
139134
|
-
function proseColonIndex(
|
|
139135
|
-
const cn =
|
|
139136
|
-
if (cn > 0 && cn <
|
|
139137
|
-
for (let i = 1; i <
|
|
139138
|
-
if (
|
|
139139
|
-
if (
|
|
139140
|
-
const scheme =
|
|
139262
|
+
function proseColonIndex(text4) {
|
|
139263
|
+
const cn = text4.indexOf("\uFF1A");
|
|
139264
|
+
if (cn > 0 && cn < text4.length - 1) return cn;
|
|
139265
|
+
for (let i = 1; i < text4.length - 1; i++) {
|
|
139266
|
+
if (text4[i] !== ":") continue;
|
|
139267
|
+
if (text4[i + 1] === "/") continue;
|
|
139268
|
+
const scheme = text4.slice(Math.max(0, i - 5), i);
|
|
139141
139269
|
if (/https?$/i.test(scheme)) continue;
|
|
139142
139270
|
return i;
|
|
139143
139271
|
}
|
|
139144
139272
|
return -1;
|
|
139145
139273
|
}
|
|
139146
|
-
function splitOverviewProse(
|
|
139147
|
-
const trimmed =
|
|
139274
|
+
function splitOverviewProse(text4) {
|
|
139275
|
+
const trimmed = text4.trim();
|
|
139148
139276
|
const cut = proseColonIndex(trimmed);
|
|
139149
139277
|
if (cut > 0) {
|
|
139150
139278
|
const title = trimmed.slice(0, cut).trim();
|
|
@@ -139155,9 +139283,9 @@ function splitOverviewProse(text3) {
|
|
|
139155
139283
|
}
|
|
139156
139284
|
function normalizeOverviewItem(item) {
|
|
139157
139285
|
if (typeof item === "string" || typeof item === "number") {
|
|
139158
|
-
const
|
|
139159
|
-
if (!
|
|
139160
|
-
return splitOverviewProse(
|
|
139286
|
+
const text4 = String(item).trim();
|
|
139287
|
+
if (!text4) return null;
|
|
139288
|
+
return splitOverviewProse(text4);
|
|
139161
139289
|
}
|
|
139162
139290
|
const rec = asRecord15(item);
|
|
139163
139291
|
if (!rec) return null;
|
|
@@ -139238,16 +139366,16 @@ function creativeSuggestionFromRow(row) {
|
|
|
139238
139366
|
function distinctCopies(rows, key) {
|
|
139239
139367
|
const counts = /* @__PURE__ */ new Map();
|
|
139240
139368
|
for (const row of rows) {
|
|
139241
|
-
const
|
|
139242
|
-
counts.set(
|
|
139369
|
+
const text4 = String(row[key] ?? "");
|
|
139370
|
+
counts.set(text4, (counts.get(text4) ?? 0) + 1);
|
|
139243
139371
|
}
|
|
139244
139372
|
const seen = /* @__PURE__ */ new Map();
|
|
139245
139373
|
return rows.map((row) => {
|
|
139246
|
-
const
|
|
139247
|
-
if ((counts.get(
|
|
139248
|
-
const n = (seen.get(
|
|
139249
|
-
seen.set(
|
|
139250
|
-
return { ...row, [key]: `${
|
|
139374
|
+
const text4 = String(row[key] ?? "");
|
|
139375
|
+
if ((counts.get(text4) ?? 0) < 3) return row;
|
|
139376
|
+
const n = (seen.get(text4) ?? 0) + 1;
|
|
139377
|
+
seen.set(text4, n);
|
|
139378
|
+
return { ...row, [key]: `${text4}\uFF08\u540C\u7ED3\u6784\u7B2C ${n} \u6761\uFF09` };
|
|
139251
139379
|
});
|
|
139252
139380
|
}
|
|
139253
139381
|
function mapRows(rows, write) {
|
|
@@ -140948,14 +141076,14 @@ var FACEBOOK_SECTION_ALIASES = {
|
|
|
140948
141076
|
import { Command as Command2 } from "commander";
|
|
140949
141077
|
|
|
140950
141078
|
// src/commands/facebook-analysis/render-report.ts
|
|
140951
|
-
import
|
|
140952
|
-
import
|
|
140953
|
-
import
|
|
140954
|
-
import { fileURLToPath as
|
|
141079
|
+
import fs36 from "fs";
|
|
141080
|
+
import fsPromises4 from "fs/promises";
|
|
141081
|
+
import path43 from "path";
|
|
141082
|
+
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
140955
141083
|
|
|
140956
141084
|
// src/commands/facebook-analysis/merge-snapshot.ts
|
|
140957
|
-
import * as
|
|
140958
|
-
import * as
|
|
141085
|
+
import * as fs35 from "fs/promises";
|
|
141086
|
+
import * as path42 from "path";
|
|
140959
141087
|
|
|
140960
141088
|
// src/commands/facebook-analysis/report-metrics.ts
|
|
140961
141089
|
function asRecord25(value) {
|
|
@@ -141107,7 +141235,7 @@ function hasResults(row) {
|
|
|
141107
141235
|
|
|
141108
141236
|
// src/commands/facebook-analysis/merge-snapshot.ts
|
|
141109
141237
|
async function readManifest3(snapshotDir) {
|
|
141110
|
-
const entries = await
|
|
141238
|
+
const entries = await fs35.readdir(snapshotDir);
|
|
141111
141239
|
const manifestNames = entries.filter(
|
|
141112
141240
|
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
141113
141241
|
);
|
|
@@ -141117,7 +141245,7 @@ async function readManifest3(snapshotDir) {
|
|
|
141117
141245
|
];
|
|
141118
141246
|
for (const name2 of ordered) {
|
|
141119
141247
|
try {
|
|
141120
|
-
const raw = await
|
|
141248
|
+
const raw = await fs35.readFile(path42.join(snapshotDir, name2), "utf8");
|
|
141121
141249
|
const parsed = JSON.parse(raw);
|
|
141122
141250
|
if (parsed?.artifacts?.length) return parsed;
|
|
141123
141251
|
} catch {
|
|
@@ -141127,7 +141255,7 @@ async function readManifest3(snapshotDir) {
|
|
|
141127
141255
|
}
|
|
141128
141256
|
async function loadSectionFile3(snapshotDir, file) {
|
|
141129
141257
|
try {
|
|
141130
|
-
const raw = await
|
|
141258
|
+
const raw = await fs35.readFile(path42.join(snapshotDir, file), "utf8");
|
|
141131
141259
|
return asRecord25(JSON.parse(raw));
|
|
141132
141260
|
} catch {
|
|
141133
141261
|
return null;
|
|
@@ -141171,7 +141299,7 @@ function mapAdSetRows(groups) {
|
|
|
141171
141299
|
})).sort((a, b) => (b.spend ?? 0) - (a.spend ?? 0));
|
|
141172
141300
|
}
|
|
141173
141301
|
async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
141174
|
-
const absDir =
|
|
141302
|
+
const absDir = path42.resolve(snapshotDir);
|
|
141175
141303
|
const manifest = await readManifest3(snapshotDir);
|
|
141176
141304
|
if (!manifest) {
|
|
141177
141305
|
throw new Error(
|
|
@@ -141438,7 +141566,7 @@ function buildMetaPeriodExcelSheets(data) {
|
|
|
141438
141566
|
})
|
|
141439
141567
|
],
|
|
141440
141568
|
[],
|
|
141441
|
-
...buildSummaryNarrative(data).map((
|
|
141569
|
+
...buildSummaryNarrative(data).map((text4) => [text4])
|
|
141442
141570
|
];
|
|
141443
141571
|
const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
|
|
141444
141572
|
for (const raw of asArray3(tables.daily)) {
|
|
@@ -141485,8 +141613,8 @@ function buildMetaPeriodExcelSheets(data) {
|
|
|
141485
141613
|
{ name: "\u53D7\u4F17", rows: audienceRows }
|
|
141486
141614
|
];
|
|
141487
141615
|
}
|
|
141488
|
-
function chrome2(
|
|
141489
|
-
return lang === "en" ? applyEnglishPhrases(
|
|
141616
|
+
function chrome2(text4, lang) {
|
|
141617
|
+
return lang === "en" ? applyEnglishPhrases(text4) : text4;
|
|
141490
141618
|
}
|
|
141491
141619
|
function writeMetaPeriodExcel(outPath, data, lang = "zh") {
|
|
141492
141620
|
const sheets = buildMetaPeriodExcelSheets(data).map((sheet) => ({
|
|
@@ -141792,20 +141920,20 @@ var TEMPLATE_BASENAMES2 = {
|
|
|
141792
141920
|
html: "meta-period-report.html"
|
|
141793
141921
|
};
|
|
141794
141922
|
var INJECT_MARKER2 = "window.__META_PERIOD_REPORT__ = window.__META_PERIOD_REPORT__ || null;";
|
|
141795
|
-
function
|
|
141796
|
-
const dir =
|
|
141923
|
+
function resolveSkillTemplatePath5(basename13) {
|
|
141924
|
+
const dir = path43.dirname(fileURLToPath11(import.meta.url));
|
|
141797
141925
|
const candidates = [
|
|
141798
|
-
|
|
141799
|
-
|
|
141800
|
-
|
|
141926
|
+
path43.join(dir, "skill", "report-templates", basename13),
|
|
141927
|
+
path43.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
141928
|
+
path43.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
141801
141929
|
];
|
|
141802
141930
|
for (const p of candidates) {
|
|
141803
|
-
if (
|
|
141931
|
+
if (fs36.existsSync(p)) return p;
|
|
141804
141932
|
}
|
|
141805
141933
|
return candidates[0];
|
|
141806
141934
|
}
|
|
141807
141935
|
function metaPeriodReportTemplatePath() {
|
|
141808
|
-
return
|
|
141936
|
+
return resolveSkillTemplatePath5(TEMPLATE_BASENAMES2.html);
|
|
141809
141937
|
}
|
|
141810
141938
|
function parseRenderFormats(raw) {
|
|
141811
141939
|
const tokens = (raw ?? "html").split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
@@ -141822,10 +141950,10 @@ function parseRenderFormats(raw) {
|
|
|
141822
141950
|
}
|
|
141823
141951
|
return [...new Set(out)];
|
|
141824
141952
|
}
|
|
141825
|
-
async function
|
|
141826
|
-
const
|
|
141953
|
+
async function readJsonFile5(filePath) {
|
|
141954
|
+
const text4 = await fsPromises4.readFile(filePath, "utf8");
|
|
141827
141955
|
try {
|
|
141828
|
-
return JSON.parse(
|
|
141956
|
+
return JSON.parse(text4);
|
|
141829
141957
|
} catch {
|
|
141830
141958
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
141831
141959
|
}
|
|
@@ -141846,7 +141974,7 @@ function injectReportData3(html, payload, lang) {
|
|
|
141846
141974
|
}
|
|
141847
141975
|
function defaultOutPath(dataPath, format, out) {
|
|
141848
141976
|
if (out?.trim()) {
|
|
141849
|
-
const resolved =
|
|
141977
|
+
const resolved = path43.resolve(out);
|
|
141850
141978
|
if (format === "xlsx" && !/\.xlsx$/i.test(resolved)) {
|
|
141851
141979
|
return resolved.replace(/\.(html?)$/i, ".xlsx");
|
|
141852
141980
|
}
|
|
@@ -141855,14 +141983,14 @@ function defaultOutPath(dataPath, format, out) {
|
|
|
141855
141983
|
}
|
|
141856
141984
|
return resolved;
|
|
141857
141985
|
}
|
|
141858
|
-
const dir =
|
|
141859
|
-
return
|
|
141986
|
+
const dir = path43.dirname(dataPath);
|
|
141987
|
+
return path43.join(dir, format === "xlsx" ? "meta-period-report.xlsx" : "meta-period-report.html");
|
|
141860
141988
|
}
|
|
141861
141989
|
async function runFacebookAnalysisRender(opts) {
|
|
141862
|
-
const dataPath =
|
|
141863
|
-
let data = asRecord28(await
|
|
141990
|
+
const dataPath = path43.resolve(opts.dataFile);
|
|
141991
|
+
let data = asRecord28(await readJsonFile5(dataPath));
|
|
141864
141992
|
if (opts.snapshotDir?.trim()) {
|
|
141865
|
-
data = await mergeFacebookSnapshotIntoReport(data,
|
|
141993
|
+
data = await mergeFacebookSnapshotIntoReport(data, path43.resolve(opts.snapshotDir));
|
|
141866
141994
|
}
|
|
141867
141995
|
localizeFacebookReportLabels(data);
|
|
141868
141996
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
@@ -141882,14 +142010,14 @@ async function runFacebookAnalysisRender(opts) {
|
|
|
141882
142010
|
const written = [];
|
|
141883
142011
|
for (const format of formats) {
|
|
141884
142012
|
const outPath = defaultOutPath(dataPath, format, opts.out);
|
|
141885
|
-
await
|
|
142013
|
+
await fsPromises4.mkdir(path43.dirname(outPath), { recursive: true });
|
|
141886
142014
|
if (format === "xlsx") {
|
|
141887
142015
|
writeMetaPeriodExcel(outPath, data, lang);
|
|
141888
142016
|
} else {
|
|
141889
142017
|
const templatePath = metaPeriodReportTemplatePath();
|
|
141890
142018
|
let html;
|
|
141891
142019
|
try {
|
|
141892
|
-
html = await
|
|
142020
|
+
html = await fsPromises4.readFile(templatePath, "utf8");
|
|
141893
142021
|
} catch {
|
|
141894
142022
|
console.error(`
|
|
141895
142023
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -141897,7 +142025,7 @@ async function runFacebookAnalysisRender(opts) {
|
|
|
141897
142025
|
`);
|
|
141898
142026
|
process.exit(1);
|
|
141899
142027
|
}
|
|
141900
|
-
await
|
|
142028
|
+
await fsPromises4.writeFile(outPath, injectReportData3(html, data, lang), "utf8");
|
|
141901
142029
|
}
|
|
141902
142030
|
written.push(outPath);
|
|
141903
142031
|
}
|
|
@@ -141918,14 +142046,14 @@ async function runFacebookAnalysisRender(opts) {
|
|
|
141918
142046
|
}
|
|
141919
142047
|
|
|
141920
142048
|
// src/commands/facebook-analysis/diagnosis-render-report.ts
|
|
141921
|
-
import
|
|
141922
|
-
import
|
|
141923
|
-
import
|
|
141924
|
-
import { fileURLToPath as
|
|
142049
|
+
import fs38 from "fs";
|
|
142050
|
+
import fsPromises5 from "fs/promises";
|
|
142051
|
+
import path45 from "path";
|
|
142052
|
+
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
141925
142053
|
|
|
141926
142054
|
// src/commands/facebook-analysis/diagnosis-merge-snapshot.ts
|
|
141927
|
-
import * as
|
|
141928
|
-
import * as
|
|
142055
|
+
import * as fs37 from "fs/promises";
|
|
142056
|
+
import * as path44 from "path";
|
|
141929
142057
|
function asRecord29(value) {
|
|
141930
142058
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
141931
142059
|
return value;
|
|
@@ -141961,7 +142089,7 @@ async function readManifest4(snapshotDir, accountId) {
|
|
|
141961
142089
|
const candidates = [];
|
|
141962
142090
|
if (accountId) candidates.push(reportManifestFile(accountId));
|
|
141963
142091
|
try {
|
|
141964
|
-
const entries = await
|
|
142092
|
+
const entries = await fs37.readdir(snapshotDir);
|
|
141965
142093
|
const manifestNames = entries.filter(
|
|
141966
142094
|
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
141967
142095
|
);
|
|
@@ -141975,7 +142103,7 @@ async function readManifest4(snapshotDir, accountId) {
|
|
|
141975
142103
|
}
|
|
141976
142104
|
for (const name2 of candidates) {
|
|
141977
142105
|
try {
|
|
141978
|
-
const raw = await
|
|
142106
|
+
const raw = await fs37.readFile(path44.join(snapshotDir, name2), "utf8");
|
|
141979
142107
|
const parsed = JSON.parse(raw);
|
|
141980
142108
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
141981
142109
|
} catch {
|
|
@@ -141985,14 +142113,14 @@ async function readManifest4(snapshotDir, accountId) {
|
|
|
141985
142113
|
}
|
|
141986
142114
|
async function loadSectionFile4(snapshotDir, file) {
|
|
141987
142115
|
try {
|
|
141988
|
-
const raw = await
|
|
142116
|
+
const raw = await fs37.readFile(path44.join(snapshotDir, file), "utf8");
|
|
141989
142117
|
return asRecord29(JSON.parse(raw));
|
|
141990
142118
|
} catch {
|
|
141991
142119
|
return null;
|
|
141992
142120
|
}
|
|
141993
142121
|
}
|
|
141994
142122
|
async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
141995
|
-
const absDir =
|
|
142123
|
+
const absDir = path44.resolve(snapshotDir);
|
|
141996
142124
|
const metaAccountId = typeof asRecord29(payload.meta)?.accountId === "string" ? asRecord29(payload.meta)?.accountId : void 0;
|
|
141997
142125
|
const manifest = await readManifest4(snapshotDir, metaAccountId);
|
|
141998
142126
|
if (!manifest) {
|
|
@@ -142270,27 +142398,27 @@ function formatMetaDiagnosisReportErrors(result) {
|
|
|
142270
142398
|
// src/commands/facebook-analysis/diagnosis-render-report.ts
|
|
142271
142399
|
init_lang();
|
|
142272
142400
|
init_html();
|
|
142273
|
-
var
|
|
142401
|
+
var TEMPLATE_BASENAME3 = "meta-account-diagnosis-report.html";
|
|
142274
142402
|
var INJECT_MARKER3 = "window.__META_DIAGNOSIS_REPORT__ = window.__META_DIAGNOSIS_REPORT__ || null;";
|
|
142275
|
-
function
|
|
142276
|
-
const dir =
|
|
142403
|
+
function resolveSkillTemplatePath6(basename13) {
|
|
142404
|
+
const dir = path45.dirname(fileURLToPath12(import.meta.url));
|
|
142277
142405
|
const candidates = [
|
|
142278
|
-
|
|
142279
|
-
|
|
142280
|
-
|
|
142406
|
+
path45.join(dir, "skill", "report-templates", basename13),
|
|
142407
|
+
path45.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
142408
|
+
path45.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
142281
142409
|
];
|
|
142282
142410
|
for (const p of candidates) {
|
|
142283
|
-
if (
|
|
142411
|
+
if (fs38.existsSync(p)) return p;
|
|
142284
142412
|
}
|
|
142285
142413
|
return candidates[0];
|
|
142286
142414
|
}
|
|
142287
142415
|
function metaDiagnosisReportTemplatePath() {
|
|
142288
|
-
return
|
|
142416
|
+
return resolveSkillTemplatePath6(TEMPLATE_BASENAME3);
|
|
142289
142417
|
}
|
|
142290
|
-
async function
|
|
142291
|
-
const
|
|
142418
|
+
async function readJsonFile6(filePath) {
|
|
142419
|
+
const text4 = await fsPromises5.readFile(filePath, "utf8");
|
|
142292
142420
|
try {
|
|
142293
|
-
return JSON.parse(
|
|
142421
|
+
return JSON.parse(text4);
|
|
142294
142422
|
} catch {
|
|
142295
142423
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
142296
142424
|
}
|
|
@@ -142310,10 +142438,10 @@ function injectReportData4(html, payload, lang) {
|
|
|
142310
142438
|
return localized.replace(INJECT_MARKER3, `window.__META_DIAGNOSIS_REPORT__ = ${json};`);
|
|
142311
142439
|
}
|
|
142312
142440
|
async function runFacebookAnalysisDiagnosisRender(opts) {
|
|
142313
|
-
const dataPath =
|
|
142314
|
-
let data = asRecord31(await
|
|
142441
|
+
const dataPath = path45.resolve(opts.dataFile);
|
|
142442
|
+
let data = asRecord31(await readJsonFile6(dataPath));
|
|
142315
142443
|
if (opts.snapshotDir?.trim()) {
|
|
142316
|
-
data = await mergeMetaDiagnosisSnapshotIntoReport(data,
|
|
142444
|
+
data = await mergeMetaDiagnosisSnapshotIntoReport(data, path45.resolve(opts.snapshotDir));
|
|
142317
142445
|
}
|
|
142318
142446
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
142319
142447
|
const contentCheck = validateMetaDiagnosisReportContent(data);
|
|
@@ -142332,7 +142460,7 @@ async function runFacebookAnalysisDiagnosisRender(opts) {
|
|
|
142332
142460
|
const templatePath = metaDiagnosisReportTemplatePath();
|
|
142333
142461
|
let html;
|
|
142334
142462
|
try {
|
|
142335
|
-
html = await
|
|
142463
|
+
html = await fsPromises5.readFile(templatePath, "utf8");
|
|
142336
142464
|
} catch {
|
|
142337
142465
|
console.error(`
|
|
142338
142466
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -142340,12 +142468,12 @@ async function runFacebookAnalysisDiagnosisRender(opts) {
|
|
|
142340
142468
|
`);
|
|
142341
142469
|
process.exit(1);
|
|
142342
142470
|
}
|
|
142343
|
-
const outPath =
|
|
142344
|
-
opts.out ??
|
|
142471
|
+
const outPath = path45.resolve(
|
|
142472
|
+
opts.out ?? path45.join(path45.dirname(dataPath), "meta-account-diagnosis-report.html")
|
|
142345
142473
|
);
|
|
142346
|
-
const outDir =
|
|
142347
|
-
await
|
|
142348
|
-
await
|
|
142474
|
+
const outDir = path45.dirname(outPath);
|
|
142475
|
+
await fsPromises5.mkdir(outDir, { recursive: true });
|
|
142476
|
+
await fsPromises5.writeFile(outPath, injectReportData4(html, data, lang), "utf8");
|
|
142349
142477
|
const { stats } = contentCheck;
|
|
142350
142478
|
console.log(`
|
|
142351
142479
|
\u2705 Meta\uFF08Facebook\uFF09\u8D26\u6237\u8BCA\u65AD HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
@@ -142361,7 +142489,7 @@ async function runFacebookAnalysisDiagnosisRender(opts) {
|
|
|
142361
142489
|
|
|
142362
142490
|
// src/commands/facebook-analysis/run-batch.ts
|
|
142363
142491
|
init_auth();
|
|
142364
|
-
import * as
|
|
142492
|
+
import * as path46 from "path";
|
|
142365
142493
|
import { performance as performance5 } from "perf_hooks";
|
|
142366
142494
|
init_version();
|
|
142367
142495
|
|
|
@@ -142463,7 +142591,7 @@ async function runAllFacebookSections(opts) {
|
|
|
142463
142591
|
const results = await runWithConcurrency3(tasks, concurrency);
|
|
142464
142592
|
const succeeded = results.filter((r) => r.ok).length;
|
|
142465
142593
|
const failed = results.length - succeeded;
|
|
142466
|
-
const absoluteSnapshotDir =
|
|
142594
|
+
const absoluteSnapshotDir = path46.resolve(opts.jsonOut);
|
|
142467
142595
|
const summary = {
|
|
142468
142596
|
kind: "siluzan-tso-facebook-analysis-snapshot-batch",
|
|
142469
142597
|
absoluteSnapshotDir,
|
|
@@ -142587,9 +142715,9 @@ function parseEffectiveStatusFilter(raw) {
|
|
|
142587
142715
|
}
|
|
142588
142716
|
return canonical.length ? canonical.join(",") : void 0;
|
|
142589
142717
|
}
|
|
142590
|
-
function facebookAdsUrl(facebookApiUrl, digits,
|
|
142718
|
+
function facebookAdsUrl(facebookApiUrl, digits, path57) {
|
|
142591
142719
|
const base2 = facebookApiUrl.replace(/\/$/, "");
|
|
142592
|
-
const p =
|
|
142720
|
+
const p = path57.startsWith("/") ? path57 : `/${path57}`;
|
|
142593
142721
|
return `${base2}/api/fb/ads/${digits}${p}`;
|
|
142594
142722
|
}
|
|
142595
142723
|
function facebookInsightsUrl(facebookApiUrl, digits, level) {
|
|
@@ -142626,7 +142754,7 @@ async function fetchFacebookAccount(config, digits, verbose) {
|
|
|
142626
142754
|
verbose
|
|
142627
142755
|
);
|
|
142628
142756
|
}
|
|
142629
|
-
async function fetchFacebookPagedList(config, digits,
|
|
142757
|
+
async function fetchFacebookPagedList(config, digits, path57, opts) {
|
|
142630
142758
|
const base2 = requireFacebookApi(config);
|
|
142631
142759
|
const items3 = [];
|
|
142632
142760
|
let after;
|
|
@@ -142641,7 +142769,7 @@ async function fetchFacebookPagedList(config, digits, path56, opts) {
|
|
|
142641
142769
|
adsetId: opts.adsetId
|
|
142642
142770
|
});
|
|
142643
142771
|
const raw = await apiFetch2(
|
|
142644
|
-
`${facebookAdsUrl(base2, digits,
|
|
142772
|
+
`${facebookAdsUrl(base2, digits, path57)}?${query}`,
|
|
142645
142773
|
config,
|
|
142646
142774
|
{},
|
|
142647
142775
|
opts.verbose
|
|
@@ -142776,7 +142904,7 @@ async function runFacebookEntityList(opts, kind) {
|
|
|
142776
142904
|
}
|
|
142777
142905
|
const pageSize = resolveFacebookPageSize(opts.pageSize);
|
|
142778
142906
|
const config = loadConfig(opts.token);
|
|
142779
|
-
const
|
|
142907
|
+
const path57 = `/${kind}`;
|
|
142780
142908
|
const labels = {
|
|
142781
142909
|
campaigns: {
|
|
142782
142910
|
section: "facebook-campaign-entities",
|
|
@@ -142789,7 +142917,7 @@ async function runFacebookEntityList(opts, kind) {
|
|
|
142789
142917
|
const meta = labels[kind];
|
|
142790
142918
|
let result;
|
|
142791
142919
|
try {
|
|
142792
|
-
result = await fetchFacebookPagedList(config, manifestId,
|
|
142920
|
+
result = await fetchFacebookPagedList(config, manifestId, path57, {
|
|
142793
142921
|
pageSize,
|
|
142794
142922
|
verbose: !!opts.verbose,
|
|
142795
142923
|
effectiveStatus,
|
|
@@ -143537,7 +143665,7 @@ function endpointHintForBingSection(def) {
|
|
|
143537
143665
|
|
|
143538
143666
|
// src/commands/bing-analysis/run-batch.ts
|
|
143539
143667
|
init_auth();
|
|
143540
|
-
import * as
|
|
143668
|
+
import * as path47 from "path";
|
|
143541
143669
|
import { performance as performance6 } from "perf_hooks";
|
|
143542
143670
|
init_version();
|
|
143543
143671
|
async function runWithConcurrency4(tasks, concurrency) {
|
|
@@ -143612,7 +143740,7 @@ async function runAllBingSections(opts) {
|
|
|
143612
143740
|
const results = await runWithConcurrency4(tasks, concurrency);
|
|
143613
143741
|
const succeeded = results.filter((r) => r.ok).length;
|
|
143614
143742
|
const failed = results.length - succeeded;
|
|
143615
|
-
const absoluteSnapshotDir =
|
|
143743
|
+
const absoluteSnapshotDir = path47.resolve(opts.jsonOut);
|
|
143616
143744
|
const summary = {
|
|
143617
143745
|
kind: "siluzan-tso-bing-analysis-snapshot-batch",
|
|
143618
143746
|
absoluteSnapshotDir,
|
|
@@ -143956,14 +144084,14 @@ Bing \u5B98\u65B9\u6708\u6D88\u8017\uFF08${id}\uFF09
|
|
|
143956
144084
|
import { Command as Command3 } from "commander";
|
|
143957
144085
|
|
|
143958
144086
|
// src/commands/bing-analysis/render-report.ts
|
|
143959
|
-
import
|
|
143960
|
-
import
|
|
143961
|
-
import
|
|
143962
|
-
import { fileURLToPath as
|
|
144087
|
+
import fs40 from "fs";
|
|
144088
|
+
import fsPromises6 from "fs/promises";
|
|
144089
|
+
import path49 from "path";
|
|
144090
|
+
import { fileURLToPath as fileURLToPath13 } from "url";
|
|
143963
144091
|
|
|
143964
144092
|
// src/commands/bing-analysis/merge-snapshot.ts
|
|
143965
|
-
import * as
|
|
143966
|
-
import * as
|
|
144093
|
+
import * as fs39 from "fs/promises";
|
|
144094
|
+
import * as path48 from "path";
|
|
143967
144095
|
function asRecord33(value) {
|
|
143968
144096
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
143969
144097
|
return value;
|
|
@@ -143985,7 +144113,7 @@ function asRows2(value) {
|
|
|
143985
144113
|
}
|
|
143986
144114
|
async function loadSectionPayload(snapshotDir, file) {
|
|
143987
144115
|
try {
|
|
143988
|
-
const raw = await
|
|
144116
|
+
const raw = await fs39.readFile(path48.join(snapshotDir, file), "utf8");
|
|
143989
144117
|
return JSON.parse(raw);
|
|
143990
144118
|
} catch {
|
|
143991
144119
|
return null;
|
|
@@ -143995,7 +144123,7 @@ async function readManifest5(snapshotDir, accountId) {
|
|
|
143995
144123
|
const candidates = [];
|
|
143996
144124
|
if (accountId) candidates.push(reportManifestFile(accountId));
|
|
143997
144125
|
try {
|
|
143998
|
-
const entries = await
|
|
144126
|
+
const entries = await fs39.readdir(snapshotDir);
|
|
143999
144127
|
const manifestNames = entries.filter(
|
|
144000
144128
|
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
144001
144129
|
);
|
|
@@ -144006,7 +144134,7 @@ async function readManifest5(snapshotDir, accountId) {
|
|
|
144006
144134
|
}
|
|
144007
144135
|
for (const name2 of candidates) {
|
|
144008
144136
|
try {
|
|
144009
|
-
const raw = await
|
|
144137
|
+
const raw = await fs39.readFile(path48.join(snapshotDir, name2), "utf8");
|
|
144010
144138
|
const parsed = JSON.parse(raw);
|
|
144011
144139
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
144012
144140
|
} catch {
|
|
@@ -144173,7 +144301,7 @@ function mapSearchTermRows(payload) {
|
|
|
144173
144301
|
);
|
|
144174
144302
|
}
|
|
144175
144303
|
async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
144176
|
-
const absDir =
|
|
144304
|
+
const absDir = path48.resolve(snapshotDir);
|
|
144177
144305
|
const metaAccountId = typeof asRecord33(payload.meta)?.accountId === "string" ? asRecord33(payload.meta)?.accountId : void 0;
|
|
144178
144306
|
const manifest = await readManifest5(snapshotDir, metaAccountId);
|
|
144179
144307
|
if (!manifest) {
|
|
@@ -144408,27 +144536,27 @@ function formatBingPeriodReportErrors(result) {
|
|
|
144408
144536
|
init_report_period();
|
|
144409
144537
|
init_lang();
|
|
144410
144538
|
init_html();
|
|
144411
|
-
var
|
|
144539
|
+
var TEMPLATE_BASENAME4 = "bing-period-report.html";
|
|
144412
144540
|
var INJECT_MARKER4 = "window.__BING_PERIOD_REPORT__ = window.__BING_PERIOD_REPORT__ || null;";
|
|
144413
|
-
function
|
|
144414
|
-
const dir =
|
|
144541
|
+
function resolveSkillTemplatePath7(basename13) {
|
|
144542
|
+
const dir = path49.dirname(fileURLToPath13(import.meta.url));
|
|
144415
144543
|
const candidates = [
|
|
144416
|
-
|
|
144417
|
-
|
|
144418
|
-
|
|
144544
|
+
path49.join(dir, "skill", "report-templates", basename13),
|
|
144545
|
+
path49.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
144546
|
+
path49.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
144419
144547
|
];
|
|
144420
144548
|
for (const p of candidates) {
|
|
144421
|
-
if (
|
|
144549
|
+
if (fs40.existsSync(p)) return p;
|
|
144422
144550
|
}
|
|
144423
144551
|
return candidates[0];
|
|
144424
144552
|
}
|
|
144425
144553
|
function bingPeriodReportTemplatePath() {
|
|
144426
|
-
return
|
|
144554
|
+
return resolveSkillTemplatePath7(TEMPLATE_BASENAME4);
|
|
144427
144555
|
}
|
|
144428
|
-
async function
|
|
144429
|
-
const
|
|
144556
|
+
async function readJsonFile7(filePath) {
|
|
144557
|
+
const text4 = await fsPromises6.readFile(filePath, "utf8");
|
|
144430
144558
|
try {
|
|
144431
|
-
return JSON.parse(
|
|
144559
|
+
return JSON.parse(text4);
|
|
144432
144560
|
} catch {
|
|
144433
144561
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
144434
144562
|
}
|
|
@@ -144448,10 +144576,10 @@ function injectReportData5(html, payload, lang) {
|
|
|
144448
144576
|
return localized.replace(INJECT_MARKER4, `window.__BING_PERIOD_REPORT__ = ${json};`);
|
|
144449
144577
|
}
|
|
144450
144578
|
async function runBingAnalysisRender(opts) {
|
|
144451
|
-
const dataPath =
|
|
144452
|
-
let data = asRecord35(await
|
|
144579
|
+
const dataPath = path49.resolve(opts.dataFile);
|
|
144580
|
+
let data = asRecord35(await readJsonFile7(dataPath));
|
|
144453
144581
|
if (opts.snapshotDir?.trim()) {
|
|
144454
|
-
data = await mergeBingAnalysisSnapshotIntoReport(data,
|
|
144582
|
+
data = await mergeBingAnalysisSnapshotIntoReport(data, path49.resolve(opts.snapshotDir));
|
|
144455
144583
|
}
|
|
144456
144584
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
144457
144585
|
const contentCheck = validateBingPeriodReportContent(data);
|
|
@@ -144470,7 +144598,7 @@ async function runBingAnalysisRender(opts) {
|
|
|
144470
144598
|
const templatePath = bingPeriodReportTemplatePath();
|
|
144471
144599
|
let html;
|
|
144472
144600
|
try {
|
|
144473
|
-
html = await
|
|
144601
|
+
html = await fsPromises6.readFile(templatePath, "utf8");
|
|
144474
144602
|
} catch {
|
|
144475
144603
|
console.error(`
|
|
144476
144604
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -144478,12 +144606,12 @@ async function runBingAnalysisRender(opts) {
|
|
|
144478
144606
|
`);
|
|
144479
144607
|
process.exit(1);
|
|
144480
144608
|
}
|
|
144481
|
-
const outPath =
|
|
144482
|
-
opts.out ??
|
|
144609
|
+
const outPath = path49.resolve(
|
|
144610
|
+
opts.out ?? path49.join(path49.dirname(dataPath), "bing-period-report.html")
|
|
144483
144611
|
);
|
|
144484
|
-
const outDir =
|
|
144485
|
-
await
|
|
144486
|
-
await
|
|
144612
|
+
const outDir = path49.dirname(outPath);
|
|
144613
|
+
await fsPromises6.mkdir(outDir, { recursive: true });
|
|
144614
|
+
await fsPromises6.writeFile(outPath, injectReportData5(html, data, lang), "utf8");
|
|
144487
144615
|
const { stats } = contentCheck;
|
|
144488
144616
|
const cover = periodWord(attachPeriodChrome(data).periodChrome.unit, "\u8D26\u6237");
|
|
144489
144617
|
console.log(`
|
|
@@ -144819,7 +144947,7 @@ async function fetchTikTokInterestList(config, account, verbose) {
|
|
|
144819
144947
|
|
|
144820
144948
|
// src/commands/tiktok-analysis/run-batch.ts
|
|
144821
144949
|
init_auth();
|
|
144822
|
-
import * as
|
|
144950
|
+
import * as path50 from "path";
|
|
144823
144951
|
import { performance as performance7 } from "perf_hooks";
|
|
144824
144952
|
init_version();
|
|
144825
144953
|
async function runWithConcurrency5(tasks, concurrency) {
|
|
@@ -144894,7 +145022,7 @@ async function runAllTikTokSections(opts) {
|
|
|
144894
145022
|
const results = await runWithConcurrency5(tasks, concurrency);
|
|
144895
145023
|
const succeeded = results.filter((r) => r.ok).length;
|
|
144896
145024
|
const failed = results.length - succeeded;
|
|
144897
|
-
const absoluteSnapshotDir =
|
|
145025
|
+
const absoluteSnapshotDir = path50.resolve(opts.jsonOut);
|
|
144898
145026
|
const summary = {
|
|
144899
145027
|
kind: "siluzan-tso-tiktok-analysis-snapshot-batch",
|
|
144900
145028
|
absoluteSnapshotDir,
|
|
@@ -144917,14 +145045,14 @@ init_auth();
|
|
|
144917
145045
|
import { Command as Command4 } from "commander";
|
|
144918
145046
|
|
|
144919
145047
|
// src/commands/tiktok-analysis/render-report.ts
|
|
144920
|
-
import
|
|
144921
|
-
import
|
|
144922
|
-
import
|
|
144923
|
-
import { fileURLToPath as
|
|
145048
|
+
import fs42 from "fs";
|
|
145049
|
+
import fsPromises7 from "fs/promises";
|
|
145050
|
+
import path52 from "path";
|
|
145051
|
+
import { fileURLToPath as fileURLToPath14 } from "url";
|
|
144924
145052
|
|
|
144925
145053
|
// src/commands/tiktok-analysis/merge-snapshot.ts
|
|
144926
|
-
import * as
|
|
144927
|
-
import * as
|
|
145054
|
+
import * as fs41 from "fs/promises";
|
|
145055
|
+
import * as path51 from "path";
|
|
144928
145056
|
function asRecord36(value) {
|
|
144929
145057
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
144930
145058
|
return value;
|
|
@@ -144940,7 +145068,7 @@ function round28(value) {
|
|
|
144940
145068
|
}
|
|
144941
145069
|
async function loadSectionPayload2(snapshotDir, file) {
|
|
144942
145070
|
try {
|
|
144943
|
-
const raw = await
|
|
145071
|
+
const raw = await fs41.readFile(path51.join(snapshotDir, file), "utf8");
|
|
144944
145072
|
return JSON.parse(raw);
|
|
144945
145073
|
} catch {
|
|
144946
145074
|
return null;
|
|
@@ -144950,7 +145078,7 @@ async function readManifest6(snapshotDir, accountId) {
|
|
|
144950
145078
|
const candidates = [];
|
|
144951
145079
|
if (accountId) candidates.push(reportManifestFile(accountId));
|
|
144952
145080
|
try {
|
|
144953
|
-
const entries = await
|
|
145081
|
+
const entries = await fs41.readdir(snapshotDir);
|
|
144954
145082
|
const manifestNames = entries.filter(
|
|
144955
145083
|
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
144956
145084
|
);
|
|
@@ -144961,7 +145089,7 @@ async function readManifest6(snapshotDir, accountId) {
|
|
|
144961
145089
|
}
|
|
144962
145090
|
for (const name2 of candidates) {
|
|
144963
145091
|
try {
|
|
144964
|
-
const raw = await
|
|
145092
|
+
const raw = await fs41.readFile(path51.join(snapshotDir, name2), "utf8");
|
|
144965
145093
|
const parsed = JSON.parse(raw);
|
|
144966
145094
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
144967
145095
|
} catch {
|
|
@@ -145102,7 +145230,7 @@ function mapAudienceMerged(payload) {
|
|
|
145102
145230
|
};
|
|
145103
145231
|
}
|
|
145104
145232
|
async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
145105
|
-
const absDir =
|
|
145233
|
+
const absDir = path51.resolve(snapshotDir);
|
|
145106
145234
|
const metaAccountId = typeof asRecord36(payload.meta)?.accountId === "string" ? asRecord36(payload.meta)?.accountId : void 0;
|
|
145107
145235
|
const manifest = await readManifest6(snapshotDir, metaAccountId);
|
|
145108
145236
|
if (!manifest) {
|
|
@@ -145312,27 +145440,27 @@ function formatTikTokPeriodReportErrors(result) {
|
|
|
145312
145440
|
init_report_period();
|
|
145313
145441
|
init_lang();
|
|
145314
145442
|
init_html();
|
|
145315
|
-
var
|
|
145443
|
+
var TEMPLATE_BASENAME5 = "tiktok-period-report.html";
|
|
145316
145444
|
var INJECT_MARKER5 = "window.__TIKTOK_PERIOD_REPORT__ = window.__TIKTOK_PERIOD_REPORT__ || null;";
|
|
145317
|
-
function
|
|
145318
|
-
const dir =
|
|
145445
|
+
function resolveSkillTemplatePath8(basename13) {
|
|
145446
|
+
const dir = path52.dirname(fileURLToPath14(import.meta.url));
|
|
145319
145447
|
const candidates = [
|
|
145320
|
-
|
|
145321
|
-
|
|
145322
|
-
|
|
145448
|
+
path52.join(dir, "skill", "report-templates", basename13),
|
|
145449
|
+
path52.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
145450
|
+
path52.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
145323
145451
|
];
|
|
145324
145452
|
for (const p of candidates) {
|
|
145325
|
-
if (
|
|
145453
|
+
if (fs42.existsSync(p)) return p;
|
|
145326
145454
|
}
|
|
145327
145455
|
return candidates[0];
|
|
145328
145456
|
}
|
|
145329
145457
|
function tiktokPeriodReportTemplatePath() {
|
|
145330
|
-
return
|
|
145458
|
+
return resolveSkillTemplatePath8(TEMPLATE_BASENAME5);
|
|
145331
145459
|
}
|
|
145332
|
-
async function
|
|
145333
|
-
const
|
|
145460
|
+
async function readJsonFile8(filePath) {
|
|
145461
|
+
const text4 = await fsPromises7.readFile(filePath, "utf8");
|
|
145334
145462
|
try {
|
|
145335
|
-
return JSON.parse(
|
|
145463
|
+
return JSON.parse(text4);
|
|
145336
145464
|
} catch {
|
|
145337
145465
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
145338
145466
|
}
|
|
@@ -145352,10 +145480,10 @@ function injectReportData6(html, payload, lang) {
|
|
|
145352
145480
|
return localized.replace(INJECT_MARKER5, `window.__TIKTOK_PERIOD_REPORT__ = ${json};`);
|
|
145353
145481
|
}
|
|
145354
145482
|
async function runTikTokAnalysisRender(opts) {
|
|
145355
|
-
const dataPath =
|
|
145356
|
-
let data = asRecord38(await
|
|
145483
|
+
const dataPath = path52.resolve(opts.dataFile);
|
|
145484
|
+
let data = asRecord38(await readJsonFile8(dataPath));
|
|
145357
145485
|
if (opts.snapshotDir?.trim()) {
|
|
145358
|
-
data = await mergeTikTokAnalysisSnapshotIntoReport(data,
|
|
145486
|
+
data = await mergeTikTokAnalysisSnapshotIntoReport(data, path52.resolve(opts.snapshotDir));
|
|
145359
145487
|
}
|
|
145360
145488
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
145361
145489
|
const contentCheck = validateTikTokPeriodReportContent(data);
|
|
@@ -145374,7 +145502,7 @@ async function runTikTokAnalysisRender(opts) {
|
|
|
145374
145502
|
const templatePath = tiktokPeriodReportTemplatePath();
|
|
145375
145503
|
let html;
|
|
145376
145504
|
try {
|
|
145377
|
-
html = await
|
|
145505
|
+
html = await fsPromises7.readFile(templatePath, "utf8");
|
|
145378
145506
|
} catch {
|
|
145379
145507
|
console.error(`
|
|
145380
145508
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -145382,12 +145510,12 @@ async function runTikTokAnalysisRender(opts) {
|
|
|
145382
145510
|
`);
|
|
145383
145511
|
process.exit(1);
|
|
145384
145512
|
}
|
|
145385
|
-
const outPath =
|
|
145386
|
-
opts.out ??
|
|
145513
|
+
const outPath = path52.resolve(
|
|
145514
|
+
opts.out ?? path52.join(path52.dirname(dataPath), "tiktok-period-report.html")
|
|
145387
145515
|
);
|
|
145388
|
-
const outDir =
|
|
145389
|
-
await
|
|
145390
|
-
await
|
|
145516
|
+
const outDir = path52.dirname(outPath);
|
|
145517
|
+
await fsPromises7.mkdir(outDir, { recursive: true });
|
|
145518
|
+
await fsPromises7.writeFile(outPath, injectReportData6(html, data, lang), "utf8");
|
|
145391
145519
|
const { stats } = contentCheck;
|
|
145392
145520
|
const cover = periodWord(attachPeriodChrome(data).periodChrome.unit, "\u8D26\u6237");
|
|
145393
145521
|
console.log(`
|
|
@@ -146313,7 +146441,7 @@ var YANDEX_SECTION_ALIASES = {
|
|
|
146313
146441
|
|
|
146314
146442
|
// src/commands/yandex-analysis/run-batch.ts
|
|
146315
146443
|
init_auth();
|
|
146316
|
-
import * as
|
|
146444
|
+
import * as path54 from "path";
|
|
146317
146445
|
import { performance as performance8 } from "perf_hooks";
|
|
146318
146446
|
init_version();
|
|
146319
146447
|
|
|
@@ -146453,8 +146581,8 @@ function endpointHintForYandexSection(def) {
|
|
|
146453
146581
|
}
|
|
146454
146582
|
|
|
146455
146583
|
// src/commands/yandex-analysis/merge-snapshot.ts
|
|
146456
|
-
import * as
|
|
146457
|
-
import * as
|
|
146584
|
+
import * as fs43 from "fs/promises";
|
|
146585
|
+
import * as path53 from "path";
|
|
146458
146586
|
function asRecord39(value) {
|
|
146459
146587
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
146460
146588
|
return value;
|
|
@@ -146504,7 +146632,7 @@ function pickMetrics2(row, extras = []) {
|
|
|
146504
146632
|
}
|
|
146505
146633
|
async function loadSectionPayload3(snapshotDir, file) {
|
|
146506
146634
|
try {
|
|
146507
|
-
const raw = await
|
|
146635
|
+
const raw = await fs43.readFile(path53.join(snapshotDir, file), "utf8");
|
|
146508
146636
|
return JSON.parse(raw);
|
|
146509
146637
|
} catch {
|
|
146510
146638
|
return null;
|
|
@@ -146514,7 +146642,7 @@ async function readManifest7(snapshotDir, accountId) {
|
|
|
146514
146642
|
const candidates = [];
|
|
146515
146643
|
if (accountId) candidates.push(reportManifestFile(accountId));
|
|
146516
146644
|
try {
|
|
146517
|
-
const entries = await
|
|
146645
|
+
const entries = await fs43.readdir(snapshotDir);
|
|
146518
146646
|
for (const name2 of entries.filter(
|
|
146519
146647
|
(n) => n.startsWith("report-manifest") && n.endsWith(".json")
|
|
146520
146648
|
)) {
|
|
@@ -146524,7 +146652,7 @@ async function readManifest7(snapshotDir, accountId) {
|
|
|
146524
146652
|
}
|
|
146525
146653
|
for (const name2 of candidates) {
|
|
146526
146654
|
try {
|
|
146527
|
-
const raw = await
|
|
146655
|
+
const raw = await fs43.readFile(path53.join(snapshotDir, name2), "utf8");
|
|
146528
146656
|
const parsed = JSON.parse(raw);
|
|
146529
146657
|
if (Array.isArray(parsed.artifacts) && parsed.artifacts.length > 0) return parsed;
|
|
146530
146658
|
} catch {
|
|
@@ -146683,7 +146811,7 @@ function mapDeviceRows2(payload) {
|
|
|
146683
146811
|
return asItems(payload).map((r) => pickMetrics2(r, ["device", "network"]));
|
|
146684
146812
|
}
|
|
146685
146813
|
async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
146686
|
-
const absDir =
|
|
146814
|
+
const absDir = path53.resolve(snapshotDir);
|
|
146687
146815
|
const metaAccountId = typeof asRecord39(payload.meta)?.accountId === "string" ? asRecord39(payload.meta)?.accountId : void 0;
|
|
146688
146816
|
const manifest = await readManifest7(snapshotDir, metaAccountId);
|
|
146689
146817
|
if (!manifest) {
|
|
@@ -146869,7 +146997,7 @@ async function runAllYandexSections(opts) {
|
|
|
146869
146997
|
const results = await runWithConcurrency6(tasks, concurrency);
|
|
146870
146998
|
const succeeded = results.filter((r) => r.ok).length;
|
|
146871
146999
|
const failed = results.length - succeeded;
|
|
146872
|
-
const absoluteSnapshotDir =
|
|
147000
|
+
const absoluteSnapshotDir = path54.resolve(opts.jsonOut);
|
|
146873
147001
|
const summary = {
|
|
146874
147002
|
kind: "siluzan-tso-yandex-analysis-snapshot-batch",
|
|
146875
147003
|
absoluteSnapshotDir,
|
|
@@ -146887,10 +147015,10 @@ async function runAllYandexSections(opts) {
|
|
|
146887
147015
|
}
|
|
146888
147016
|
|
|
146889
147017
|
// src/commands/yandex-analysis/render-report.ts
|
|
146890
|
-
import
|
|
146891
|
-
import
|
|
146892
|
-
import
|
|
146893
|
-
import { fileURLToPath as
|
|
147018
|
+
import fs44 from "fs";
|
|
147019
|
+
import fsPromises8 from "fs/promises";
|
|
147020
|
+
import path55 from "path";
|
|
147021
|
+
import { fileURLToPath as fileURLToPath15 } from "url";
|
|
146894
147022
|
|
|
146895
147023
|
// src/commands/yandex-analysis/report-content.ts
|
|
146896
147024
|
var SECTION_KEYS4 = [
|
|
@@ -147093,27 +147221,27 @@ function formatYandexPeriodReportErrors(result) {
|
|
|
147093
147221
|
init_report_period();
|
|
147094
147222
|
init_lang();
|
|
147095
147223
|
init_html();
|
|
147096
|
-
var
|
|
147224
|
+
var TEMPLATE_BASENAME6 = "yandex-period-report.html";
|
|
147097
147225
|
var INJECT_MARKER6 = "window.__YANDEX_PERIOD_REPORT__ = window.__YANDEX_PERIOD_REPORT__ || null;";
|
|
147098
|
-
function
|
|
147099
|
-
const dir =
|
|
147226
|
+
function resolveSkillTemplatePath9(basename13) {
|
|
147227
|
+
const dir = path55.dirname(fileURLToPath15(import.meta.url));
|
|
147100
147228
|
const candidates = [
|
|
147101
|
-
|
|
147102
|
-
|
|
147103
|
-
|
|
147229
|
+
path55.join(dir, "skill", "report-templates", basename13),
|
|
147230
|
+
path55.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
|
|
147231
|
+
path55.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
|
|
147104
147232
|
];
|
|
147105
147233
|
for (const p of candidates) {
|
|
147106
|
-
if (
|
|
147234
|
+
if (fs44.existsSync(p)) return p;
|
|
147107
147235
|
}
|
|
147108
147236
|
return candidates[0];
|
|
147109
147237
|
}
|
|
147110
147238
|
function yandexPeriodReportTemplatePath() {
|
|
147111
|
-
return
|
|
147239
|
+
return resolveSkillTemplatePath9(TEMPLATE_BASENAME6);
|
|
147112
147240
|
}
|
|
147113
|
-
async function
|
|
147114
|
-
const
|
|
147241
|
+
async function readJsonFile9(filePath) {
|
|
147242
|
+
const text4 = await fsPromises8.readFile(filePath, "utf8");
|
|
147115
147243
|
try {
|
|
147116
|
-
return JSON.parse(
|
|
147244
|
+
return JSON.parse(text4);
|
|
147117
147245
|
} catch {
|
|
147118
147246
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
147119
147247
|
}
|
|
@@ -147146,10 +147274,10 @@ function injectReportData7(html, payload, lang) {
|
|
|
147146
147274
|
return localized.replace(INJECT_MARKER6, `window.__YANDEX_PERIOD_REPORT__ = ${json};`);
|
|
147147
147275
|
}
|
|
147148
147276
|
async function runYandexAnalysisRender(opts) {
|
|
147149
|
-
const dataPath =
|
|
147150
|
-
let data = asRecord41(await
|
|
147277
|
+
const dataPath = path55.resolve(opts.dataFile);
|
|
147278
|
+
let data = asRecord41(await readJsonFile9(dataPath));
|
|
147151
147279
|
if (opts.snapshotDir?.trim()) {
|
|
147152
|
-
data = await mergeYandexAnalysisSnapshotIntoReport(data,
|
|
147280
|
+
data = await mergeYandexAnalysisSnapshotIntoReport(data, path55.resolve(opts.snapshotDir));
|
|
147153
147281
|
}
|
|
147154
147282
|
data = refreshWeeklyFromDaily(data);
|
|
147155
147283
|
const lang = readReportLangOrExit({ flag: opts.lang, meta: data.meta });
|
|
@@ -147167,7 +147295,7 @@ async function runYandexAnalysisRender(opts) {
|
|
|
147167
147295
|
const templatePath = yandexPeriodReportTemplatePath();
|
|
147168
147296
|
let html;
|
|
147169
147297
|
try {
|
|
147170
|
-
html = await
|
|
147298
|
+
html = await fsPromises8.readFile(templatePath, "utf8");
|
|
147171
147299
|
} catch {
|
|
147172
147300
|
console.error(`
|
|
147173
147301
|
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
@@ -147175,12 +147303,12 @@ async function runYandexAnalysisRender(opts) {
|
|
|
147175
147303
|
`);
|
|
147176
147304
|
process.exit(1);
|
|
147177
147305
|
}
|
|
147178
|
-
const outPath =
|
|
147179
|
-
opts.out ??
|
|
147306
|
+
const outPath = path55.resolve(
|
|
147307
|
+
opts.out ?? path55.join(path55.dirname(dataPath), "yandex-period-report.html")
|
|
147180
147308
|
);
|
|
147181
|
-
const outDir =
|
|
147182
|
-
await
|
|
147183
|
-
await
|
|
147309
|
+
const outDir = path55.dirname(outPath);
|
|
147310
|
+
await fsPromises8.mkdir(outDir, { recursive: true });
|
|
147311
|
+
await fsPromises8.writeFile(outPath, injectReportData7(html, data, lang), "utf8");
|
|
147184
147312
|
const { stats } = contentCheck;
|
|
147185
147313
|
const cover = periodWord(attachPeriodChrome(data).periodChrome.unit, "\u8D26\u6237");
|
|
147186
147314
|
console.log(`
|
|
@@ -147279,13 +147407,13 @@ function optionalId(raw) {
|
|
|
147279
147407
|
function insightsLevelToPath(level) {
|
|
147280
147408
|
return level;
|
|
147281
147409
|
}
|
|
147282
|
-
function assertYandexAnalysisQuery(
|
|
147283
|
-
const caps = YANDEX_PATH_CAPS[
|
|
147410
|
+
function assertYandexAnalysisQuery(path57, query) {
|
|
147411
|
+
const caps = YANDEX_PATH_CAPS[path57];
|
|
147284
147412
|
if (query.timeIncrement != null && !caps.timeIncrement) {
|
|
147285
|
-
throw new Error(`--time-increment \u4E0D\u80FD\u7528\u4E8E /${
|
|
147413
|
+
throw new Error(`--time-increment \u4E0D\u80FD\u7528\u4E8E /${path57}\uFF08\u4EC5 campaigns / adgroups / ads\uFF09\u3002`);
|
|
147286
147414
|
}
|
|
147287
147415
|
if (query.network != null && !caps.network) {
|
|
147288
|
-
throw new Error(`--network \u4E0D\u80FD\u7528\u4E8E /${
|
|
147416
|
+
throw new Error(`--network \u4E0D\u80FD\u7528\u4E8E /${path57}\uFF08\u4EC5 campaigns / geo / devices\uFF09\u3002`);
|
|
147289
147417
|
}
|
|
147290
147418
|
if (query.status != null && !caps.status) {
|
|
147291
147419
|
throw new Error(`--status \u4EC5\u7528\u4E8E /ads\uFF08\u62D2\u5BA1/\u5BA1\u6838\u6001\u8D70\u7ED3\u6784\u67E5\u8BE2\uFF0C\u884C\u5185 spend \u4E3A 0\uFF09\u3002`);
|
|
@@ -147302,12 +147430,12 @@ function assertYandexAnalysisQuery(path56, query) {
|
|
|
147302
147430
|
);
|
|
147303
147431
|
}
|
|
147304
147432
|
if (query.limit != null && !caps.limit) {
|
|
147305
|
-
throw new Error(`--limit \u4E0D\u80FD\u7528\u4E8E /${
|
|
147433
|
+
throw new Error(`--limit \u4E0D\u80FD\u7528\u4E8E /${path57}\uFF08overview / daily / devices \u65E0\u6B64\u53C2\u6570\uFF09\u3002`);
|
|
147306
147434
|
}
|
|
147307
147435
|
}
|
|
147308
|
-
function buildYandexAnalysisSearchParams(
|
|
147309
|
-
assertYandexAnalysisQuery(
|
|
147310
|
-
const caps = YANDEX_PATH_CAPS[
|
|
147436
|
+
function buildYandexAnalysisSearchParams(path57, query) {
|
|
147437
|
+
assertYandexAnalysisQuery(path57, query);
|
|
147438
|
+
const caps = YANDEX_PATH_CAPS[path57];
|
|
147311
147439
|
const params = new URLSearchParams({
|
|
147312
147440
|
account: query.account,
|
|
147313
147441
|
start: query.start,
|
|
@@ -147333,10 +147461,10 @@ function buildYandexAnalysisSearchParams(path56, query) {
|
|
|
147333
147461
|
}
|
|
147334
147462
|
return params;
|
|
147335
147463
|
}
|
|
147336
|
-
async function fetchYandexAnalysisPath(config,
|
|
147464
|
+
async function fetchYandexAnalysisPath(config, path57, query, verbose) {
|
|
147337
147465
|
const yandexApiUrl = requireYandexApi(config);
|
|
147338
|
-
const params = buildYandexAnalysisSearchParams(
|
|
147339
|
-
const url = analysisUrl(yandexApiUrl,
|
|
147466
|
+
const params = buildYandexAnalysisSearchParams(path57, query);
|
|
147467
|
+
const url = analysisUrl(yandexApiUrl, path57, params.toString());
|
|
147340
147468
|
return apiFetch2(url, config, {}, verbose);
|
|
147341
147469
|
}
|
|
147342
147470
|
function unwrapYandexItems(raw) {
|
|
@@ -147400,13 +147528,13 @@ ${args.title}
|
|
|
147400
147528
|
console.log(` ${args.footnote}
|
|
147401
147529
|
`);
|
|
147402
147530
|
}
|
|
147403
|
-
async function fetchPath(opts,
|
|
147531
|
+
async function fetchPath(opts, path57, extra) {
|
|
147404
147532
|
const accountId = assertYandexAccountId(opts.account);
|
|
147405
147533
|
const { startDate, endDate } = resolveRange(opts.start, opts.end);
|
|
147406
147534
|
const config = loadConfig(opts.token);
|
|
147407
147535
|
const raw = await fetchYandexAnalysisPath(
|
|
147408
147536
|
config,
|
|
147409
|
-
|
|
147537
|
+
path57,
|
|
147410
147538
|
{
|
|
147411
147539
|
account: accountId,
|
|
147412
147540
|
start: startDate,
|
|
@@ -147775,12 +147903,12 @@ function hasDateFromTo(args) {
|
|
|
147775
147903
|
}
|
|
147776
147904
|
var RERUN_HINT = "\u7ACB\u523B\u6539\u8DD1\u63D0\u793A\u4E2D\u7684\u90A3\u6761\uFF0C\u4E0D\u8981\u505C\u5728\u9519\u8BEF\u547D\u4EE4\u3002";
|
|
147777
147905
|
function fatal(body) {
|
|
147778
|
-
const
|
|
147779
|
-
if (
|
|
147780
|
-
${
|
|
147906
|
+
const text4 = body.replace(/\s+$/g, "");
|
|
147907
|
+
if (text4.includes(RERUN_HINT)) return `
|
|
147908
|
+
${text4}
|
|
147781
147909
|
`;
|
|
147782
147910
|
return `
|
|
147783
|
-
${
|
|
147911
|
+
${text4}
|
|
147784
147912
|
${RERUN_HINT}
|
|
147785
147913
|
`;
|
|
147786
147914
|
}
|
|
@@ -147930,9 +148058,9 @@ function interceptAgentCompatArgv(argv) {
|
|
|
147930
148058
|
installProcessHandlers();
|
|
147931
148059
|
function getVersion() {
|
|
147932
148060
|
try {
|
|
147933
|
-
const __dirname3 =
|
|
147934
|
-
const pkgPath =
|
|
147935
|
-
const pkg = JSON.parse(
|
|
148061
|
+
const __dirname3 = path56.dirname(fileURLToPath16(import.meta.url));
|
|
148062
|
+
const pkgPath = path56.join(__dirname3, "..", "package.json");
|
|
148063
|
+
const pkg = JSON.parse(fs45.readFileSync(pkgPath, "utf8"));
|
|
147936
148064
|
return pkg.version ?? "0.0.0";
|
|
147937
148065
|
} catch {
|
|
147938
148066
|
return "0.0.0";
|