siluzan-tso-cli 1.1.58-beta.2 → 1.1.58-beta.4
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 +665 -356
- package/dist/skill/SKILL.md +1 -0
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/accounts/accounts-balance-stats.md +26 -3
- package/dist/skill/references/analytics/account-analytics.md +3 -2
- package/dist/skill/references/core/agent-conventions.md +2 -1
- package/dist/skill/references/core/cli-enums.md +1 -1
- package/dist/skill/references/core/playbooks.md +5 -3
- package/dist/skill/references/core/workflows.md +1 -1
- package/dist/skill/references/operations/guard.md +1 -0
- package/dist/skill/references/report-templates/okki-weekly-google-client.md +8 -8
- package/dist/skill/report-templates/okki-weekly-google-client.md +8 -8
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/dist/skill/snippets/handoff-p6-okki.md +2 -2
- 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(text3) {
|
|
2176
|
+
return JSON.parse(text3, jsonParseReviverStringifyIds);
|
|
2177
2177
|
}
|
|
2178
2178
|
function hasSiluzanAgentCredentials() {
|
|
2179
2179
|
const apiKey = process.env.SILUZAN_API_KEY?.trim();
|
|
@@ -2486,8 +2486,8 @@ function redactSensitive(input) {
|
|
|
2486
2486
|
);
|
|
2487
2487
|
return output;
|
|
2488
2488
|
}
|
|
2489
|
-
function trimDetail(
|
|
2490
|
-
const t =
|
|
2489
|
+
function trimDetail(text3, maxLen) {
|
|
2490
|
+
const t = text3.trim();
|
|
2491
2491
|
if (t.length <= maxLen) return t;
|
|
2492
2492
|
return `${t.slice(0, maxLen)}\u2026`;
|
|
2493
2493
|
}
|
|
@@ -2533,25 +2533,25 @@ function messageFromJsonValue(value) {
|
|
|
2533
2533
|
return void 0;
|
|
2534
2534
|
}
|
|
2535
2535
|
function extractHttpErrorDetail(rawBody) {
|
|
2536
|
-
const
|
|
2537
|
-
if (!
|
|
2538
|
-
if (
|
|
2536
|
+
const text3 = rawBody?.trim();
|
|
2537
|
+
if (!text3) return void 0;
|
|
2538
|
+
if (text3.startsWith('"')) {
|
|
2539
2539
|
try {
|
|
2540
|
-
const parsed = JSON.parse(
|
|
2540
|
+
const parsed = JSON.parse(text3);
|
|
2541
2541
|
if (typeof parsed === "string" && parsed.trim()) return parsed.trim();
|
|
2542
2542
|
} catch {
|
|
2543
2543
|
}
|
|
2544
2544
|
}
|
|
2545
|
-
if (
|
|
2545
|
+
if (text3.startsWith("{") || text3.startsWith("[")) {
|
|
2546
2546
|
try {
|
|
2547
|
-
const parsed = JSON.parse(
|
|
2547
|
+
const parsed = JSON.parse(text3);
|
|
2548
2548
|
const msg = messageFromJsonValue(parsed);
|
|
2549
2549
|
if (msg) return msg;
|
|
2550
2550
|
} catch {
|
|
2551
2551
|
}
|
|
2552
2552
|
}
|
|
2553
|
-
if (
|
|
2554
|
-
return
|
|
2553
|
+
if (text3.startsWith("<")) return void 0;
|
|
2554
|
+
return text3;
|
|
2555
2555
|
}
|
|
2556
2556
|
function formatHttpError(status, rawBody, opts) {
|
|
2557
2557
|
const verbose = opts?.verbose === true;
|
|
@@ -2568,18 +2568,18 @@ function formatHttpError(status, rawBody, opts) {
|
|
|
2568
2568
|
function buildAuthHeaders(config) {
|
|
2569
2569
|
return buildSiluzanAuthHeaders(config);
|
|
2570
2570
|
}
|
|
2571
|
-
async function parseApiResponse(status,
|
|
2571
|
+
async function parseApiResponse(status, text3, verbose) {
|
|
2572
2572
|
if (status < 200 || status >= 300) {
|
|
2573
|
-
throw new Error(formatHttpError(status,
|
|
2573
|
+
throw new Error(formatHttpError(status, text3, { verbose }));
|
|
2574
2574
|
}
|
|
2575
|
-
if (!
|
|
2575
|
+
if (!text3.trim()) return null;
|
|
2576
2576
|
try {
|
|
2577
|
-
return parseJsonWithStringIds(
|
|
2577
|
+
return parseJsonWithStringIds(text3);
|
|
2578
2578
|
} catch {
|
|
2579
2579
|
if (verbose) {
|
|
2580
|
-
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(
|
|
2580
|
+
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text3).slice(0, 200)}`);
|
|
2581
2581
|
}
|
|
2582
|
-
return
|
|
2582
|
+
return text3;
|
|
2583
2583
|
}
|
|
2584
2584
|
}
|
|
2585
2585
|
function isTransientNetworkError(err) {
|
|
@@ -2635,18 +2635,18 @@ async function apiFetchWithHeaders(url, config, options = {}, verbose = false) {
|
|
|
2635
2635
|
};
|
|
2636
2636
|
const body = typeof options.body === "string" ? options.body : void 0;
|
|
2637
2637
|
const res = await requestWithReadRetry(url, { method, headers: reqHeaders, body });
|
|
2638
|
-
const
|
|
2638
|
+
const text3 = res.text;
|
|
2639
2639
|
if (res.status < 200 || res.status >= 300) {
|
|
2640
|
-
throw new Error(formatHttpError(res.status,
|
|
2640
|
+
throw new Error(formatHttpError(res.status, text3, { verbose }));
|
|
2641
2641
|
}
|
|
2642
2642
|
let data;
|
|
2643
|
-
if (!
|
|
2643
|
+
if (!text3.trim()) {
|
|
2644
2644
|
data = null;
|
|
2645
2645
|
} else {
|
|
2646
2646
|
try {
|
|
2647
|
-
data = parseJsonWithStringIds(
|
|
2647
|
+
data = parseJsonWithStringIds(text3);
|
|
2648
2648
|
} catch {
|
|
2649
|
-
data =
|
|
2649
|
+
data = text3;
|
|
2650
2650
|
}
|
|
2651
2651
|
}
|
|
2652
2652
|
return { data, headers: res.headers };
|
|
@@ -3248,9 +3248,9 @@ function pickCompanyId(data) {
|
|
|
3248
3248
|
}
|
|
3249
3249
|
return void 0;
|
|
3250
3250
|
}
|
|
3251
|
-
function parseMeResponse(
|
|
3251
|
+
function parseMeResponse(text3) {
|
|
3252
3252
|
try {
|
|
3253
|
-
const json = JSON.parse(
|
|
3253
|
+
const json = JSON.parse(text3);
|
|
3254
3254
|
const data = json?.data && typeof json.data === "object" ? json.data : json;
|
|
3255
3255
|
const id = pickStr(data, "entityId") ?? pickStr(data, "id") ?? pickStr(data, "userId") ?? pickStr(data, "accountId");
|
|
3256
3256
|
const email = pickStr(data, "email");
|
|
@@ -4397,12 +4397,12 @@ async function apiDeleteRaw(url, config, options = {}) {
|
|
|
4397
4397
|
if (res.status < 200 || res.status >= 300) {
|
|
4398
4398
|
throw new Error(formatHttpError(res.status, res.text, { verbose: options.verbose }));
|
|
4399
4399
|
}
|
|
4400
|
-
const
|
|
4401
|
-
const value = !
|
|
4400
|
+
const text3 = res.text;
|
|
4401
|
+
const value = !text3.trim() ? null : (() => {
|
|
4402
4402
|
try {
|
|
4403
|
-
return JSON.parse(
|
|
4403
|
+
return JSON.parse(text3);
|
|
4404
4404
|
} catch {
|
|
4405
|
-
return
|
|
4405
|
+
return text3;
|
|
4406
4406
|
}
|
|
4407
4407
|
})();
|
|
4408
4408
|
return { value, httpStatus: res.status };
|
|
@@ -5440,13 +5440,13 @@ function skippedNoSpendCampaignTypes() {
|
|
|
5440
5440
|
};
|
|
5441
5441
|
}
|
|
5442
5442
|
function errorCampaignTypes(message) {
|
|
5443
|
-
const
|
|
5443
|
+
const text3 = message.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
5444
5444
|
return {
|
|
5445
5445
|
campaignTypesStatus: "error",
|
|
5446
5446
|
campaignTypes: null,
|
|
5447
5447
|
hasDisplay: null,
|
|
5448
5448
|
hasPmax: null,
|
|
5449
|
-
campaignTypesError:
|
|
5449
|
+
campaignTypesError: text3 || "unknown error"
|
|
5450
5450
|
};
|
|
5451
5451
|
}
|
|
5452
5452
|
function errorMessage(err) {
|
|
@@ -5489,6 +5489,231 @@ var init_campaign_types = __esm({
|
|
|
5489
5489
|
}
|
|
5490
5490
|
});
|
|
5491
5491
|
|
|
5492
|
+
// src/commands/ad/_shared.ts
|
|
5493
|
+
function resolveAdAccountId(account, label2 = "-a, --account") {
|
|
5494
|
+
try {
|
|
5495
|
+
return requireNumericMediaCustomerId(account, label2);
|
|
5496
|
+
} catch (e) {
|
|
5497
|
+
console.error(`
|
|
5498
|
+
\u274C ${e instanceof Error ? e.message : String(e)}
|
|
5499
|
+
`);
|
|
5500
|
+
process.exit(1);
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
function withResolvedAdAccount(opts) {
|
|
5504
|
+
return { ...opts, account: resolveAdAccountId(opts.account) };
|
|
5505
|
+
}
|
|
5506
|
+
async function findItemInList(listUrl, config, id, verbose) {
|
|
5507
|
+
const res = await apiFetch2(listUrl, config, {}, verbose);
|
|
5508
|
+
const item = (res.data ?? []).find((x) => x["id"] === id);
|
|
5509
|
+
if (!item) {
|
|
5510
|
+
throw new Error(`\u672A\u5728\u5217\u8868\u4E2D\u627E\u5230 id="${id}" \u7684\u6761\u76EE`);
|
|
5511
|
+
}
|
|
5512
|
+
return item;
|
|
5513
|
+
}
|
|
5514
|
+
function toGoogleDate(dateStr, offsetDays) {
|
|
5515
|
+
if (dateStr) return dateStr.replace(/-/g, "/");
|
|
5516
|
+
const d = /* @__PURE__ */ new Date();
|
|
5517
|
+
d.setDate(d.getDate() + offsetDays);
|
|
5518
|
+
return d.toISOString().slice(0, 10).replace(/-/g, "/");
|
|
5519
|
+
}
|
|
5520
|
+
function toDisplayMoney(raw) {
|
|
5521
|
+
if (raw == null) return null;
|
|
5522
|
+
const n = Number(raw);
|
|
5523
|
+
if (!Number.isFinite(n)) return null;
|
|
5524
|
+
return n / 100;
|
|
5525
|
+
}
|
|
5526
|
+
function toCentAmount(displayValue) {
|
|
5527
|
+
if (!Number.isFinite(displayValue)) {
|
|
5528
|
+
throw new Error(`toCentAmount: \u8F93\u5165\u5FC5\u987B\u662F\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${displayValue}`);
|
|
5529
|
+
}
|
|
5530
|
+
return Math.round(displayValue * 100);
|
|
5531
|
+
}
|
|
5532
|
+
function convertBatchMoneyTreeFromYuan(value) {
|
|
5533
|
+
return convertBatchMoneyTreeFromYuanInner(value);
|
|
5534
|
+
}
|
|
5535
|
+
function convertBatchMoneyTreeFromYuanInner(value) {
|
|
5536
|
+
if (Array.isArray(value)) {
|
|
5537
|
+
return value.map(convertBatchMoneyTreeFromYuanInner);
|
|
5538
|
+
}
|
|
5539
|
+
if (value && typeof value === "object") {
|
|
5540
|
+
const out = {};
|
|
5541
|
+
for (const [key, val] of Object.entries(value)) {
|
|
5542
|
+
if (typeof val === "number" && CAMPAIGN_BATCH_MONEY_KEYS.has(key)) {
|
|
5543
|
+
out[key] = toCentAmount(val);
|
|
5544
|
+
} else {
|
|
5545
|
+
out[key] = convertBatchMoneyTreeFromYuanInner(val);
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
return out;
|
|
5549
|
+
}
|
|
5550
|
+
return value;
|
|
5551
|
+
}
|
|
5552
|
+
function adgroupListUrl(googleApiUrl, account, startDate, endDate, fresh) {
|
|
5553
|
+
const params = new URLSearchParams();
|
|
5554
|
+
params.set("startDate", toGoogleDate(startDate, -30));
|
|
5555
|
+
params.set("endDate", toGoogleDate(endDate, 0));
|
|
5556
|
+
if (fresh) params.set("newest", "true");
|
|
5557
|
+
return `${googleApiUrl}/adgroupnmanagement/v2/list/${account}?${params}`;
|
|
5558
|
+
}
|
|
5559
|
+
function campaignListUrl(googleApiUrl, account, startDate, endDate, fresh) {
|
|
5560
|
+
const params = new URLSearchParams();
|
|
5561
|
+
params.set("startDate", toGoogleDate(startDate, -30));
|
|
5562
|
+
params.set("endDate", toGoogleDate(endDate, 0));
|
|
5563
|
+
if (fresh) params.set("newest", "true");
|
|
5564
|
+
return `${googleApiUrl}/campaignmanagement/v2/list/${account}?${params}`;
|
|
5565
|
+
}
|
|
5566
|
+
function requireGoogleApi(config) {
|
|
5567
|
+
if (!config.googleApiUrl) {
|
|
5568
|
+
console.error(
|
|
5569
|
+
"\n\u274C \u672A\u627E\u5230 Google API \u5730\u5740\u3002\n Google API \u5730\u5740\u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_GOOGLE_API \u8986\u76D6\u3002\n"
|
|
5570
|
+
);
|
|
5571
|
+
process.exit(1);
|
|
5572
|
+
}
|
|
5573
|
+
return config.googleApiUrl;
|
|
5574
|
+
}
|
|
5575
|
+
var CAMPAIGN_BATCH_MONEY_KEYS;
|
|
5576
|
+
var init_shared = __esm({
|
|
5577
|
+
"src/commands/ad/_shared.ts"() {
|
|
5578
|
+
"use strict";
|
|
5579
|
+
init_auth();
|
|
5580
|
+
init_media_customer_id();
|
|
5581
|
+
CAMPAIGN_BATCH_MONEY_KEYS = /* @__PURE__ */ new Set([
|
|
5582
|
+
"Budget",
|
|
5583
|
+
"MaxCPCAmount",
|
|
5584
|
+
"MaxCpmAmount",
|
|
5585
|
+
"MaxCPVAmount",
|
|
5586
|
+
"TargetCpa_BidingAmount",
|
|
5587
|
+
"TargetSpend_BidCeilingAmount",
|
|
5588
|
+
"TargetCpaAmount",
|
|
5589
|
+
"MaxCPC"
|
|
5590
|
+
]);
|
|
5591
|
+
}
|
|
5592
|
+
});
|
|
5593
|
+
|
|
5594
|
+
// src/commands/accounts-digest/enabled-campaigns.ts
|
|
5595
|
+
function isPmaxChannel(channel) {
|
|
5596
|
+
return PMAX_CHANNEL.test(String(channel ?? ""));
|
|
5597
|
+
}
|
|
5598
|
+
function isDisplayChannel(channel) {
|
|
5599
|
+
return DISPLAY_CHANNEL.test(String(channel ?? "").trim());
|
|
5600
|
+
}
|
|
5601
|
+
function text(value) {
|
|
5602
|
+
return value == null ? "" : String(value);
|
|
5603
|
+
}
|
|
5604
|
+
function impressionsOf(row) {
|
|
5605
|
+
const n = Number(row["impressions"]);
|
|
5606
|
+
return Number.isFinite(n) ? n : 0;
|
|
5607
|
+
}
|
|
5608
|
+
function summarizeEnabledCampaigns(rows) {
|
|
5609
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
5610
|
+
let enabledCampaignCount = 0;
|
|
5611
|
+
let hasEnabledPmax = false;
|
|
5612
|
+
const zeroImpressionEnabled = [];
|
|
5613
|
+
for (const item of list) {
|
|
5614
|
+
if (!item || typeof item !== "object") continue;
|
|
5615
|
+
const row = item;
|
|
5616
|
+
const status = text(row["statusV2"] || row["status"]).toLowerCase();
|
|
5617
|
+
if (status !== "enabled") continue;
|
|
5618
|
+
const id = text(row["id"]).trim();
|
|
5619
|
+
if (!id) continue;
|
|
5620
|
+
enabledCampaignCount += 1;
|
|
5621
|
+
const channelType = text(row["channelTypeV2"] || row["channelType"]);
|
|
5622
|
+
if (isPmaxChannel(channelType)) hasEnabledPmax = true;
|
|
5623
|
+
if (impressionsOf(row) !== 0) continue;
|
|
5624
|
+
if (isPmaxChannel(channelType) || isDisplayChannel(channelType)) continue;
|
|
5625
|
+
zeroImpressionEnabled.push({
|
|
5626
|
+
id,
|
|
5627
|
+
name: text(row["name"]),
|
|
5628
|
+
channelType
|
|
5629
|
+
});
|
|
5630
|
+
}
|
|
5631
|
+
return {
|
|
5632
|
+
enabledCampaignStatus: "ok",
|
|
5633
|
+
hasEnabledPmax,
|
|
5634
|
+
enabledCampaignCount,
|
|
5635
|
+
zeroImpressionEnabled,
|
|
5636
|
+
enabledCampaignError: null
|
|
5637
|
+
};
|
|
5638
|
+
}
|
|
5639
|
+
function skippedNoSpendEnabledCampaigns() {
|
|
5640
|
+
return {
|
|
5641
|
+
enabledCampaignStatus: "skipped-no-spend",
|
|
5642
|
+
hasEnabledPmax: null,
|
|
5643
|
+
enabledCampaignCount: null,
|
|
5644
|
+
zeroImpressionEnabled: null,
|
|
5645
|
+
enabledCampaignError: null
|
|
5646
|
+
};
|
|
5647
|
+
}
|
|
5648
|
+
function errorEnabledCampaigns(message) {
|
|
5649
|
+
const textMessage = message.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
5650
|
+
return {
|
|
5651
|
+
enabledCampaignStatus: "error",
|
|
5652
|
+
hasEnabledPmax: null,
|
|
5653
|
+
enabledCampaignCount: null,
|
|
5654
|
+
zeroImpressionEnabled: null,
|
|
5655
|
+
enabledCampaignError: textMessage || "unknown error"
|
|
5656
|
+
};
|
|
5657
|
+
}
|
|
5658
|
+
function errorMessage2(err) {
|
|
5659
|
+
if (err instanceof Error) return err.message;
|
|
5660
|
+
return String(err);
|
|
5661
|
+
}
|
|
5662
|
+
async function fetchEnabledCampaignScans(accountIds, fetchOne, opts) {
|
|
5663
|
+
const ids = [...new Set(accountIds.filter((id) => id.trim() !== ""))];
|
|
5664
|
+
const out = /* @__PURE__ */ new Map();
|
|
5665
|
+
if (ids.length === 0) return out;
|
|
5666
|
+
const concurrency = Math.max(1, Math.min(opts?.concurrency ?? 8, 16, ids.length));
|
|
5667
|
+
let cursor = 0;
|
|
5668
|
+
let done = 0;
|
|
5669
|
+
const workers = new Array(concurrency).fill(0).map(async () => {
|
|
5670
|
+
while (true) {
|
|
5671
|
+
const index = cursor++;
|
|
5672
|
+
if (index >= ids.length) return;
|
|
5673
|
+
const id = ids[index];
|
|
5674
|
+
try {
|
|
5675
|
+
out.set(id, summarizeEnabledCampaigns(await fetchOne(id)));
|
|
5676
|
+
} catch (err) {
|
|
5677
|
+
out.set(id, errorEnabledCampaigns(errorMessage2(err)));
|
|
5678
|
+
}
|
|
5679
|
+
done += 1;
|
|
5680
|
+
opts?.onProgress?.(done, ids.length);
|
|
5681
|
+
}
|
|
5682
|
+
});
|
|
5683
|
+
await Promise.all(workers);
|
|
5684
|
+
return out;
|
|
5685
|
+
}
|
|
5686
|
+
var PMAX_CHANNEL, DISPLAY_CHANNEL;
|
|
5687
|
+
var init_enabled_campaigns = __esm({
|
|
5688
|
+
"src/commands/accounts-digest/enabled-campaigns.ts"() {
|
|
5689
|
+
"use strict";
|
|
5690
|
+
PMAX_CHANNEL = /performance[\s_-]?max/i;
|
|
5691
|
+
DISPLAY_CHANNEL = /^display$/i;
|
|
5692
|
+
}
|
|
5693
|
+
});
|
|
5694
|
+
|
|
5695
|
+
// src/commands/accounts-digest/pace.ts
|
|
5696
|
+
function digestWindowDays(start, end) {
|
|
5697
|
+
const s = Date.parse(`${start}T00:00:00Z`);
|
|
5698
|
+
const e = Date.parse(`${end}T00:00:00Z`);
|
|
5699
|
+
if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) return 7;
|
|
5700
|
+
const days = Math.round((e - s) / 864e5) + 1;
|
|
5701
|
+
return days >= 1 ? days : 7;
|
|
5702
|
+
}
|
|
5703
|
+
function spendPace(spend, balance, days) {
|
|
5704
|
+
const windowDays = days >= 1 ? days : 7;
|
|
5705
|
+
const dailySpend = spend != null && spend > 0 ? +(spend / windowDays).toFixed(2) : null;
|
|
5706
|
+
const remainingDays = dailySpend != null && dailySpend >= MIN_DAILY_SPEND && balance != null ? +(balance / dailySpend).toFixed(1) : null;
|
|
5707
|
+
return { dailySpend, remainingDays };
|
|
5708
|
+
}
|
|
5709
|
+
var MIN_DAILY_SPEND;
|
|
5710
|
+
var init_pace = __esm({
|
|
5711
|
+
"src/commands/accounts-digest/pace.ts"() {
|
|
5712
|
+
"use strict";
|
|
5713
|
+
MIN_DAILY_SPEND = 0.01;
|
|
5714
|
+
}
|
|
5715
|
+
});
|
|
5716
|
+
|
|
5492
5717
|
// src/commands/accounts-digest/filters.ts
|
|
5493
5718
|
function keepDigestRow(row, opts) {
|
|
5494
5719
|
const { maxCpa, zeroConversions } = opts;
|
|
@@ -5519,16 +5744,23 @@ var init_filters = __esm({
|
|
|
5519
5744
|
// src/commands/accounts-digest/run.ts
|
|
5520
5745
|
function formatCampaignTypesCell(row) {
|
|
5521
5746
|
if (row.campaignTypesStatus === "ok") {
|
|
5522
|
-
const flags = [
|
|
5523
|
-
row.hasDisplay ? "Display" : "\u65E0Display",
|
|
5524
|
-
row.hasPmax ? "PMax" : "\u65E0PMax"
|
|
5525
|
-
];
|
|
5747
|
+
const flags = [row.hasDisplay ? "Display" : "\u65E0Display", row.hasPmax ? "PMax" : "\u65E0PMax"];
|
|
5526
5748
|
return flags.join(" ");
|
|
5527
5749
|
}
|
|
5528
5750
|
if (row.campaignTypesStatus === "skipped-no-spend") return "\u672A\u67E5(\u65E0\u6D88\u8017)";
|
|
5529
5751
|
if (row.campaignTypesStatus === "error") return "\u67E5\u8BE2\u5931\u8D25";
|
|
5530
5752
|
return "-";
|
|
5531
5753
|
}
|
|
5754
|
+
function formatEnabledCampaignCell(row) {
|
|
5755
|
+
if (row.enabledCampaignStatus === "ok") {
|
|
5756
|
+
const pmax = row.hasEnabledPmax ? "\u6709\u542F\u7528PMax" : "\u65E0\u542F\u7528PMax";
|
|
5757
|
+
const zeros = row.zeroImpressionEnabled?.length ?? 0;
|
|
5758
|
+
return zeros > 0 ? `${pmax} 0\u5C55\u793A${zeros}` : pmax;
|
|
5759
|
+
}
|
|
5760
|
+
if (row.enabledCampaignStatus === "skipped-no-spend") return "\u672A\u67E5(\u65E0\u6D88\u8017)";
|
|
5761
|
+
if (row.enabledCampaignStatus === "error") return "\u67E5\u8BE2\u5931\u8D25";
|
|
5762
|
+
return "-";
|
|
5763
|
+
}
|
|
5532
5764
|
function round2(n) {
|
|
5533
5765
|
if (n == null) return null;
|
|
5534
5766
|
const v = Number(n);
|
|
@@ -5557,6 +5789,21 @@ async function runAccountsDigest(opts) {
|
|
|
5557
5789
|
console.error("\n\u274C \u5F53\u524D\u914D\u7F6E\u6CA1\u6709 googleApiUrl\uFF0C\u65E0\u6CD5\u62C9\u53D6\u5E7F\u544A\u7CFB\u5217\u7C7B\u578B\u3002\n");
|
|
5558
5790
|
process.exit(1);
|
|
5559
5791
|
}
|
|
5792
|
+
if (opts.withEnabledCampaigns && media !== "Google") {
|
|
5793
|
+
console.error(
|
|
5794
|
+
"\n\u274C --with-enabled-campaigns \u53EA\u652F\u6301 -m Google\uFF08\u7CFB\u5217\u5217\u8868\u6765\u81EA Google campaignmanagement\uFF09\u3002\n"
|
|
5795
|
+
);
|
|
5796
|
+
process.exit(1);
|
|
5797
|
+
}
|
|
5798
|
+
if (opts.withEnabledCampaigns && !config.googleApiUrl) {
|
|
5799
|
+
console.error("\n\u274C \u5F53\u524D\u914D\u7F6E\u6CA1\u6709 googleApiUrl\uFF0C\u65E0\u6CD5\u62C9\u53D6\u5E7F\u544A\u7CFB\u5217\u3002\n");
|
|
5800
|
+
process.exit(1);
|
|
5801
|
+
}
|
|
5802
|
+
if (opts.withCampaignTypes && opts.withEnabledCampaigns) {
|
|
5803
|
+
process.stderr.write(
|
|
5804
|
+
"\u26A0 --with-campaign-types \u4E0E --with-enabled-campaigns \u4F1A\u5404\u6253\u4E00\u8F6E\u6309\u6237\u8BF7\u6C42\u3002\u542F\u7528 PMax / 0 \u5C55\u793A\u53EA\u7528\u540E\u8005\u3002\n"
|
|
5805
|
+
);
|
|
5806
|
+
}
|
|
5560
5807
|
const filterIds = (opts.accounts ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
5561
5808
|
const filterSet = new Set(filterIds);
|
|
5562
5809
|
const minSpend = opts.minSpend ?? 0;
|
|
@@ -5658,6 +5905,10 @@ async function runAccountsDigest(opts) {
|
|
|
5658
5905
|
overviewMap = fetched.overviewMap;
|
|
5659
5906
|
batchChunkSize = fetched.chunkSize;
|
|
5660
5907
|
}
|
|
5908
|
+
const fallbackWindow = defaultDateRange();
|
|
5909
|
+
const windowStart = opts.startDate ?? fallbackWindow.startDate;
|
|
5910
|
+
const windowEnd = opts.endDate ?? fallbackWindow.endDate;
|
|
5911
|
+
const windowDays = digestWindowDays(windowStart, windowEnd);
|
|
5661
5912
|
const rows = [];
|
|
5662
5913
|
let spendPositiveCount = 0;
|
|
5663
5914
|
for (const item of accountsList) {
|
|
@@ -5689,7 +5940,8 @@ async function runAccountsDigest(opts) {
|
|
|
5689
5940
|
// 百分比
|
|
5690
5941
|
cpc: round2(cpc),
|
|
5691
5942
|
cpa: round2(cpa),
|
|
5692
|
-
invalidOAuthToken: !!ma.invalidOAuthToken
|
|
5943
|
+
invalidOAuthToken: !!ma.invalidOAuthToken,
|
|
5944
|
+
...spendPace(round2(spend), round2(bal?.remainingAccountBudget ?? null), windowDays)
|
|
5693
5945
|
};
|
|
5694
5946
|
if (!keepDigestRow(row, {
|
|
5695
5947
|
maxCpa: opts.maxCpa,
|
|
@@ -5747,6 +5999,61 @@ async function runAccountsDigest(opts) {
|
|
|
5747
5999
|
};
|
|
5748
6000
|
process.stderr.write(
|
|
5749
6001
|
` \u2713 [\u7CFB\u5217\u7C7B\u578B] \u5B8C\u6210\uFF1A\u6210\u529F ${ok}\uFF0C\u5931\u8D25 ${failed}\uFF0C\u672A\u67E5\uFF08\u65E0\u6D88\u8017\uFF09${skippedNoSpend}
|
|
6002
|
+
`
|
|
6003
|
+
);
|
|
6004
|
+
}
|
|
6005
|
+
let enabledCampaignMeta = null;
|
|
6006
|
+
if (opts.withEnabledCampaigns) {
|
|
6007
|
+
const concurrency = Math.max(1, Math.min(opts.enabledCampaignConcurrency ?? 8, 16));
|
|
6008
|
+
const spendIds = rows.filter((row) => (row.spend ?? 0) > 0).map((row) => row.mediaCustomerId);
|
|
6009
|
+
process.stderr.write(
|
|
6010
|
+
`\u23F3 [accounts-digest] \u542F\u7528\u7CFB\u5217\uFF1A${spendIds.length} \u4E2A\u6709\u6D88\u8017\u8D26\u6237\uFF0C\u5E76\u53D1 ${concurrency}\uFF08\u6D88\u8017\u4E3A 0 \u7684\u4E0D\u8BF7\u6C42\uFF09\u3002
|
|
6011
|
+
`
|
|
6012
|
+
);
|
|
6013
|
+
const googleApiUrl = config.googleApiUrl ?? "";
|
|
6014
|
+
const scans = await fetchEnabledCampaignScans(
|
|
6015
|
+
spendIds,
|
|
6016
|
+
async (accountId) => {
|
|
6017
|
+
const url = campaignListUrl(googleApiUrl, accountId, windowStart, windowEnd);
|
|
6018
|
+
const data = await apiFetch2(url, config, {}, !!opts.verbose);
|
|
6019
|
+
if (!Array.isArray(data?.data)) {
|
|
6020
|
+
throw new Error("\u7CFB\u5217\u5217\u8868\u6CA1\u6709 data \u6570\u7EC4");
|
|
6021
|
+
}
|
|
6022
|
+
return data.data;
|
|
6023
|
+
},
|
|
6024
|
+
{
|
|
6025
|
+
concurrency,
|
|
6026
|
+
onProgress: (done, total) => {
|
|
6027
|
+
if (done === total || done % 50 === 0) {
|
|
6028
|
+
process.stderr.write(` \u2713 [\u542F\u7528\u7CFB\u5217] ${done}/${total}
|
|
6029
|
+
`);
|
|
6030
|
+
}
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
);
|
|
6034
|
+
let ok = 0;
|
|
6035
|
+
let failed = 0;
|
|
6036
|
+
let skippedNoSpend = 0;
|
|
6037
|
+
for (const row of rows) {
|
|
6038
|
+
const fields = (row.spend ?? 0) > 0 ? scans.get(row.mediaCustomerId) ?? errorEnabledCampaigns("\u672A\u8FD4\u56DE\u8BE5\u8D26\u6237\u7684\u7CFB\u5217\u5217\u8868") : skippedNoSpendEnabledCampaigns();
|
|
6039
|
+
row.enabledCampaignStatus = fields.enabledCampaignStatus;
|
|
6040
|
+
row.hasEnabledPmax = fields.hasEnabledPmax;
|
|
6041
|
+
row.enabledCampaignCount = fields.enabledCampaignCount;
|
|
6042
|
+
row.zeroImpressionEnabled = fields.zeroImpressionEnabled;
|
|
6043
|
+
row.enabledCampaignError = fields.enabledCampaignError;
|
|
6044
|
+
if (fields.enabledCampaignStatus === "ok") ok += 1;
|
|
6045
|
+
else if (fields.enabledCampaignStatus === "error") failed += 1;
|
|
6046
|
+
else skippedNoSpend += 1;
|
|
6047
|
+
}
|
|
6048
|
+
enabledCampaignMeta = {
|
|
6049
|
+
requested: spendIds.length,
|
|
6050
|
+
ok,
|
|
6051
|
+
failed,
|
|
6052
|
+
skippedNoSpend,
|
|
6053
|
+
concurrency
|
|
6054
|
+
};
|
|
6055
|
+
process.stderr.write(
|
|
6056
|
+
` \u2713 [\u542F\u7528\u7CFB\u5217] \u5B8C\u6210\uFF1A\u6210\u529F ${ok}\uFF0C\u5931\u8D25 ${failed}\uFF0C\u672A\u67E5\uFF08\u65E0\u6D88\u8017\uFF09${skippedNoSpend}
|
|
5750
6057
|
`
|
|
5751
6058
|
);
|
|
5752
6059
|
}
|
|
@@ -5765,7 +6072,8 @@ async function runAccountsDigest(opts) {
|
|
|
5765
6072
|
window: {
|
|
5766
6073
|
startDate: opts.startDate ?? null,
|
|
5767
6074
|
endDate: opts.endDate ?? null,
|
|
5768
|
-
|
|
6075
|
+
dayCount: windowDays,
|
|
6076
|
+
note: opts.startDate && opts.endDate ? "\u7528\u6237/AI \u660E\u786E\u6307\u5B9A\u533A\u95F4\u3002dailySpend = spend / dayCount\uFF0CremainingDays = balance / dailySpend" : "\u672A\u6307\u5B9A\u533A\u95F4\uFF0CCLI \u9ED8\u8BA4\u8FD1 7 \u5929\uFF1BSKILL \u8981\u6C42\u5148\u5411\u7528\u6237\u786E\u8BA4\u3002dailySpend = spend / dayCount"
|
|
5769
6077
|
},
|
|
5770
6078
|
scanned: accountsList.length,
|
|
5771
6079
|
validAccountCount: validIds.length,
|
|
@@ -5793,7 +6101,9 @@ async function runAccountsDigest(opts) {
|
|
|
5793
6101
|
currencyNote: "\u5404\u8D26\u6237\u4E3B\u5E01\u79CD\u53EF\u80FD\u4E0D\u540C\uFF1Btotals \u53EA\u5408\u8BA1 returned\uFF08\u547D\u4E2D\uFF09\u884C\uFF0C\u7981\u6B62\u5199\u6210\u5168\u90E8\u8D26\u6237\u3002\u8DE8\u5E01\u79CD\u8BF7\u6309 currencyCode \u5206\u8868",
|
|
5794
6102
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5795
6103
|
/** 未传 --with-campaign-types 时为 null。失败户的 hasDisplay 是 null,不能当成「无展示」。 */
|
|
5796
|
-
campaignTypes: campaignTypeMeta
|
|
6104
|
+
campaignTypes: campaignTypeMeta,
|
|
6105
|
+
/** 未传 --with-enabled-campaigns 时为 null。失败户的 hasEnabledPmax 是 null,不能当成「无 PMax」。 */
|
|
6106
|
+
enabledCampaigns: enabledCampaignMeta
|
|
5797
6107
|
};
|
|
5798
6108
|
const agentBrief = buildDigestAgentBrief({
|
|
5799
6109
|
rows,
|
|
@@ -5839,6 +6149,9 @@ ${media} \u8D26\u6237\u6295\u653E\u753B\u50CF\uFF1A\u8FD4\u56DE ${rows.length} \
|
|
|
5839
6149
|
if (opts.withCampaignTypes) {
|
|
5840
6150
|
cols.push({ key: "types", header: "\u7CFB\u5217\u7C7B\u578B" });
|
|
5841
6151
|
}
|
|
6152
|
+
if (opts.withEnabledCampaigns) {
|
|
6153
|
+
cols.push({ key: "enabled", header: "\u542F\u7528\u7CFB\u5217" });
|
|
6154
|
+
}
|
|
5842
6155
|
const tableRows = rows.map((r) => ({
|
|
5843
6156
|
id: r.mediaCustomerId,
|
|
5844
6157
|
company: r.advertiserName ?? "-",
|
|
@@ -5851,7 +6164,8 @@ ${media} \u8D26\u6237\u6295\u653E\u753B\u50CF\uFF1A\u8FD4\u56DE ${rows.length} \
|
|
|
5851
6164
|
cpc: formatMoneyDisplay(r.cpc, r.currencyCode),
|
|
5852
6165
|
cpa: formatMoneyDisplay(r.cpa, r.currencyCode),
|
|
5853
6166
|
balance: formatMoneyDisplay(r.balance, r.currencyCode),
|
|
5854
|
-
types: formatCampaignTypesCell(r)
|
|
6167
|
+
types: formatCampaignTypesCell(r),
|
|
6168
|
+
enabled: formatEnabledCampaignCell(r)
|
|
5855
6169
|
}));
|
|
5856
6170
|
printCliTable(tableRows, cols);
|
|
5857
6171
|
if (meta.nullConversionCount > 0) {
|
|
@@ -5885,6 +6199,9 @@ var init_run = __esm({
|
|
|
5885
6199
|
init_login_customer_id();
|
|
5886
6200
|
init_brief();
|
|
5887
6201
|
init_campaign_types();
|
|
6202
|
+
init_shared();
|
|
6203
|
+
init_enabled_campaigns();
|
|
6204
|
+
init_pace();
|
|
5888
6205
|
init_filters();
|
|
5889
6206
|
}
|
|
5890
6207
|
});
|
|
@@ -5916,6 +6233,14 @@ function register10(program2) {
|
|
|
5916
6233
|
"--campaign-type-concurrency <n>",
|
|
5917
6234
|
"\u7CFB\u5217\u7C7B\u578B\u8BF7\u6C42\u5E76\u53D1\uFF081\u201316\uFF0C\u9ED8\u8BA4 8\uFF09",
|
|
5918
6235
|
(v) => parseInt(v, 10)
|
|
6236
|
+
).option(
|
|
6237
|
+
"--with-enabled-campaigns",
|
|
6238
|
+
"\u4EC5 Google\uFF1A\u5BF9\u533A\u95F4\u6D88\u8017 > 0 \u7684\u8D26\u6237\u5E76\u53D1\u62C9\u53D6\u7CFB\u5217\u5217\u8868\uFF0C\u5728\u6BCF\u884C\u5199\u5165 hasEnabledPmax\uFF08\u53EA\u770B\u542F\u7528\u4E2D\u7684\u7CFB\u5217\uFF09\u548C zeroImpressionEnabled\uFF08\u542F\u7528\u3001\u533A\u95F4\u5C55\u793A\u4E3A 0\u3001\u4E14\u4E0D\u662F PMax/Display\uFF09\u3002\u7528\u6765\u505A D \u7EC4\u8FD9\u7C7B\u5DE1\u68C0\uFF0C\u4E0D\u8981\u518D\u9010\u6237\u8C03 ad campaigns\uFF0C\u4E5F\u4E0D\u8981\u548C --with-campaign-types \u4E00\u8D77\u5F00\u3002",
|
|
6239
|
+
false
|
|
6240
|
+
).option(
|
|
6241
|
+
"--enabled-campaign-concurrency <n>",
|
|
6242
|
+
"\u542F\u7528\u7CFB\u5217\u5217\u8868\u8BF7\u6C42\u5E76\u53D1\uFF081\u201316\uFF0C\u9ED8\u8BA4 8\uFF09",
|
|
6243
|
+
(v) => parseInt(v, 10)
|
|
5919
6244
|
).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF0C\u4E0A\u9650 200\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option(
|
|
5920
6245
|
"--json-out <path>",
|
|
5921
6246
|
"\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
|
|
@@ -5939,7 +6264,9 @@ function register10(program2) {
|
|
|
5939
6264
|
verbose: opts.verbose,
|
|
5940
6265
|
loginCustomerId: opts.loginCustomerId,
|
|
5941
6266
|
withCampaignTypes: opts.withCampaignTypes,
|
|
5942
|
-
campaignTypeConcurrency: opts.campaignTypeConcurrency
|
|
6267
|
+
campaignTypeConcurrency: opts.campaignTypeConcurrency,
|
|
6268
|
+
withEnabledCampaigns: opts.withEnabledCampaigns,
|
|
6269
|
+
enabledCampaignConcurrency: opts.enabledCampaignConcurrency
|
|
5943
6270
|
});
|
|
5944
6271
|
}
|
|
5945
6272
|
);
|
|
@@ -6082,6 +6409,7 @@ var init_wrap_snapshot_envelope = __esm({
|
|
|
6082
6409
|
"geo-matched": "countries",
|
|
6083
6410
|
"campaign-geo": "countries",
|
|
6084
6411
|
"campaign-geo-matched": "countries",
|
|
6412
|
+
"geo-targeted": "countries",
|
|
6085
6413
|
"campaign-device": "devices",
|
|
6086
6414
|
audience: "audience"
|
|
6087
6415
|
};
|
|
@@ -6297,6 +6625,7 @@ var init_google_analysis = __esm({
|
|
|
6297
6625
|
"geo-matched",
|
|
6298
6626
|
"campaign-geo",
|
|
6299
6627
|
"campaign-geo-matched",
|
|
6628
|
+
"geo-targeted",
|
|
6300
6629
|
"campaign-device",
|
|
6301
6630
|
"audience",
|
|
6302
6631
|
"asset-images",
|
|
@@ -6331,6 +6660,10 @@ var init_google_analysis = __esm({
|
|
|
6331
6660
|
"campaign-geo-matched": [
|
|
6332
6661
|
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
6333
6662
|
],
|
|
6663
|
+
"geo-targeted": [
|
|
6664
|
+
"// \u5F53\u524D\u4ECD\u5728\u6295\u653E\u7684\u5B9A\u4F4D\uFF08\u5DF2\u79FB\u9664\u56FD\u5BB6\u4E0D\u4F1A\u51FA\u73B0\uFF09\u3002\u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002",
|
|
6665
|
+
"// `ctr` \u5DF2\u6298\u6210 0~1 \u5C0F\u6570\uFF1B`conversionRate` \u7F51\u5173\u672C\u8EAB\u5C31\u662F 0~1\uFF0C\u4E0D\u8981\u518D \xF7100\u3002"
|
|
6666
|
+
],
|
|
6334
6667
|
"geo-matched": [
|
|
6335
6668
|
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
6336
6669
|
]
|
|
@@ -6410,8 +6743,8 @@ function relLuminance(hex) {
|
|
|
6410
6743
|
function textColorFor(bgHex) {
|
|
6411
6744
|
return relLuminance(bgHex) > 0.55 ? NEUTRAL.textDark : NEUTRAL.white;
|
|
6412
6745
|
}
|
|
6413
|
-
function xmlEscape(
|
|
6414
|
-
return
|
|
6746
|
+
function xmlEscape(text3) {
|
|
6747
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6415
6748
|
}
|
|
6416
6749
|
function colLetter(index) {
|
|
6417
6750
|
let n = index + 1;
|
|
@@ -6533,8 +6866,8 @@ function sheetRelsXml(sheet) {
|
|
|
6533
6866
|
).join("");
|
|
6534
6867
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${rels}</Relationships>`;
|
|
6535
6868
|
}
|
|
6536
|
-
function estimateWrapHeight(
|
|
6537
|
-
const str3 = String(
|
|
6869
|
+
function estimateWrapHeight(text3, colWidthChars) {
|
|
6870
|
+
const str3 = String(text3 ?? "");
|
|
6538
6871
|
if (!str3) return void 0;
|
|
6539
6872
|
const lines = str3.split("\n").reduce((sum, line) => {
|
|
6540
6873
|
const width = Math.max(colWidthChars || 20, 8);
|
|
@@ -6682,7 +7015,7 @@ var init_xlsx_style_engine = __esm({
|
|
|
6682
7015
|
for (let i = 0; i < n; i++) this.pushRow([]);
|
|
6683
7016
|
return this;
|
|
6684
7017
|
}
|
|
6685
|
-
titleBar(
|
|
7018
|
+
titleBar(text3, opts = {}) {
|
|
6686
7019
|
const fill = opts.fill === null ? void 0 : opts.fill ?? NEUTRAL.titleFill;
|
|
6687
7020
|
const fontColor = opts.fontColor ?? (fill ? textColorFor(fill) : NEUTRAL.textDark);
|
|
6688
7021
|
const s = this.registry.resolve({
|
|
@@ -6693,22 +7026,22 @@ var init_xlsx_style_engine = __esm({
|
|
|
6693
7026
|
border: opts.border ?? false,
|
|
6694
7027
|
hAlign: opts.hAlign ?? "left"
|
|
6695
7028
|
});
|
|
6696
|
-
this.pushRow([{ value:
|
|
7029
|
+
this.pushRow([{ value: text3, styleId: s }], { height: 28 });
|
|
6697
7030
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
6698
7031
|
return this;
|
|
6699
7032
|
}
|
|
6700
|
-
subtitleBar(
|
|
7033
|
+
subtitleBar(text3, opts = {}) {
|
|
6701
7034
|
const s = this.registry.resolve({
|
|
6702
7035
|
fontSize: 10.5,
|
|
6703
7036
|
fontColor: NEUTRAL.subtitleText,
|
|
6704
7037
|
fill: NEUTRAL.subtitleFill,
|
|
6705
7038
|
border: false
|
|
6706
7039
|
});
|
|
6707
|
-
this.pushRow([{ value:
|
|
7040
|
+
this.pushRow([{ value: text3, styleId: s }], { height: 20 });
|
|
6708
7041
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
6709
7042
|
return this;
|
|
6710
7043
|
}
|
|
6711
|
-
sectionBar(
|
|
7044
|
+
sectionBar(text3, opts = {}) {
|
|
6712
7045
|
const fill = opts.fill ?? this.accentHex;
|
|
6713
7046
|
const s = this.registry.resolve({
|
|
6714
7047
|
fontSize: 11,
|
|
@@ -6718,11 +7051,11 @@ var init_xlsx_style_engine = __esm({
|
|
|
6718
7051
|
border: false,
|
|
6719
7052
|
hAlign: "center"
|
|
6720
7053
|
});
|
|
6721
|
-
this.pushRow([{ value:
|
|
7054
|
+
this.pushRow([{ value: text3, styleId: s }], { height: 22 });
|
|
6722
7055
|
this.mergeCurrentRow(opts.span || this.colCount);
|
|
6723
7056
|
return this;
|
|
6724
7057
|
}
|
|
6725
|
-
noteRow(
|
|
7058
|
+
noteRow(text3, span) {
|
|
6726
7059
|
const s = this.registry.resolve({
|
|
6727
7060
|
fontSize: 9,
|
|
6728
7061
|
fontColor: NEUTRAL.textMuted,
|
|
@@ -6730,8 +7063,8 @@ var init_xlsx_style_engine = __esm({
|
|
|
6730
7063
|
border: true,
|
|
6731
7064
|
vAlign: "top"
|
|
6732
7065
|
});
|
|
6733
|
-
const height = estimateWrapHeight(
|
|
6734
|
-
this.pushRow([{ value:
|
|
7066
|
+
const height = estimateWrapHeight(text3, this.colWidths.reduce((a, b) => a + b, 0) || 60);
|
|
7067
|
+
this.pushRow([{ value: text3, styleId: s }], { height });
|
|
6735
7068
|
this.mergeCurrentRow(span || this.colCount);
|
|
6736
7069
|
return this;
|
|
6737
7070
|
}
|
|
@@ -7397,11 +7730,17 @@ var init_sections = __esm({
|
|
|
7397
7730
|
},
|
|
7398
7731
|
{
|
|
7399
7732
|
name: "campaign-geo-matched",
|
|
7400
|
-
description: "\u76F8\u7B26\u5730\u7406\u4F4D\u7F6E\uFF08Matched locations\uFF0Cuser_location_view\uFF09\u7CFB\u5217\u7EA7\u660E\u7EC6 GET \u2026/campaigns/reports/geo/matched/combined",
|
|
7733
|
+
description: "\u76F8\u7B26\u5730\u7406\u4F4D\u7F6E\uFF08Matched locations\uFF0Cuser_location_view\uFF09\u7CFB\u5217\u7EA7\u660E\u7EC6 GET \u2026/campaigns/reports/geo/matched/combined\u3002\u542B\u65E5\u671F\u5185\u66FE\u7ECF\u547D\u4E2D\u3001\u540E\u6765\u5DF2\u79FB\u9664\u7684\u56FD\u5BB6",
|
|
7401
7734
|
dateMode: "range",
|
|
7402
7735
|
path: (id) => `/reporting/media-account/${id}/campaigns/reports/geo/matched/combined`,
|
|
7403
7736
|
campaignGeoFilterOption: true
|
|
7404
7737
|
},
|
|
7738
|
+
{
|
|
7739
|
+
name: "geo-targeted",
|
|
7740
|
+
description: "\u5F53\u524D\u4ECD\u5728\u6295\u653E\u7684\u5730\u7406\u4F4D\u7F6E\uFF08\u672A\u79FB\u9664\u7684 campaign location criterion\uFF09GET \u2026/campaignmanagement/v2/targetedlocations\u3002\u4E0D\u542B\u5DF2\u5220\u9664\u56FD\u5BB6\uFF1BOKKI \u56FD\u5BB6\u8868\u7528\u8FD9\u4E2A",
|
|
7741
|
+
dateMode: "range",
|
|
7742
|
+
path: (id) => `/campaignmanagement/v2/targetedlocations/${id}`
|
|
7743
|
+
},
|
|
7405
7744
|
{
|
|
7406
7745
|
name: "campaign-device",
|
|
7407
7746
|
description: "\u5E7F\u544A\u7CFB\u5217\u7EF4\u5EA6\u8BBE\u5907 GET \u2026/campaigns/reports/device\uFF08GetCampaignDeviceReport\uFF1B\u884C\u53EF\u542B campaign/adGroup\uFF09",
|
|
@@ -7805,6 +8144,47 @@ var init_normalize_overview = __esm({
|
|
|
7805
8144
|
}
|
|
7806
8145
|
});
|
|
7807
8146
|
|
|
8147
|
+
// src/commands/google-analysis/geo-targeted.ts
|
|
8148
|
+
function isRecord3(value) {
|
|
8149
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
8150
|
+
}
|
|
8151
|
+
function finiteNumber(value) {
|
|
8152
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
8153
|
+
return Number.isFinite(n) ? n : 0;
|
|
8154
|
+
}
|
|
8155
|
+
function extractRows(raw) {
|
|
8156
|
+
if (Array.isArray(raw)) return raw.filter(isRecord3);
|
|
8157
|
+
if (!isRecord3(raw)) return [];
|
|
8158
|
+
if (Array.isArray(raw.data)) return raw.data.filter(isRecord3);
|
|
8159
|
+
if (isRecord3(raw.data) && Array.isArray(raw.data.data)) return raw.data.data.filter(isRecord3);
|
|
8160
|
+
return [];
|
|
8161
|
+
}
|
|
8162
|
+
function targetedLocationsToGeographic(raw) {
|
|
8163
|
+
const countries = extractRows(raw).map((row) => ({
|
|
8164
|
+
countryCriteriaId: row.id,
|
|
8165
|
+
countryOrRegion: typeof row.locationName === "string" ? row.locationName : "",
|
|
8166
|
+
campaignId: row.campaignId == null ? void 0 : String(row.campaignId),
|
|
8167
|
+
campaignName: typeof row.campaignName === "string" ? row.campaignName : "",
|
|
8168
|
+
impressions: finiteNumber(row.impressions),
|
|
8169
|
+
clicks: finiteNumber(row.clicks),
|
|
8170
|
+
ctr: finiteNumber(row.ctr) / 100,
|
|
8171
|
+
spend: finiteNumber(row.spend),
|
|
8172
|
+
conversions: finiteNumber(row.conversions),
|
|
8173
|
+
allConversions: finiteNumber(row.allConversions),
|
|
8174
|
+
averageCpc: finiteNumber(row.averageCpc),
|
|
8175
|
+
conversionRate: finiteNumber(row.conversionRate),
|
|
8176
|
+
costPerConversion: finiteNumber(row.costPerConversion),
|
|
8177
|
+
interactions: finiteNumber(row.interactions),
|
|
8178
|
+
interactionRate: row.interactionRate ?? null
|
|
8179
|
+
}));
|
|
8180
|
+
return { countries };
|
|
8181
|
+
}
|
|
8182
|
+
var init_geo_targeted = __esm({
|
|
8183
|
+
"src/commands/google-analysis/geo-targeted.ts"() {
|
|
8184
|
+
"use strict";
|
|
8185
|
+
}
|
|
8186
|
+
});
|
|
8187
|
+
|
|
7808
8188
|
// src/commands/google-analysis/match-type-en2zh.json
|
|
7809
8189
|
var match_type_en2zh_default;
|
|
7810
8190
|
var init_match_type_en2zh = __esm({
|
|
@@ -102947,6 +103327,7 @@ function annotateZhFields(payload, section) {
|
|
|
102947
103327
|
case "campaign-geo":
|
|
102948
103328
|
case "campaign-geo-matched":
|
|
102949
103329
|
case "geo-matched":
|
|
103330
|
+
case "geo-targeted":
|
|
102950
103331
|
case "geographic": {
|
|
102951
103332
|
const rows = payload.countries;
|
|
102952
103333
|
annotateArrayRows(rows, "countryOrRegion", "countryOrRegionZh", GEO_DICT2);
|
|
@@ -103100,6 +103481,10 @@ async function fetchGoogleAnalysisSectionJson(config, fullPath, verbose, name2,
|
|
|
103100
103481
|
return fetchSection();
|
|
103101
103482
|
case "campaign-geo-matched":
|
|
103102
103483
|
return fetchSection();
|
|
103484
|
+
case "geo-targeted":
|
|
103485
|
+
return targetedLocationsToGeographic(
|
|
103486
|
+
await fetchJson(config, fullPath, verbose, label2, http2)
|
|
103487
|
+
);
|
|
103103
103488
|
case "campaign-device":
|
|
103104
103489
|
return fetchSection();
|
|
103105
103490
|
case "audience":
|
|
@@ -103303,6 +103688,7 @@ var init_fetch = __esm({
|
|
|
103303
103688
|
init_normalize_rates();
|
|
103304
103689
|
init_normalize_money();
|
|
103305
103690
|
init_normalize_overview();
|
|
103691
|
+
init_geo_targeted();
|
|
103306
103692
|
init_translate_fields();
|
|
103307
103693
|
init_daily_metrics_range();
|
|
103308
103694
|
}
|
|
@@ -103397,8 +103783,8 @@ function summarizeOkkiDeviceSpend(rows) {
|
|
|
103397
103783
|
otherConversions: conv.other
|
|
103398
103784
|
};
|
|
103399
103785
|
}
|
|
103400
|
-
function narrativeClaimsMobileSpendLeads(
|
|
103401
|
-
const t =
|
|
103786
|
+
function narrativeClaimsMobileSpendLeads(text3) {
|
|
103787
|
+
const t = text3.replace(/\s+/g, "");
|
|
103402
103788
|
if (!t.includes("\u79FB\u52A8")) return false;
|
|
103403
103789
|
return /移动(?:端|设备)?(?:为|是)主要消耗/.test(t) || /移动(?:端|设备)?为主要(?:消耗)?设备/.test(t) || /移动(?:端|设备)?(?:消耗|花费|费用|流量)?占比高/.test(t);
|
|
103404
103790
|
}
|
|
@@ -103870,7 +104256,7 @@ function formatOkkiWeeklyReportErrors(result) {
|
|
|
103870
104256
|
...lines,
|
|
103871
104257
|
"",
|
|
103872
104258
|
"\u8BF7\u8865\u5168 narrative.sheetAnalysis.<sheet>.{summary,suggestions}\uFF085 \u4E2A Sheet\uFF09\u4E0E narrative.review.<dimension>.{overview,summary,suggestion}\uFF08\u56FA\u5B9A 5 \u7EF4\uFF1A\u8D26\u6237/\u5173\u952E\u8BCD/\u641C\u7D22\u5B57\u8BCD/\u8BBE\u5907/\u56FD\u5BB6\uFF09\u540E\u91CD\u65B0\u6267\u884C okki-render\u3002",
|
|
103873
|
-
"\u8868\u683C\u6570\u636E\u987B\u7531 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u5408\u5E76\uFF08campaigns / keywords / search-terms / campaign-device /
|
|
104259
|
+
"\u8868\u683C\u6570\u636E\u987B\u7531 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u5408\u5E76\uFF08campaigns / keywords / search-terms / campaign-device / geo-targeted\uFF09\u3002\u7981\u6B62\u624B\u5199 xlsx\u3002"
|
|
103874
104260
|
].join("\n");
|
|
103875
104261
|
}
|
|
103876
104262
|
var OKKI_SHEET_KEYS, OKKI_REVIEW_KEYS, OKKI_SNAPSHOT_SECTIONS, SHEET_LABELS, REVIEW_LABELS, SNAPSHOT_HINTS;
|
|
@@ -103897,7 +104283,7 @@ var init_okki_report_content = __esm({
|
|
|
103897
104283
|
"keywords",
|
|
103898
104284
|
"search-terms",
|
|
103899
104285
|
"campaign-device",
|
|
103900
|
-
"
|
|
104286
|
+
"geo-targeted"
|
|
103901
104287
|
];
|
|
103902
104288
|
SHEET_LABELS = {
|
|
103903
104289
|
campaigns: "\u8D26\u6237\u62A5\u544A",
|
|
@@ -103918,7 +104304,7 @@ var init_okki_report_content = __esm({
|
|
|
103918
104304
|
keywords: "google-analysis --sections keywords",
|
|
103919
104305
|
"search-terms": "google-analysis --sections search-terms",
|
|
103920
104306
|
"campaign-device": "\u987B\u62C9 campaign-device\uFF08\u6309\u7CFB\u5217\u62C6\u884C\uFF09\uFF0C\u7981\u6B62\u7528\u8D26\u6237\u7EA7 devices \u4EE3\u66FF",
|
|
103921
|
-
"
|
|
104307
|
+
"geo-targeted": "\u987B\u62C9 geo-targeted\uFF08\u5F53\u524D\u4ECD\u5728\u6295\u653E\u7684\u5730\u7406\u4F4D\u7F6E\uFF09\u3002\u7981\u6B62\u7528 campaign-geo-matched / geographic / campaign-geo\uFF1A\u524D\u8005\u4F1A\u628A\u5DF2\u79FB\u9664\u7684\u56FD\u5BB6\u4E5F\u7B97\u8FDB\u65E5\u671F\u533A\u95F4"
|
|
103922
104308
|
};
|
|
103923
104309
|
}
|
|
103924
104310
|
});
|
|
@@ -104058,7 +104444,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
|
|
|
104058
104444
|
keywords: items2(sectionMap.get("keywords")),
|
|
104059
104445
|
searchTerms: items2(sectionMap.get("search-terms")),
|
|
104060
104446
|
devices: deviceRows2,
|
|
104061
|
-
geo: items2(sectionMap.get("
|
|
104447
|
+
geo: items2(sectionMap.get("geo-targeted"))
|
|
104062
104448
|
},
|
|
104063
104449
|
facts: {
|
|
104064
104450
|
devices: summarizeOkkiDeviceSpend(deviceRows2)
|
|
@@ -104149,9 +104535,9 @@ function sortBySpendDesc(rows) {
|
|
|
104149
104535
|
return [...rows].sort((a, b) => (num6(b.spend) ?? 0) - (num6(a.spend) ?? 0));
|
|
104150
104536
|
}
|
|
104151
104537
|
function prefixLines(items3, firstPrefix) {
|
|
104152
|
-
return items3.map((
|
|
104153
|
-
if (idx === 0 && !
|
|
104154
|
-
return
|
|
104538
|
+
return items3.map((text3, idx) => {
|
|
104539
|
+
if (idx === 0 && !text3.startsWith(firstPrefix)) return `${firstPrefix}${text3}`;
|
|
104540
|
+
return text3;
|
|
104155
104541
|
});
|
|
104156
104542
|
}
|
|
104157
104543
|
function analysisLines(data, key) {
|
|
@@ -104492,9 +104878,9 @@ var init_okki_render_excel = __esm({
|
|
|
104492
104878
|
import fs29 from "fs/promises";
|
|
104493
104879
|
import path34 from "path";
|
|
104494
104880
|
async function readJsonFile2(filePath) {
|
|
104495
|
-
const
|
|
104881
|
+
const text3 = await fs29.readFile(filePath, "utf8");
|
|
104496
104882
|
try {
|
|
104497
|
-
return JSON.parse(
|
|
104883
|
+
return JSON.parse(text3);
|
|
104498
104884
|
} catch {
|
|
104499
104885
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
104500
104886
|
}
|
|
@@ -104716,9 +105102,9 @@ function googlePeriodReportTemplatePath() {
|
|
|
104716
105102
|
return resolveSkillTemplatePath3(TEMPLATE_BASENAME);
|
|
104717
105103
|
}
|
|
104718
105104
|
async function readJsonFile3(filePath) {
|
|
104719
|
-
const
|
|
105105
|
+
const text3 = await fsPromises2.readFile(filePath, "utf8");
|
|
104720
105106
|
try {
|
|
104721
|
-
return JSON.parse(
|
|
105107
|
+
return JSON.parse(text3);
|
|
104722
105108
|
} catch {
|
|
104723
105109
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
104724
105110
|
}
|
|
@@ -104930,10 +105316,10 @@ async function readTaskLog(paths) {
|
|
|
104930
105316
|
const entries = [];
|
|
104931
105317
|
let skipped = 0;
|
|
104932
105318
|
for (const line of raw.split("\n")) {
|
|
104933
|
-
const
|
|
104934
|
-
if (!
|
|
105319
|
+
const text3 = line.trim();
|
|
105320
|
+
if (!text3) continue;
|
|
104935
105321
|
try {
|
|
104936
|
-
const parsed = JSON.parse(
|
|
105322
|
+
const parsed = JSON.parse(text3);
|
|
104937
105323
|
if (!isTaskLogEntry(parsed)) {
|
|
104938
105324
|
skipped += 1;
|
|
104939
105325
|
continue;
|
|
@@ -106389,7 +106775,7 @@ function registerGoogleAnalysisCommands(program2) {
|
|
|
106389
106775
|
"\u6839\u636E Agent \u64B0\u5199\u7684 OKKI \u53D9\u4E8B JSON \u751F\u6210 5 Sheet xlsx\uFF08\u6821\u9A8C\u6BCF Sheet \u5206\u6790 + \u8D26\u6237 Sheet 5 \u7EF4\u6570\u636E\u590D\u76D8\uFF0C\u7F3A\u9879\u62D2\u7EDD\u6E32\u67D3\uFF09"
|
|
106390
106776
|
).requiredOption("--data <file>", "Agent \u4EA7\u51FA\u7684 okki-weekly-report.json").requiredOption(
|
|
106391
106777
|
"--snapshot-dir <dir>",
|
|
106392
|
-
"google-analysis --json-out \u76EE\u5F55\uFF08\u987B\u542B campaigns / keywords / search-terms / campaign-device /
|
|
106778
|
+
"google-analysis --json-out \u76EE\u5F55\uFF08\u987B\u542B campaigns / keywords / search-terms / campaign-device / geo-targeted\uFF09"
|
|
106393
106779
|
).option("--out <file>", "\u8F93\u51FA xlsx \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\u7684 okki-weekly-report.xlsx\uFF09").action(async (opts) => {
|
|
106394
106780
|
await runGoogleAnalysisOkkiRender({
|
|
106395
106781
|
dataFile: opts.data,
|
|
@@ -109493,104 +109879,7 @@ init_cli_json_snapshot();
|
|
|
109493
109879
|
init_auth();
|
|
109494
109880
|
init_list_fetch();
|
|
109495
109881
|
init_login_customer_id();
|
|
109496
|
-
|
|
109497
|
-
// src/commands/ad/_shared.ts
|
|
109498
|
-
init_auth();
|
|
109499
|
-
init_media_customer_id();
|
|
109500
|
-
function resolveAdAccountId(account, label2 = "-a, --account") {
|
|
109501
|
-
try {
|
|
109502
|
-
return requireNumericMediaCustomerId(account, label2);
|
|
109503
|
-
} catch (e) {
|
|
109504
|
-
console.error(`
|
|
109505
|
-
\u274C ${e instanceof Error ? e.message : String(e)}
|
|
109506
|
-
`);
|
|
109507
|
-
process.exit(1);
|
|
109508
|
-
}
|
|
109509
|
-
}
|
|
109510
|
-
function withResolvedAdAccount(opts) {
|
|
109511
|
-
return { ...opts, account: resolveAdAccountId(opts.account) };
|
|
109512
|
-
}
|
|
109513
|
-
async function findItemInList(listUrl, config, id, verbose) {
|
|
109514
|
-
const res = await apiFetch2(listUrl, config, {}, verbose);
|
|
109515
|
-
const item = (res.data ?? []).find((x) => x["id"] === id);
|
|
109516
|
-
if (!item) {
|
|
109517
|
-
throw new Error(`\u672A\u5728\u5217\u8868\u4E2D\u627E\u5230 id="${id}" \u7684\u6761\u76EE`);
|
|
109518
|
-
}
|
|
109519
|
-
return item;
|
|
109520
|
-
}
|
|
109521
|
-
function toGoogleDate(dateStr, offsetDays) {
|
|
109522
|
-
if (dateStr) return dateStr.replace(/-/g, "/");
|
|
109523
|
-
const d = /* @__PURE__ */ new Date();
|
|
109524
|
-
d.setDate(d.getDate() + offsetDays);
|
|
109525
|
-
return d.toISOString().slice(0, 10).replace(/-/g, "/");
|
|
109526
|
-
}
|
|
109527
|
-
function toDisplayMoney(raw) {
|
|
109528
|
-
if (raw == null) return null;
|
|
109529
|
-
const n = Number(raw);
|
|
109530
|
-
if (!Number.isFinite(n)) return null;
|
|
109531
|
-
return n / 100;
|
|
109532
|
-
}
|
|
109533
|
-
function toCentAmount(displayValue) {
|
|
109534
|
-
if (!Number.isFinite(displayValue)) {
|
|
109535
|
-
throw new Error(`toCentAmount: \u8F93\u5165\u5FC5\u987B\u662F\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${displayValue}`);
|
|
109536
|
-
}
|
|
109537
|
-
return Math.round(displayValue * 100);
|
|
109538
|
-
}
|
|
109539
|
-
var CAMPAIGN_BATCH_MONEY_KEYS = /* @__PURE__ */ new Set([
|
|
109540
|
-
"Budget",
|
|
109541
|
-
"MaxCPCAmount",
|
|
109542
|
-
"MaxCpmAmount",
|
|
109543
|
-
"MaxCPVAmount",
|
|
109544
|
-
"TargetCpa_BidingAmount",
|
|
109545
|
-
"TargetSpend_BidCeilingAmount",
|
|
109546
|
-
"TargetCpaAmount",
|
|
109547
|
-
"MaxCPC"
|
|
109548
|
-
]);
|
|
109549
|
-
function convertBatchMoneyTreeFromYuan(value) {
|
|
109550
|
-
return convertBatchMoneyTreeFromYuanInner(value);
|
|
109551
|
-
}
|
|
109552
|
-
function convertBatchMoneyTreeFromYuanInner(value) {
|
|
109553
|
-
if (Array.isArray(value)) {
|
|
109554
|
-
return value.map(convertBatchMoneyTreeFromYuanInner);
|
|
109555
|
-
}
|
|
109556
|
-
if (value && typeof value === "object") {
|
|
109557
|
-
const out = {};
|
|
109558
|
-
for (const [key, val] of Object.entries(value)) {
|
|
109559
|
-
if (typeof val === "number" && CAMPAIGN_BATCH_MONEY_KEYS.has(key)) {
|
|
109560
|
-
out[key] = toCentAmount(val);
|
|
109561
|
-
} else {
|
|
109562
|
-
out[key] = convertBatchMoneyTreeFromYuanInner(val);
|
|
109563
|
-
}
|
|
109564
|
-
}
|
|
109565
|
-
return out;
|
|
109566
|
-
}
|
|
109567
|
-
return value;
|
|
109568
|
-
}
|
|
109569
|
-
function adgroupListUrl(googleApiUrl, account, startDate, endDate, fresh) {
|
|
109570
|
-
const params = new URLSearchParams();
|
|
109571
|
-
params.set("startDate", toGoogleDate(startDate, -30));
|
|
109572
|
-
params.set("endDate", toGoogleDate(endDate, 0));
|
|
109573
|
-
if (fresh) params.set("newest", "true");
|
|
109574
|
-
return `${googleApiUrl}/adgroupnmanagement/v2/list/${account}?${params}`;
|
|
109575
|
-
}
|
|
109576
|
-
function campaignListUrl(googleApiUrl, account, startDate, endDate, fresh) {
|
|
109577
|
-
const params = new URLSearchParams();
|
|
109578
|
-
params.set("startDate", toGoogleDate(startDate, -30));
|
|
109579
|
-
params.set("endDate", toGoogleDate(endDate, 0));
|
|
109580
|
-
if (fresh) params.set("newest", "true");
|
|
109581
|
-
return `${googleApiUrl}/campaignmanagement/v2/list/${account}?${params}`;
|
|
109582
|
-
}
|
|
109583
|
-
function requireGoogleApi(config) {
|
|
109584
|
-
if (!config.googleApiUrl) {
|
|
109585
|
-
console.error(
|
|
109586
|
-
"\n\u274C \u672A\u627E\u5230 Google API \u5730\u5740\u3002\n Google API \u5730\u5740\u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_GOOGLE_API \u8986\u76D6\u3002\n"
|
|
109587
|
-
);
|
|
109588
|
-
process.exit(1);
|
|
109589
|
-
}
|
|
109590
|
-
return config.googleApiUrl;
|
|
109591
|
-
}
|
|
109592
|
-
|
|
109593
|
-
// src/commands/guard/shared.ts
|
|
109882
|
+
init_shared();
|
|
109594
109883
|
init_cli_table();
|
|
109595
109884
|
var GUARD_ACCOUNT_CONCURRENCY = 4;
|
|
109596
109885
|
async function resolveGuardConfig(opts) {
|
|
@@ -113570,6 +113859,9 @@ function register20(program2) {
|
|
|
113570
113859
|
});
|
|
113571
113860
|
}
|
|
113572
113861
|
|
|
113862
|
+
// src/commands/ad/index.ts
|
|
113863
|
+
init_shared();
|
|
113864
|
+
|
|
113573
113865
|
// src/commands/ad/campaign.ts
|
|
113574
113866
|
init_auth();
|
|
113575
113867
|
init_cli_json_snapshot();
|
|
@@ -113589,6 +113881,9 @@ function ensureIConfirm(opts) {
|
|
|
113589
113881
|
process.exit(1);
|
|
113590
113882
|
}
|
|
113591
113883
|
|
|
113884
|
+
// src/commands/ad/campaign.ts
|
|
113885
|
+
init_shared();
|
|
113886
|
+
|
|
113592
113887
|
// src/commands/ad/campaign-create-validate.ts
|
|
113593
113888
|
init_media_customer_id();
|
|
113594
113889
|
|
|
@@ -113826,27 +114121,27 @@ function validateCalloutProperties(prefix, rec, errors, _warnings, lengthViolati
|
|
|
113826
114121
|
);
|
|
113827
114122
|
return;
|
|
113828
114123
|
}
|
|
113829
|
-
const
|
|
113830
|
-
if (typeof
|
|
114124
|
+
const text3 = raw["Text"];
|
|
114125
|
+
if (typeof text3 !== "string" || !text3.trim()) {
|
|
113831
114126
|
pushErr(
|
|
113832
114127
|
errors,
|
|
113833
114128
|
`${prefix}.Properties.Text \u4E0D\u80FD\u4E3A\u7A7A\uFF08CALLOUT \u5FC5\u586B\uFF0C\u540E\u7AEF CreateCalloutFeedItem \u8BFB\u53D6 Properties["Text"]\uFF09`
|
|
113834
114129
|
);
|
|
113835
114130
|
return;
|
|
113836
114131
|
}
|
|
113837
|
-
if (
|
|
114132
|
+
if (text3.length > CALLOUT_TEXT_MAX_LEN) {
|
|
113838
114133
|
pushLengthViolation(lengthViolations, {
|
|
113839
114134
|
path: `${prefix}.Properties.Text`,
|
|
113840
114135
|
field: "Text",
|
|
113841
114136
|
kind: "callout_text",
|
|
113842
114137
|
limit: CALLOUT_TEXT_MAX_LEN,
|
|
113843
|
-
actual:
|
|
114138
|
+
actual: text3.length,
|
|
113844
114139
|
countMode: "ascii",
|
|
113845
|
-
text:
|
|
114140
|
+
text: text3
|
|
113846
114141
|
});
|
|
113847
114142
|
pushErr(
|
|
113848
114143
|
errors,
|
|
113849
|
-
`${prefix}.Properties.Text \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${
|
|
114144
|
+
`${prefix}.Properties.Text \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${text3.length}\uFF0CGoogle \u786C\u7EA6\u675F\uFF09\uFF1A"${text3}"`
|
|
113850
114145
|
);
|
|
113851
114146
|
}
|
|
113852
114147
|
}
|
|
@@ -113958,6 +114253,7 @@ import { readFileSync as readFileSync4 } from "fs";
|
|
|
113958
114253
|
init_cli_json_snapshot();
|
|
113959
114254
|
init_strip_legacy_google_fields();
|
|
113960
114255
|
init_cli_table();
|
|
114256
|
+
init_shared();
|
|
113961
114257
|
|
|
113962
114258
|
// src/commands/ad/search-field-patch.ts
|
|
113963
114259
|
function buildSearchFieldPatch(pairs) {
|
|
@@ -114135,8 +114431,8 @@ function judgeBudgetAfterFailedPut(input) {
|
|
|
114135
114431
|
}
|
|
114136
114432
|
return { kind: "unchanged" };
|
|
114137
114433
|
}
|
|
114138
|
-
function coreKeyword(
|
|
114139
|
-
const t =
|
|
114434
|
+
function coreKeyword(text3) {
|
|
114435
|
+
const t = text3.trim();
|
|
114140
114436
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("[") && t.endsWith("]"))) {
|
|
114141
114437
|
return t.slice(1, -1).trim();
|
|
114142
114438
|
}
|
|
@@ -114179,8 +114475,8 @@ function summarizeNegativeKeywordCreate(requested, response, listItems) {
|
|
|
114179
114475
|
const pools = listItems == null ? responseRecords : [...responseRecords, ...listItems];
|
|
114180
114476
|
const matched = [];
|
|
114181
114477
|
const pending = [];
|
|
114182
|
-
for (const
|
|
114183
|
-
const core = coreKeyword(
|
|
114478
|
+
for (const text3 of requested) {
|
|
114479
|
+
const core = coreKeyword(text3);
|
|
114184
114480
|
const hit = pools.find((item) => {
|
|
114185
114481
|
const cores = [
|
|
114186
114482
|
...collectKeywordCores(item["keywordText"]),
|
|
@@ -114190,11 +114486,11 @@ function summarizeNegativeKeywordCreate(requested, response, listItems) {
|
|
|
114190
114486
|
return cores.includes(core);
|
|
114191
114487
|
});
|
|
114192
114488
|
if (!hit) {
|
|
114193
|
-
pending.push(
|
|
114489
|
+
pending.push(text3);
|
|
114194
114490
|
continue;
|
|
114195
114491
|
}
|
|
114196
114492
|
const idRaw = hit["id"] ?? hit["Id"];
|
|
114197
|
-
matched.push({ text:
|
|
114493
|
+
matched.push({ text: text3, id: typeof idRaw === "string" ? idRaw : void 0 });
|
|
114198
114494
|
}
|
|
114199
114495
|
let verification;
|
|
114200
114496
|
if (requested.length > 0 && matched.length === requested.length) verification = "verified";
|
|
@@ -114910,8 +115206,8 @@ async function runAdNegativeKeywordDelete(opts) {
|
|
|
114910
115206
|
|
|
114911
115207
|
// src/commands/ad/campaign-keywords.ts
|
|
114912
115208
|
var GOOGLE_KEYWORD_MAX_CORE_LENGTH = 80;
|
|
114913
|
-
function collapseDuplicateSpacesInKeywordText(
|
|
114914
|
-
return
|
|
115209
|
+
function collapseDuplicateSpacesInKeywordText(text3) {
|
|
115210
|
+
return text3.replace(/\s{2,}/g, " ");
|
|
114915
115211
|
}
|
|
114916
115212
|
var VALID_CORE_REGEX = /^[\p{L}\p{N}\s.\-]+$/u;
|
|
114917
115213
|
function matchTypeV2ToUi(raw) {
|
|
@@ -114936,8 +115232,8 @@ function matchTypeUiToV2(ui) {
|
|
|
114936
115232
|
}
|
|
114937
115233
|
}
|
|
114938
115234
|
}
|
|
114939
|
-
function inferMatchTypeFromDisplayText(
|
|
114940
|
-
const t =
|
|
115235
|
+
function inferMatchTypeFromDisplayText(text3) {
|
|
115236
|
+
const t = text3.trim();
|
|
114941
115237
|
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return "Phrase";
|
|
114942
115238
|
if (t.length >= 2 && t.startsWith("[") && t.endsWith("]")) return "Exact";
|
|
114943
115239
|
return "Broad";
|
|
@@ -115475,9 +115771,9 @@ var POLICY_RISK_RULES = [
|
|
|
115475
115771
|
{ re: /\b(alcohol|whisk(e)?y|vodka|liquor)\b/i, label: "\u9152\u7CBE\uFF08\u5730\u57DF\u9650\u5236\uFF09" },
|
|
115476
115772
|
{ re: /(最好|第一|国家级|绝对|100%)/, label: "\u5E7F\u544A\u6CD5\u7EDD\u5BF9\u5316\u7528\u8BED" }
|
|
115477
115773
|
];
|
|
115478
|
-
function matchRisk(
|
|
115774
|
+
function matchRisk(text3) {
|
|
115479
115775
|
for (const r of POLICY_RISK_RULES) {
|
|
115480
|
-
if (r.re.test(
|
|
115776
|
+
if (r.re.test(text3)) return r.label;
|
|
115481
115777
|
}
|
|
115482
115778
|
return void 0;
|
|
115483
115779
|
}
|
|
@@ -115500,10 +115796,10 @@ function warnPolicyRiskTerms(campaign, warnings) {
|
|
|
115500
115796
|
const groups = campaign["AdGroupsForBatchJob"];
|
|
115501
115797
|
if (!Array.isArray(groups)) return;
|
|
115502
115798
|
const hitsByLabel = /* @__PURE__ */ new Map();
|
|
115503
|
-
const add = (label2,
|
|
115799
|
+
const add = (label2, text3) => {
|
|
115504
115800
|
let set = hitsByLabel.get(label2);
|
|
115505
115801
|
if (!set) hitsByLabel.set(label2, set = /* @__PURE__ */ new Set());
|
|
115506
|
-
set.add(
|
|
115802
|
+
set.add(text3.trim());
|
|
115507
115803
|
};
|
|
115508
115804
|
for (const g of groups) {
|
|
115509
115805
|
const gr = g;
|
|
@@ -115539,8 +115835,8 @@ function warnPolicyRiskTerms(campaign, warnings) {
|
|
|
115539
115835
|
}
|
|
115540
115836
|
|
|
115541
115837
|
// src/commands/ad/campaign-rsa.ts
|
|
115542
|
-
function normalizeRsaAssetKey(
|
|
115543
|
-
return
|
|
115838
|
+
function normalizeRsaAssetKey(text3) {
|
|
115839
|
+
return text3.trim().replace(/\s+/g, " ").toLowerCase();
|
|
115544
115840
|
}
|
|
115545
115841
|
function listRsaHeadlines(ad) {
|
|
115546
115842
|
const parts = [
|
|
@@ -115708,9 +116004,9 @@ function validateLocationsFidelity(cfg, campaign, errors) {
|
|
|
115708
116004
|
}
|
|
115709
116005
|
}
|
|
115710
116006
|
}
|
|
115711
|
-
function calcGoogleCharLength(
|
|
116007
|
+
function calcGoogleCharLength(text3) {
|
|
115712
116008
|
let len = 0;
|
|
115713
|
-
for (const ch of
|
|
116009
|
+
for (const ch of text3) {
|
|
115714
116010
|
const code = ch.codePointAt(0) ?? 0;
|
|
115715
116011
|
if (code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 131072 && code <= 173791 || code >= 12288 && code <= 12351 || code >= 65280 && code <= 65519) {
|
|
115716
116012
|
len += 2;
|
|
@@ -116477,8 +116773,8 @@ async function reportFailedCampaignPut(opts) {
|
|
|
116477
116773
|
async function reportCampaignWrite(opts) {
|
|
116478
116774
|
const nextQuery = `siluzan-tso ad campaigns -a ${opts.account} --json-out ./snap`;
|
|
116479
116775
|
const unmatched = describeUnmatchedChecks(opts.checks);
|
|
116480
|
-
const
|
|
116481
|
-
const headline = writeVerificationHeadline(opts.verification,
|
|
116776
|
+
const text3 = opts.verification === "verified" ? opts.detail : unmatched || opts.detail;
|
|
116777
|
+
const headline = writeVerificationHeadline(opts.verification, text3);
|
|
116482
116778
|
if (opts.verification !== "verified") {
|
|
116483
116779
|
console.error(`
|
|
116484
116780
|
${headline}
|
|
@@ -116981,6 +117277,7 @@ init_auth();
|
|
|
116981
117277
|
init_cli_json_snapshot();
|
|
116982
117278
|
init_strip_legacy_google_fields();
|
|
116983
117279
|
init_cli_table();
|
|
117280
|
+
init_shared();
|
|
116984
117281
|
async function runAdGroups(opts) {
|
|
116985
117282
|
opts = withResolvedAdAccount(opts);
|
|
116986
117283
|
const config = loadConfig(opts.token);
|
|
@@ -117241,6 +117538,7 @@ init_auth();
|
|
|
117241
117538
|
init_cli_json_snapshot();
|
|
117242
117539
|
init_strip_legacy_google_fields();
|
|
117243
117540
|
init_cli_table();
|
|
117541
|
+
init_shared();
|
|
117244
117542
|
|
|
117245
117543
|
// src/commands/ad/rsa-cli-validate.ts
|
|
117246
117544
|
var AD_CLI_MIN_HEADLINES = 3;
|
|
@@ -117566,6 +117864,7 @@ init_auth();
|
|
|
117566
117864
|
import { readFileSync as readFileSync8 } from "fs";
|
|
117567
117865
|
init_cli_json_snapshot();
|
|
117568
117866
|
init_strip_legacy_google_fields();
|
|
117867
|
+
init_shared();
|
|
117569
117868
|
|
|
117570
117869
|
// src/commands/ad/extension-lead-form.ts
|
|
117571
117870
|
import { readFileSync as readFileSync6 } from "fs";
|
|
@@ -118253,6 +118552,7 @@ init_auth();
|
|
|
118253
118552
|
init_cli_json_snapshot();
|
|
118254
118553
|
init_strip_legacy_google_fields();
|
|
118255
118554
|
init_cli_table();
|
|
118555
|
+
init_shared();
|
|
118256
118556
|
async function runAdSearchTerms(opts) {
|
|
118257
118557
|
opts = withResolvedAdAccount(opts);
|
|
118258
118558
|
const config = loadConfig(opts.token);
|
|
@@ -118339,11 +118639,13 @@ init_auth();
|
|
|
118339
118639
|
import { readFileSync as readFileSync9 } from "fs";
|
|
118340
118640
|
init_cli_json_snapshot();
|
|
118341
118641
|
init_strip_legacy_google_fields();
|
|
118642
|
+
init_shared();
|
|
118342
118643
|
|
|
118343
118644
|
// src/commands/ad/device-bid.ts
|
|
118344
118645
|
init_auth();
|
|
118345
118646
|
init_cli_json_snapshot();
|
|
118346
118647
|
init_bid_modifier_display();
|
|
118648
|
+
init_shared();
|
|
118347
118649
|
init_bid_modifier_display();
|
|
118348
118650
|
var CAMPAIGN_ZERO_AMBIGUOUS_DISPLAY = "\u2014 \u6216 -100%\uFF08\u7F51\u5173\u4E0D\u533A\u5206\uFF0C\u9700\u5728 Google Ads \u540E\u53F0\u786E\u8BA4\uFF09";
|
|
118349
118651
|
function multiplierToAdGroupBidPercent(multiplier) {
|
|
@@ -119137,6 +119439,7 @@ init_cli_table();
|
|
|
119137
119439
|
// src/commands/ad/campaign-batch-diff.ts
|
|
119138
119440
|
init_auth();
|
|
119139
119441
|
init_cli_json_snapshot();
|
|
119442
|
+
init_shared();
|
|
119140
119443
|
import fs9 from "fs";
|
|
119141
119444
|
import path14 from "path";
|
|
119142
119445
|
|
|
@@ -119170,14 +119473,14 @@ function buildExtensionRemediateCommandLine(opts) {
|
|
|
119170
119473
|
const campaignFlag = level === "Campaign" ? `--campaign-id ${campaignId}` : "";
|
|
119171
119474
|
const base = ["siluzan-tso", "ad", "extension"];
|
|
119172
119475
|
if (type === "SITELINK") {
|
|
119173
|
-
const
|
|
119476
|
+
const text3 = pickString(props["Text"], props["LinkText"]);
|
|
119174
119477
|
const url = pickString(props["DestinationUrl"]);
|
|
119175
|
-
if (!
|
|
119478
|
+
if (!text3 || !url) return null;
|
|
119176
119479
|
const parts = [
|
|
119177
119480
|
...base,
|
|
119178
119481
|
"sitelink",
|
|
119179
119482
|
`-a ${accountId}`,
|
|
119180
|
-
`--text ${shellArg(
|
|
119483
|
+
`--text ${shellArg(text3)}`,
|
|
119181
119484
|
`--url ${shellArg(url)}`
|
|
119182
119485
|
];
|
|
119183
119486
|
const line2 = pickString(props["Line2"], props["Description1"]);
|
|
@@ -119191,9 +119494,9 @@ function buildExtensionRemediateCommandLine(opts) {
|
|
|
119191
119494
|
return parts.join(" ");
|
|
119192
119495
|
}
|
|
119193
119496
|
if (type === "CALLOUT") {
|
|
119194
|
-
const
|
|
119195
|
-
if (!
|
|
119196
|
-
const parts = [...base, "callout", `-a ${accountId}`, `--text ${shellArg(
|
|
119497
|
+
const text3 = pickString(props["Text"], props["CalloutText"]);
|
|
119498
|
+
if (!text3) return null;
|
|
119499
|
+
const parts = [...base, "callout", `-a ${accountId}`, `--text ${shellArg(text3)}`, levelFlag];
|
|
119197
119500
|
if (campaignFlag) parts.push(campaignFlag);
|
|
119198
119501
|
parts.push(`--json-out ${jsonOut}`);
|
|
119199
119502
|
parts.push(`--commit ${shellArg("batch-diff remediate extension")}`);
|
|
@@ -119353,11 +119656,11 @@ function buildBatchOperationSlots(cfg) {
|
|
|
119353
119656
|
return;
|
|
119354
119657
|
}
|
|
119355
119658
|
pickArray(block, "Items", "items").forEach((it, ii) => {
|
|
119356
|
-
const
|
|
119659
|
+
const text3 = pickText(asRecord3(it), "Text", "text");
|
|
119357
119660
|
push(
|
|
119358
119661
|
"ad_group_criterion",
|
|
119359
119662
|
`${groupPath}.KeywordsForBatchJob[${bi}].Items[${ii}]`,
|
|
119360
|
-
`\u5173\u952E\u8BCD\u300C${
|
|
119663
|
+
`\u5173\u952E\u8BCD\u300C${text3}\u300D\uFF08\u7EC4\u300C${groupName}\u300D\uFF09`
|
|
119361
119664
|
);
|
|
119362
119665
|
});
|
|
119363
119666
|
});
|
|
@@ -119390,9 +119693,9 @@ function buildSubmittedOperationSlots(cfg) {
|
|
|
119390
119693
|
return buildBatchOperationSlots(clone);
|
|
119391
119694
|
}
|
|
119392
119695
|
var OP_RE = /mutate_operations\[(\d+)\]\.([a-z_]+?)_operation\.([a-z_.]+)/;
|
|
119393
|
-
function parseBatchOperationErrors(
|
|
119696
|
+
function parseBatchOperationErrors(text3) {
|
|
119394
119697
|
const out = [];
|
|
119395
|
-
for (const seg of
|
|
119698
|
+
for (const seg of text3.split(/Processing error:\s*/).slice(1)) {
|
|
119396
119699
|
const m = OP_RE.exec(seg);
|
|
119397
119700
|
if (!m) continue;
|
|
119398
119701
|
const head = seg.slice(0, m.index);
|
|
@@ -119549,8 +119852,8 @@ function pickLiveAdForPlannedRsa(plannedHeadlines, primary, unmatchedLiveAds) {
|
|
|
119549
119852
|
const [picked] = unmatchedLiveAds.splice(bestIdx, 1);
|
|
119550
119853
|
return picked ?? null;
|
|
119551
119854
|
}
|
|
119552
|
-
function livePoolHasText(pool,
|
|
119553
|
-
const t =
|
|
119855
|
+
function livePoolHasText(pool, text3) {
|
|
119856
|
+
const t = text3.trim().toLowerCase();
|
|
119554
119857
|
return t.length > 0 && pool.has(t);
|
|
119555
119858
|
}
|
|
119556
119859
|
function listPlannedRsaAssets(ad, groupPath, adIndex, adGroupName) {
|
|
@@ -120436,8 +120739,8 @@ function printPlanItemsByAdGroup(configFile, layer, layerItems) {
|
|
|
120436
120739
|
}
|
|
120437
120740
|
}
|
|
120438
120741
|
}
|
|
120439
|
-
function mdCell(
|
|
120440
|
-
return
|
|
120742
|
+
function mdCell(text3) {
|
|
120743
|
+
return text3.replace(/\r?\n/g, " ").replace(/\|/g, "\uFF5C").trim();
|
|
120441
120744
|
}
|
|
120442
120745
|
function statusLabel(status) {
|
|
120443
120746
|
if (status === "ok") return "\u2705 \u5DF2\u521B\u5EFA";
|
|
@@ -120764,6 +121067,7 @@ async function runCampaignBatchDiff(opts) {
|
|
|
120764
121067
|
}
|
|
120765
121068
|
|
|
120766
121069
|
// src/commands/ad/ai-creation.ts
|
|
121070
|
+
init_shared();
|
|
120767
121071
|
async function runAiCreationList(opts) {
|
|
120768
121072
|
const config = loadConfig(opts.token);
|
|
120769
121073
|
const params = new URLSearchParams();
|
|
@@ -121179,6 +121483,7 @@ async function runAiCreationUpdate(opts) {
|
|
|
121179
121483
|
// src/commands/ad/pmax-create.ts
|
|
121180
121484
|
init_auth();
|
|
121181
121485
|
init_cli_json_snapshot();
|
|
121486
|
+
init_shared();
|
|
121182
121487
|
|
|
121183
121488
|
// src/commands/ad/pmax-create-validate.ts
|
|
121184
121489
|
var VALID_PMAX_BIDDING_STRATEGIES = [
|
|
@@ -121266,8 +121571,8 @@ function normalizeBidding(raw) {
|
|
|
121266
121571
|
return byNum[n] ?? null;
|
|
121267
121572
|
}
|
|
121268
121573
|
function validateTextLengths(errors, lengthViolations, texts, arrayField, kind, limit, label2) {
|
|
121269
|
-
texts.forEach((
|
|
121270
|
-
const len = calcGoogleCharLength(
|
|
121574
|
+
texts.forEach((text3, i) => {
|
|
121575
|
+
const len = calcGoogleCharLength(text3);
|
|
121271
121576
|
if (len > limit) {
|
|
121272
121577
|
const field = `${arrayField}[${i}]`;
|
|
121273
121578
|
pushLengthViolation(lengthViolations, {
|
|
@@ -121277,9 +121582,9 @@ function validateTextLengths(errors, lengthViolations, texts, arrayField, kind,
|
|
|
121277
121582
|
limit,
|
|
121278
121583
|
actual: len,
|
|
121279
121584
|
countMode: "google",
|
|
121280
|
-
text:
|
|
121585
|
+
text: text3
|
|
121281
121586
|
});
|
|
121282
|
-
pushErr3(errors, `${label2}[${i}] \u8D85\u8FC7 ${limit} \u5B57\u7B26\uFF08\u5F53\u524D ${len}\uFF0CCJK \u8BA1 2\uFF09\uFF1A"${
|
|
121587
|
+
pushErr3(errors, `${label2}[${i}] \u8D85\u8FC7 ${limit} \u5B57\u7B26\uFF08\u5F53\u524D ${len}\uFF0CCJK \u8BA1 2\uFF09\uFF1A"${text3}"`);
|
|
121283
121588
|
}
|
|
121284
121589
|
});
|
|
121285
121590
|
}
|
|
@@ -121801,14 +122106,14 @@ async function uploadPmaxImageFileMultipart(config, googleApiUrl, accountId, abs
|
|
|
121801
122106
|
if (config.apiKey) headers["x-api-key"] = config.apiKey;
|
|
121802
122107
|
else headers.Authorization = `Bearer ${config.authToken}`;
|
|
121803
122108
|
const res = await fetch(url, { method: "POST", headers, body: form });
|
|
121804
|
-
const
|
|
122109
|
+
const text3 = await res.text();
|
|
121805
122110
|
if (!res.ok) {
|
|
121806
|
-
const detail = verbose ? `\uFF1A${
|
|
122111
|
+
const detail = verbose ? `\uFF1A${text3.slice(0, 300)}` : "";
|
|
121807
122112
|
throw new Error(`\u4E0A\u4F20\u56FE\u7247\u8D44\u4EA7 HTTP ${res.status}${detail}\uFF08${absImagePath}\uFF09`);
|
|
121808
122113
|
}
|
|
121809
122114
|
let data;
|
|
121810
122115
|
try {
|
|
121811
|
-
data = JSON.parse(
|
|
122116
|
+
data = JSON.parse(text3);
|
|
121812
122117
|
} catch {
|
|
121813
122118
|
throw new Error(`\u4E0A\u4F20\u56FE\u7247\u8D44\u4EA7\u54CD\u5E94\u975E JSON\uFF08${absImagePath}\uFF09`);
|
|
121814
122119
|
}
|
|
@@ -121943,6 +122248,7 @@ function assertPmaxImageSlotsResolved(slots, requiredKinds = ["marketing", "squa
|
|
|
121943
122248
|
|
|
121944
122249
|
// src/commands/ad/pmax-load.ts
|
|
121945
122250
|
import { readFileSync as readFileSync11 } from "fs";
|
|
122251
|
+
init_shared();
|
|
121946
122252
|
|
|
121947
122253
|
// src/commands/ad/pmax-campaign-extensions.ts
|
|
121948
122254
|
init_auth();
|
|
@@ -121969,19 +122275,19 @@ function validatePmaxSitelinkSpec(link, prefix, errors, warnings) {
|
|
|
121969
122275
|
errors.push(`${prefix} \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
121970
122276
|
return;
|
|
121971
122277
|
}
|
|
121972
|
-
const
|
|
122278
|
+
const text3 = link.text?.trim();
|
|
121973
122279
|
const url = link.destinationUrl?.trim();
|
|
121974
|
-
if (!
|
|
122280
|
+
if (!text3) errors.push(`${prefix}.text \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
121975
122281
|
if (!url) {
|
|
121976
122282
|
errors.push(`${prefix}.destinationUrl \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
121977
122283
|
} else if (!/^https?:\/\/.+/i.test(url)) {
|
|
121978
122284
|
errors.push(`${prefix}.destinationUrl \u683C\u5F0F\u4E0D\u6B63\u786E\uFF1A${url}`);
|
|
121979
122285
|
}
|
|
121980
|
-
if (
|
|
122286
|
+
if (text3 && url) {
|
|
121981
122287
|
validateSitelinkProperties(
|
|
121982
122288
|
prefix,
|
|
121983
122289
|
{
|
|
121984
|
-
Text:
|
|
122290
|
+
Text: text3,
|
|
121985
122291
|
DestinationUrl: url,
|
|
121986
122292
|
Line2: link.line2?.trim() ?? "",
|
|
121987
122293
|
Line3: link.line3?.trim() ?? ""
|
|
@@ -122032,16 +122338,16 @@ function convertExtensionsForBatchJobToCampaignExtensions(items3) {
|
|
|
122032
122338
|
const type = String(ext.typeV2 ?? ext.TypeV2 ?? ext.AssetFieldType ?? "").toUpperCase();
|
|
122033
122339
|
const props = ext.Properties ?? {};
|
|
122034
122340
|
if (type === "CALLOUT") {
|
|
122035
|
-
const
|
|
122036
|
-
if (
|
|
122341
|
+
const text3 = String(props.Text ?? props.CalloutText ?? "").trim();
|
|
122342
|
+
if (text3) config.callouts.push(text3);
|
|
122037
122343
|
continue;
|
|
122038
122344
|
}
|
|
122039
122345
|
if (type === "SITELINK") {
|
|
122040
|
-
const
|
|
122346
|
+
const text3 = String(props.Text ?? props.LinkText ?? "").trim();
|
|
122041
122347
|
const destinationUrl = String(props.DestinationUrl ?? "").trim();
|
|
122042
|
-
if (
|
|
122348
|
+
if (text3 && destinationUrl) {
|
|
122043
122349
|
config.sitelinks.push({
|
|
122044
|
-
text:
|
|
122350
|
+
text: text3,
|
|
122045
122351
|
destinationUrl,
|
|
122046
122352
|
line2: String(props.Line2 ?? props.Description1 ?? "").trim() || void 0,
|
|
122047
122353
|
line3: String(props.Line3 ?? props.Description2 ?? "").trim() || void 0
|
|
@@ -122110,14 +122416,14 @@ function validatePmaxCampaignExtensions(ext, opts) {
|
|
|
122110
122416
|
}
|
|
122111
122417
|
const callouts = ext.callouts ?? [];
|
|
122112
122418
|
for (let i = 0; i < callouts.length; i++) {
|
|
122113
|
-
const
|
|
122114
|
-
if (!
|
|
122419
|
+
const text3 = callouts[i]?.trim();
|
|
122420
|
+
if (!text3) {
|
|
122115
122421
|
errors.push(`campaignExtensions.callouts[${i}] \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
122116
122422
|
continue;
|
|
122117
122423
|
}
|
|
122118
|
-
if (
|
|
122424
|
+
if (text3.length > CALLOUT_TEXT_MAX_LEN) {
|
|
122119
122425
|
errors.push(
|
|
122120
|
-
`campaignExtensions.callouts[${i}] \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${
|
|
122426
|
+
`campaignExtensions.callouts[${i}] \u8D85\u8FC7 ${CALLOUT_TEXT_MAX_LEN} \u5B57\u7B26\uFF08\u5F53\u524D ${text3.length}\uFF09\uFF1A"${text3}"`
|
|
122121
122427
|
);
|
|
122122
122428
|
}
|
|
122123
122429
|
}
|
|
@@ -122190,14 +122496,14 @@ async function postExtension(config, googleApiUrl, accountId, body, verbose) {
|
|
|
122190
122496
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
122191
122497
|
}
|
|
122192
122498
|
}
|
|
122193
|
-
function buildCalloutBody(accountId, campaignId,
|
|
122499
|
+
function buildCalloutBody(accountId, campaignId, text3) {
|
|
122194
122500
|
return {
|
|
122195
122501
|
activeuseridg: accountId,
|
|
122196
122502
|
campaignId,
|
|
122197
122503
|
level: "Campaign",
|
|
122198
122504
|
typeV2: "CALLOUT",
|
|
122199
122505
|
assetFieldType: "CALLOUT",
|
|
122200
|
-
properties: { Text:
|
|
122506
|
+
properties: { Text: text3.trim() }
|
|
122201
122507
|
};
|
|
122202
122508
|
}
|
|
122203
122509
|
function buildSnippetBody(accountId, campaignId, header, values) {
|
|
@@ -122214,8 +122520,8 @@ function buildSnippetBody(accountId, campaignId, header, values) {
|
|
|
122214
122520
|
};
|
|
122215
122521
|
}
|
|
122216
122522
|
function buildSitelinkBody(accountId, campaignId, link) {
|
|
122217
|
-
const
|
|
122218
|
-
const line2 = link.line2?.trim() ||
|
|
122523
|
+
const text3 = link.text.trim();
|
|
122524
|
+
const line2 = link.line2?.trim() || text3;
|
|
122219
122525
|
const line3 = link.line3?.trim() || line2;
|
|
122220
122526
|
return {
|
|
122221
122527
|
activeuseridg: accountId,
|
|
@@ -122224,7 +122530,7 @@ function buildSitelinkBody(accountId, campaignId, link) {
|
|
|
122224
122530
|
typeV2: "SITELINK",
|
|
122225
122531
|
assetFieldType: "SITELINK",
|
|
122226
122532
|
properties: {
|
|
122227
|
-
Text:
|
|
122533
|
+
Text: text3,
|
|
122228
122534
|
Line2: line2,
|
|
122229
122535
|
Line3: line3,
|
|
122230
122536
|
DestinationUrl: link.destinationUrl.trim()
|
|
@@ -122252,26 +122558,26 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
122252
122558
|
allOk: true
|
|
122253
122559
|
};
|
|
122254
122560
|
for (const raw of ext.callouts ?? []) {
|
|
122255
|
-
const
|
|
122256
|
-
if (!
|
|
122561
|
+
const text3 = raw?.trim();
|
|
122562
|
+
if (!text3) continue;
|
|
122257
122563
|
if (opts.logProgress) console.log(`
|
|
122258
|
-
\u6302\u8F7D\u5BA3\u4F20\u4FE1\u606F\uFF1A${
|
|
122564
|
+
\u6302\u8F7D\u5BA3\u4F20\u4FE1\u606F\uFF1A${text3}`);
|
|
122259
122565
|
const posted = await postExtension(
|
|
122260
122566
|
opts.config,
|
|
122261
122567
|
opts.googleApiUrl,
|
|
122262
122568
|
opts.accountId,
|
|
122263
|
-
buildCalloutBody(opts.accountId, opts.campaignId,
|
|
122569
|
+
buildCalloutBody(opts.accountId, opts.campaignId, text3),
|
|
122264
122570
|
opts.verbose
|
|
122265
122571
|
);
|
|
122266
122572
|
if (posted.ok) {
|
|
122267
122573
|
result.callouts.push({
|
|
122268
122574
|
ok: true,
|
|
122269
122575
|
id: String(posted.data["id"] ?? ""),
|
|
122270
|
-
label:
|
|
122576
|
+
label: text3
|
|
122271
122577
|
});
|
|
122272
122578
|
} else {
|
|
122273
122579
|
result.allOk = false;
|
|
122274
|
-
result.callouts.push({ ok: false, error: posted.error, label:
|
|
122580
|
+
result.callouts.push({ ok: false, error: posted.error, label: text3 });
|
|
122275
122581
|
}
|
|
122276
122582
|
}
|
|
122277
122583
|
for (const s of ext.structuredSnippets ?? []) {
|
|
@@ -122300,11 +122606,11 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
122300
122606
|
}
|
|
122301
122607
|
}
|
|
122302
122608
|
for (const link of ext.sitelinks ?? []) {
|
|
122303
|
-
const
|
|
122609
|
+
const text3 = link?.text?.trim();
|
|
122304
122610
|
const url = link?.destinationUrl?.trim();
|
|
122305
|
-
if (!
|
|
122611
|
+
if (!text3 || !url) continue;
|
|
122306
122612
|
if (opts.logProgress) console.log(`
|
|
122307
|
-
\u6302\u8F7D\u7AD9\u5185\u94FE\u63A5\uFF1A${
|
|
122613
|
+
\u6302\u8F7D\u7AD9\u5185\u94FE\u63A5\uFF1A${text3} \u2192 ${url}`);
|
|
122308
122614
|
const posted = await postExtension(
|
|
122309
122615
|
opts.config,
|
|
122310
122616
|
opts.googleApiUrl,
|
|
@@ -122316,11 +122622,11 @@ async function attachPmaxCampaignExtensions(opts) {
|
|
|
122316
122622
|
result.sitelinks.push({
|
|
122317
122623
|
ok: true,
|
|
122318
122624
|
id: String(posted.data["id"] ?? ""),
|
|
122319
|
-
label:
|
|
122625
|
+
label: text3
|
|
122320
122626
|
});
|
|
122321
122627
|
} else {
|
|
122322
122628
|
result.allOk = false;
|
|
122323
|
-
result.sitelinks.push({ ok: false, error: posted.error, label:
|
|
122629
|
+
result.sitelinks.push({ ok: false, error: posted.error, label: text3 });
|
|
122324
122630
|
}
|
|
122325
122631
|
}
|
|
122326
122632
|
if (ext.leadForm) {
|
|
@@ -122573,6 +122879,7 @@ init_auth();
|
|
|
122573
122879
|
init_cli_json_snapshot();
|
|
122574
122880
|
import { readFileSync as readFileSync12 } from "fs";
|
|
122575
122881
|
import { dirname as dirname9, isAbsolute as isAbsolute4, resolve as resolve8 } from "path";
|
|
122882
|
+
init_shared();
|
|
122576
122883
|
var PMAX_MONEY_KEYS = /* @__PURE__ */ new Set(["budget", "targetCpa_BidingAmount"]);
|
|
122577
122884
|
function loadPmaxJsonFile(configFile) {
|
|
122578
122885
|
let raw;
|
|
@@ -122784,13 +123091,13 @@ function runPmaxVideoValidation(configFile, cfg) {
|
|
|
122784
123091
|
async function fetchVideoUploadStatus(config, googleApiUrl, mediaAccountId, resourceName, verbose) {
|
|
122785
123092
|
const url = pyapiVideoStatusUrl(googleApiUrl, mediaAccountId, resourceName);
|
|
122786
123093
|
const res = await fetch(url, { method: "GET", headers: authHeaders(config) });
|
|
122787
|
-
const
|
|
123094
|
+
const text3 = await res.text();
|
|
122788
123095
|
if (!res.ok) {
|
|
122789
|
-
const detail = verbose ? `\uFF1A${
|
|
123096
|
+
const detail = verbose ? `\uFF1A${text3.slice(0, 300)}` : "";
|
|
122790
123097
|
throw new Error(`\u67E5\u8BE2\u89C6\u9891\u5904\u7406\u72B6\u6001 HTTP ${res.status}${detail}`);
|
|
122791
123098
|
}
|
|
122792
123099
|
try {
|
|
122793
|
-
return JSON.parse(
|
|
123100
|
+
return JSON.parse(text3);
|
|
122794
123101
|
} catch {
|
|
122795
123102
|
throw new Error("\u67E5\u8BE2\u89C6\u9891\u5904\u7406\u72B6\u6001\u54CD\u5E94\u975E JSON");
|
|
122796
123103
|
}
|
|
@@ -122846,14 +123153,14 @@ async function uploadPmaxLocalVideo(opts) {
|
|
|
122846
123153
|
);
|
|
122847
123154
|
const url = pyapiVideoUploadUrl(opts.googleApiUrl);
|
|
122848
123155
|
const res = await fetch(url, { method: "POST", headers: authHeaders(opts.config), body: form });
|
|
122849
|
-
const
|
|
123156
|
+
const text3 = await res.text();
|
|
122850
123157
|
if (!res.ok) {
|
|
122851
|
-
const detail = opts.verbose ? `\uFF1A${
|
|
123158
|
+
const detail = opts.verbose ? `\uFF1A${text3.slice(0, 400)}` : "";
|
|
122852
123159
|
throw new Error(`\u4E0A\u4F20\u89C6\u9891 HTTP ${res.status}${detail}\uFF08${opts.absVideoPath}\uFF09`);
|
|
122853
123160
|
}
|
|
122854
123161
|
let data;
|
|
122855
123162
|
try {
|
|
122856
|
-
data = JSON.parse(
|
|
123163
|
+
data = JSON.parse(text3);
|
|
122857
123164
|
} catch {
|
|
122858
123165
|
throw new Error(`\u4E0A\u4F20\u89C6\u9891\u54CD\u5E94\u975E JSON\uFF08${opts.absVideoPath}\uFF09`);
|
|
122859
123166
|
}
|
|
@@ -123456,6 +123763,7 @@ async function buildEnableBrandGuidelinesApiBody(configFile, cfg, accountId, con
|
|
|
123456
123763
|
}
|
|
123457
123764
|
|
|
123458
123765
|
// src/commands/ad/pmax-mgmt.ts
|
|
123766
|
+
init_shared();
|
|
123459
123767
|
function buildReportQuery(opts) {
|
|
123460
123768
|
const params = new URLSearchParams();
|
|
123461
123769
|
params.set("startDate", toGoogleDate(opts.startDate, -30).replace(/\//g, "-"));
|
|
@@ -126030,15 +126338,15 @@ function formatMetaAdError(err) {
|
|
|
126030
126338
|
}
|
|
126031
126339
|
return appendMetaAdErrorHint(raw);
|
|
126032
126340
|
}
|
|
126033
|
-
function appendMetaAdErrorHint(
|
|
126034
|
-
if (!/advantage_audience|targeting_automation/i.test(
|
|
126035
|
-
return `${
|
|
126341
|
+
function appendMetaAdErrorHint(text3) {
|
|
126342
|
+
if (!/advantage_audience|targeting_automation/i.test(text3)) return text3;
|
|
126343
|
+
return `${text3}
|
|
126036
126344
|
\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
|
|
126037
126345
|
\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`;
|
|
126038
126346
|
}
|
|
126039
126347
|
function isBidAmountRequired(err) {
|
|
126040
|
-
const
|
|
126041
|
-
return /BID_AMOUNT_REQUIRED/i.test(
|
|
126348
|
+
const text3 = formatMetaAdError(err);
|
|
126349
|
+
return /BID_AMOUNT_REQUIRED/i.test(text3) || /缺少竞价金额/.test(text3) || /必须提供 bid_amount/.test(text3) || /必须在 bid_amount/.test(text3);
|
|
126042
126350
|
}
|
|
126043
126351
|
function failMetaAd(action, err) {
|
|
126044
126352
|
console.error(`
|
|
@@ -127435,7 +127743,7 @@ var QUESTION_TYPE_LABEL = {
|
|
|
127435
127743
|
JOB_TITLE: "Job Title",
|
|
127436
127744
|
CUSTOM: "Custom"
|
|
127437
127745
|
};
|
|
127438
|
-
function
|
|
127746
|
+
function text2(value) {
|
|
127439
127747
|
if (value == null) return PENDING;
|
|
127440
127748
|
const s = String(value).trim();
|
|
127441
127749
|
return s || PENDING;
|
|
@@ -127456,7 +127764,7 @@ function dailyBudgetText(cfg) {
|
|
|
127456
127764
|
return `$${amount} / \u5929\uFF08${mode || "CBO"}\uFF09`;
|
|
127457
127765
|
}
|
|
127458
127766
|
function questionLabel(q) {
|
|
127459
|
-
return q.label?.trim() || QUESTION_TYPE_LABEL[String(q.type || "").toUpperCase()] ||
|
|
127767
|
+
return q.label?.trim() || QUESTION_TYPE_LABEL[String(q.type || "").toUpperCase()] || text2(q.type);
|
|
127460
127768
|
}
|
|
127461
127769
|
function questionRequired(q) {
|
|
127462
127770
|
if (q.required === false) return "\u5426";
|
|
@@ -127563,21 +127871,21 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127563
127871
|
hAlign: "center"
|
|
127564
127872
|
});
|
|
127565
127873
|
overview.blankRow();
|
|
127566
|
-
overview.kvRow("\u5BA2\u6237\u540D\u79F0",
|
|
127567
|
-
overview.kvRow("Facebook \u4E3B\u9875",
|
|
127874
|
+
overview.kvRow("\u5BA2\u6237\u540D\u79F0", text2(plan.customerName));
|
|
127875
|
+
overview.kvRow("Facebook \u4E3B\u9875", text2(plan.pageUrl || "\u5F85 pages \u540E\u8865"), {
|
|
127568
127876
|
hyperlink: plan.pageUrl?.startsWith("http") ? plan.pageUrl : void 0
|
|
127569
127877
|
});
|
|
127570
|
-
overview.kvRow("\u5B98\u65B9\u7F51\u7AD9",
|
|
127878
|
+
overview.kvRow("\u5B98\u65B9\u7F51\u7AD9", text2(plan.siteUrl), {
|
|
127571
127879
|
hyperlink: plan.siteUrl?.startsWith("http") ? plan.siteUrl : void 0
|
|
127572
127880
|
});
|
|
127573
|
-
overview.kvRow("\u4E3B\u8425\u4E1A\u52A1",
|
|
127574
|
-
overview.kvRow("\u6838\u5FC3\u4EA7\u54C1",
|
|
127575
|
-
overview.kvRow("\u6838\u5FC3\u5356\u70B9",
|
|
127576
|
-
overview.kvRow("\u76EE\u6807\u5E02\u573A",
|
|
127577
|
-
overview.kvRow("\u8425\u9500\u76EE\u6807",
|
|
127881
|
+
overview.kvRow("\u4E3B\u8425\u4E1A\u52A1", text2(plan.businessOneLiner));
|
|
127882
|
+
overview.kvRow("\u6838\u5FC3\u4EA7\u54C1", text2(plan.products));
|
|
127883
|
+
overview.kvRow("\u6838\u5FC3\u5356\u70B9", text2(plan.sellingPoints));
|
|
127884
|
+
overview.kvRow("\u76EE\u6807\u5E02\u573A", text2(plan.targetMarkets || joinList(cfg.adset?.countries, ", ")));
|
|
127885
|
+
overview.kvRow("\u8425\u9500\u76EE\u6807", text2(plan.mainResult || "\u8868\u5355\u8BE2\u76D8\uFF08Lead Form\uFF09"));
|
|
127578
127886
|
overview.kvRow("\u65E5\u9884\u7B97", dailyBudgetText(cfg));
|
|
127579
127887
|
overview.kvRow("\u5E7F\u544A\u7ED3\u6784", structureSummary(cfg));
|
|
127580
|
-
overview.kvRow("\u6295\u653E\u7B56\u7565",
|
|
127888
|
+
overview.kvRow("\u6295\u653E\u7B56\u7565", text2(plan.strategy || plan.landingType));
|
|
127581
127889
|
const profile = wb.addSheet(SHEET_NAMES[1]);
|
|
127582
127890
|
profile.setColWidths([26, 48, 26, 26]);
|
|
127583
127891
|
profile.titleBar(profileTitle(plan), { fill: OPS.title });
|
|
@@ -127586,13 +127894,13 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127586
127894
|
profile.sectionBar("\u4E00\u3001\u516C\u53F8\u57FA\u672C\u4FE1\u606F", { fill: OPS.section });
|
|
127587
127895
|
profile.tableHeader(["\u9879\u76EE", "\u5185\u5BB9", "\u5907\u6CE8", ""], { fill: OPS.header });
|
|
127588
127896
|
const profileRows = [
|
|
127589
|
-
["\u516C\u53F8\u540D\u79F0",
|
|
127590
|
-
["\u5B98\u7F51",
|
|
127591
|
-
["\u6838\u5FC3\u4EA7\u54C1",
|
|
127592
|
-
["\u5E7F\u544A\u805A\u7126",
|
|
127593
|
-
["\u5DE5\u5382\u5B9E\u529B",
|
|
127594
|
-
["\u8BA4\u8BC1\u8D44\u8D28",
|
|
127595
|
-
["\u6838\u5FC3\u5356\u70B9",
|
|
127897
|
+
["\u516C\u53F8\u540D\u79F0", text2(plan.customerName), "\u5355\u4E3B\u4F53\u5B9A\u4F4D"],
|
|
127898
|
+
["\u5B98\u7F51", text2(plan.siteUrl), "\u9A8C\u8BC1\u516C\u53F8\u771F\u5B9E\u6027"],
|
|
127899
|
+
["\u6838\u5FC3\u4EA7\u54C1", text2(plan.products), ""],
|
|
127900
|
+
["\u5E7F\u544A\u805A\u7126", text2(plan.adFocus), ""],
|
|
127901
|
+
["\u5DE5\u5382\u5B9E\u529B", text2(plan.factory), "\u6838\u5FC3\u5B9E\u529B\u80CC\u4E66"],
|
|
127902
|
+
["\u8BA4\u8BC1\u8D44\u8D28", text2(plan.certifications), "B2B\u4FE1\u4EFB\u4FE1\u53F7"],
|
|
127903
|
+
["\u6838\u5FC3\u5356\u70B9", text2(plan.sellingPoints || endorsementText(plan)), "\u5DEE\u5F02\u5316\u4F18\u52BF"]
|
|
127596
127904
|
];
|
|
127597
127905
|
for (const [label2, value, note] of profileRows) {
|
|
127598
127906
|
profile.dataRow([label2, value, note || "", ""], { labelColumns: [0] });
|
|
@@ -127609,20 +127917,20 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127609
127917
|
} else {
|
|
127610
127918
|
for (const [industry, job] of termRows) {
|
|
127611
127919
|
profile.dataRow(
|
|
127612
|
-
[
|
|
127920
|
+
[text2(industry.en), optionalText(industry.zh), text2(job.en), optionalText(job.zh)],
|
|
127613
127921
|
{ labelColumns: [0, 2] }
|
|
127614
127922
|
);
|
|
127615
127923
|
}
|
|
127616
127924
|
}
|
|
127617
127925
|
profile.blankRow();
|
|
127618
127926
|
profile.sectionBar("\u8865\u5145\u5174\u8DA3\u8BCD\uFF08Broad Targeting\uFF09", { fill: OPS.section });
|
|
127619
|
-
profile.noteRow(
|
|
127927
|
+
profile.noteRow(text2(plan.targeting?.extraInterests));
|
|
127620
127928
|
profile.noteRow(
|
|
127621
127929
|
plan.targeting?.disclaimer?.trim() || "\u672C\u6279\u7EC4\u5B9A\u5411\u53EA\u8BA4\u56FD\u5BB6/\u5E74\u9F84/\u6027\u522B\uFF0C\u5174\u8DA3\u8BCD\u4EC5\u4F5C\u7D20\u6750\u4E0E\u83B7\u5BA2\u8BF4\u660E"
|
|
127622
127930
|
);
|
|
127623
127931
|
const structure = wb.addSheet(SHEET_NAMES[2]);
|
|
127624
127932
|
structure.setColWidths([18, 44, 26, 22]);
|
|
127625
|
-
structure.titleBar(
|
|
127933
|
+
structure.titleBar(text2(plan.brand ? `\u5E7F\u544A\u8D26\u6237\u7ED3\u6784\uFF1A${plan.brand}` : "\u5E7F\u544A\u8D26\u6237\u7ED3\u6784"), {
|
|
127626
127934
|
fill: OPS.title
|
|
127627
127935
|
});
|
|
127628
127936
|
structure.subtitleBar(subtitle);
|
|
@@ -127633,13 +127941,13 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127633
127941
|
structure.dataRow(
|
|
127634
127942
|
[
|
|
127635
127943
|
"\u5E7F\u544A\u76EE\u6807",
|
|
127636
|
-
|
|
127637
|
-
|
|
127944
|
+
text2(cfg.campaign?.name),
|
|
127945
|
+
text2(cfg.adset?.optimizationGoal || "Leads\uFF08\u6F5C\u5728\u5BA2\u6237\u5F00\u53D1\uFF09"),
|
|
127638
127946
|
dailyBudgetText(cfg)
|
|
127639
127947
|
],
|
|
127640
127948
|
{ labelColumns: [0] }
|
|
127641
127949
|
);
|
|
127642
|
-
structure.dataRow(["\u5E7F\u544A\u7EC4\u7B56\u7565", `${adSets.length} \u4E2A\u5E7F\u544A\u7EC4`,
|
|
127950
|
+
structure.dataRow(["\u5E7F\u544A\u7EC4\u7B56\u7565", `${adSets.length} \u4E2A\u5E7F\u544A\u7EC4`, text2(plan.strategy), ""], {
|
|
127643
127951
|
labelColumns: [0]
|
|
127644
127952
|
});
|
|
127645
127953
|
structure.dataRow(
|
|
@@ -127671,11 +127979,11 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127671
127979
|
for (const row of adSets) {
|
|
127672
127980
|
lead.dataRow(
|
|
127673
127981
|
[
|
|
127674
|
-
|
|
127675
|
-
|
|
127676
|
-
|
|
127677
|
-
|
|
127678
|
-
|
|
127982
|
+
text2(row.label || row.name),
|
|
127983
|
+
text2(row.region || joinList(row.countries, "\u3001")),
|
|
127984
|
+
text2(row.targeting),
|
|
127985
|
+
text2(row.creatives),
|
|
127986
|
+
text2(row.cpl),
|
|
127679
127987
|
optionalText(row.note)
|
|
127680
127988
|
],
|
|
127681
127989
|
{ labelColumns: [0] }
|
|
@@ -127701,9 +128009,9 @@ function writeOpsExcel(outPath, cfg) {
|
|
|
127701
128009
|
for (const block of resolveCopyBlocks(cfg)) {
|
|
127702
128010
|
lead.dataRow(
|
|
127703
128011
|
[
|
|
127704
|
-
|
|
128012
|
+
text2(block.element),
|
|
127705
128013
|
optionalText(block.kind),
|
|
127706
|
-
|
|
128014
|
+
text2(block.text),
|
|
127707
128015
|
optionalText(block.note),
|
|
127708
128016
|
"",
|
|
127709
128017
|
""
|
|
@@ -127723,28 +128031,28 @@ function renderMarkdown(cfg) {
|
|
|
127723
128031
|
const jobs = (plan.targeting?.jobs ?? []).map((row) => `- ${row.en ?? PENDING}${row.zh ? `\uFF08${row.zh}\uFF09` : ""}`).join("\n");
|
|
127724
128032
|
const copies = resolveCopyBlocks(cfg).map((block) => `### ${block.element?.replace(/\n/g, " ") || "\u6587\u6848"}
|
|
127725
128033
|
|
|
127726
|
-
${
|
|
128034
|
+
${text2(block.text)}
|
|
127727
128035
|
`).join("\n");
|
|
127728
128036
|
return `# ${overviewTitle(plan)}
|
|
127729
128037
|
|
|
127730
|
-
- \u5BA2\u6237/\u7AD9\u70B9\uFF1A${
|
|
127731
|
-
- \u4E3B\u7ED3\u679C\uFF1A${
|
|
127732
|
-
- \u843D\u5730\u5EFA\u8BAE\uFF1A${
|
|
128038
|
+
- \u5BA2\u6237/\u7AD9\u70B9\uFF1A${text2(plan.customerName)} + ${text2(plan.siteUrl)} + ${text2(plan.businessOneLiner)}
|
|
128039
|
+
- \u4E3B\u7ED3\u679C\uFF1A${text2(plan.mainResult)}
|
|
128040
|
+
- \u843D\u5730\u5EFA\u8BAE\uFF1A${text2(plan.landingType)}
|
|
127733
128041
|
- \u65E5\u9884\u7B97\uFF1A${dailyBudgetText(cfg)}\u3000\u56FD\u5BB6\uFF1A${joinList(cfg.adset?.countries, ", ")}
|
|
127734
128042
|
- \u5E7F\u544A\u7ED3\u6784\uFF1A${structureSummary(cfg)}
|
|
127735
128043
|
- \u8BA1\u5212\u72B6\u6001\uFF1A**\u5F85\u786E\u8BA4**\u3000\u672C\u6279\u53EF\u6267\u884C\uFF1AInstant Form \u7EBF\u7D22\u5E7F\u544A\uFF08\u975E Advantage+\uFF09
|
|
127736
128044
|
|
|
127737
|
-
> \u8D26\u6237\uFF1A${
|
|
128045
|
+
> \u8D26\u6237\uFF1A${text2(cfg.account)}\u3000\u4E3B\u9875\uFF1A${text2(cfg.pageId)}
|
|
127738
128046
|
|
|
127739
128047
|
## \u4E00\u3001\u516C\u53F8\u57FA\u672C\u4FE1\u606F
|
|
127740
128048
|
|
|
127741
128049
|
| \u9879\u76EE | \u5185\u5BB9 |
|
|
127742
128050
|
| --- | --- |
|
|
127743
|
-
| \u6838\u5FC3\u4EA7\u54C1 | ${
|
|
127744
|
-
| \u5E7F\u544A\u805A\u7126 | ${
|
|
127745
|
-
| \u5DE5\u5382\u5B9E\u529B | ${
|
|
127746
|
-
| \u8BA4\u8BC1\u8D44\u8D28 | ${
|
|
127747
|
-
| \u6838\u5FC3\u5356\u70B9 | ${
|
|
128051
|
+
| \u6838\u5FC3\u4EA7\u54C1 | ${text2(plan.products)} |
|
|
128052
|
+
| \u5E7F\u544A\u805A\u7126 | ${text2(plan.adFocus)} |
|
|
128053
|
+
| \u5DE5\u5382\u5B9E\u529B | ${text2(plan.factory)} |
|
|
128054
|
+
| \u8BA4\u8BC1\u8D44\u8D28 | ${text2(plan.certifications)} |
|
|
128055
|
+
| \u6838\u5FC3\u5356\u70B9 | ${text2(plan.sellingPoints)} |
|
|
127748
128056
|
| \u53EF\u5F15\u7528\u80CC\u4E66 | ${endorsementText(plan)} |
|
|
127749
128057
|
|
|
127750
128058
|
## \u5B9A\u5411\u8BF4\u660E\uFF08\u5BA1\u67E5\u7A3F\uFF09
|
|
@@ -127757,7 +128065,7 @@ ${industries || PENDING}
|
|
|
127757
128065
|
|
|
127758
128066
|
${jobs || PENDING}
|
|
127759
128067
|
|
|
127760
|
-
\u8865\u5145\u5174\u8DA3\u8BCD\uFF1A${
|
|
128068
|
+
\u8865\u5145\u5174\u8DA3\u8BCD\uFF1A${text2(plan.targeting?.extraInterests)}
|
|
127761
128069
|
|
|
127762
128070
|
${plan.targeting?.disclaimer || "\u672C\u6279\u7EC4\u5B9A\u5411\u53EA\u8BA4\u56FD\u5BB6/\u5E74\u9F84/\u6027\u522B\uFF0C\u5174\u8DA3\u8BCD\u4EC5\u4F5C\u7D20\u6750\u4E0E\u83B7\u5BA2\u8BF4\u660E\u3002"}
|
|
127763
128071
|
|
|
@@ -127766,7 +128074,7 @@ ${plan.targeting?.disclaimer || "\u672C\u6279\u7EC4\u5B9A\u5411\u53EA\u8BA4\u56F
|
|
|
127766
128074
|
| \u5E7F\u544A\u7EC4 | \u5730\u533A | \u7D20\u6750 | \u8BE2\u76D8\u6210\u672C |
|
|
127767
128075
|
| --- | --- | --- | --- |
|
|
127768
128076
|
${adSets.map(
|
|
127769
|
-
(row) => `| ${
|
|
128077
|
+
(row) => `| ${text2(row.label || row.name)} | ${text2(row.region || joinList(row.countries, "\u3001"))} | ${text2(row.creatives)} | ${text2(row.cpl)} |`
|
|
127770
128078
|
).join("\n")}
|
|
127771
128079
|
|
|
127772
128080
|
## Instant Form \u5B57\u6BB5
|
|
@@ -127783,10 +128091,10 @@ ${copies}
|
|
|
127783
128091
|
|
|
127784
128092
|
| \u9879 | \u5185\u5BB9 |
|
|
127785
128093
|
| --- | --- |
|
|
127786
|
-
| message | ${
|
|
127787
|
-
| headline | ${
|
|
127788
|
-
| link | ${
|
|
127789
|
-
| \u8868\u5355 | ${
|
|
128094
|
+
| message | ${text2(cfg.creative?.message)} |
|
|
128095
|
+
| headline | ${text2(cfg.creative?.headline)} |
|
|
128096
|
+
| link | ${text2(cfg.creative?.link)} |
|
|
128097
|
+
| \u8868\u5355 | ${text2(cfg.form?.name || cfg.form?.reuseId)} |
|
|
127790
128098
|
|
|
127791
128099
|
\u8349\u6848\u4F9D\u636E\u4E3A\u516C\u5F00\u9875\u9762/\u5BA2\u6237\u6750\u6599\uFF0C\u975E\u5E7F\u544A\u540E\u53F0\u6570\u636E\u3002
|
|
127792
128100
|
`;
|
|
@@ -128784,6 +129092,7 @@ init_cli_table();
|
|
|
128784
129092
|
|
|
128785
129093
|
// src/commands/keyword-account-match.ts
|
|
128786
129094
|
init_auth();
|
|
129095
|
+
init_shared();
|
|
128787
129096
|
function normalizeKeywordForAccountMatch(raw) {
|
|
128788
129097
|
return unwrapKeywordDisplayTextForEdit(raw.trim()).toLowerCase();
|
|
128789
129098
|
}
|
|
@@ -128814,9 +129123,9 @@ async function fetchAccountPositiveKeywordNormSet(config, googleApiUrl, accountI
|
|
|
128814
129123
|
if (seenIds.has(id)) continue;
|
|
128815
129124
|
seenIds.add(id);
|
|
128816
129125
|
}
|
|
128817
|
-
const
|
|
128818
|
-
if (!
|
|
128819
|
-
const norm = normalizeKeywordForAccountMatch(
|
|
129126
|
+
const text3 = extractKeywordTextFromManagementRow(row);
|
|
129127
|
+
if (!text3) continue;
|
|
129128
|
+
const norm = normalizeKeywordForAccountMatch(text3);
|
|
128820
129129
|
if (norm) normSet.add(norm);
|
|
128821
129130
|
}
|
|
128822
129131
|
return normSet;
|
|
@@ -129335,8 +129644,8 @@ function similarityPercent(score) {
|
|
|
129335
129644
|
const s = Math.min(1, Math.max(0, score));
|
|
129336
129645
|
return `${Math.round(s * 100)}%`;
|
|
129337
129646
|
}
|
|
129338
|
-
function blockquoteMarkdown(
|
|
129339
|
-
return
|
|
129647
|
+
function blockquoteMarkdown(text3) {
|
|
129648
|
+
return text3.split("\n").map((line) => `> ${line}`).join("\n");
|
|
129340
129649
|
}
|
|
129341
129650
|
function formatTime(iso) {
|
|
129342
129651
|
if (!iso) return "";
|
|
@@ -130004,8 +130313,8 @@ function assertGoogleMediaCustomerId(raw) {
|
|
|
130004
130313
|
process.exit(1);
|
|
130005
130314
|
}
|
|
130006
130315
|
}
|
|
130007
|
-
function parseCustomerAccessPermissionBody(
|
|
130008
|
-
const trimmed =
|
|
130316
|
+
function parseCustomerAccessPermissionBody(text3) {
|
|
130317
|
+
const trimmed = text3.trim();
|
|
130009
130318
|
if (!trimmed) return null;
|
|
130010
130319
|
try {
|
|
130011
130320
|
const parsed = JSON.parse(trimmed);
|
|
@@ -130047,8 +130356,8 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
|
|
|
130047
130356
|
};
|
|
130048
130357
|
}
|
|
130049
130358
|
if (httpStatus === 403) {
|
|
130050
|
-
const
|
|
130051
|
-
if (
|
|
130359
|
+
const text3 = typeof rawBody === "string" ? rawBody : rawBody == null ? "" : String(rawBody);
|
|
130360
|
+
if (text3.includes("token\u4E0D\u80FD\u4E3A\u7A7A") || text3.toLowerCase().includes("token") && text3.includes("\u7A7A")) {
|
|
130052
130361
|
return {
|
|
130053
130362
|
...base,
|
|
130054
130363
|
status: "google_not_bound",
|
|
@@ -131963,12 +132272,12 @@ async function uploadAttachment(filePath, apiBaseUrl, config, verbose) {
|
|
|
131963
132272
|
headers,
|
|
131964
132273
|
body: form
|
|
131965
132274
|
});
|
|
131966
|
-
const
|
|
132275
|
+
const text3 = await res.text();
|
|
131967
132276
|
if (!res.ok) {
|
|
131968
|
-
const detail = verbose ? `\uFF1A${
|
|
132277
|
+
const detail = verbose ? `\uFF1A${text3.slice(0, 300)}` : "";
|
|
131969
132278
|
throw new Error(`\u4E0A\u4F20\u6587\u4EF6 HTTP ${res.status}${detail}`);
|
|
131970
132279
|
}
|
|
131971
|
-
const data = JSON.parse(
|
|
132280
|
+
const data = JSON.parse(text3);
|
|
131972
132281
|
if (!data.id) {
|
|
131973
132282
|
throw new Error("\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25\uFF1A\u54CD\u5E94\u4E2D\u672A\u5305\u542B\u6587\u4EF6 ID");
|
|
131974
132283
|
}
|
|
@@ -133713,9 +134022,9 @@ init_cli_json_snapshot();
|
|
|
133713
134022
|
import fs14 from "fs";
|
|
133714
134023
|
import path19 from "path";
|
|
133715
134024
|
function readJson(filePath) {
|
|
133716
|
-
const
|
|
134025
|
+
const text3 = fs14.readFileSync(filePath, "utf8");
|
|
133717
134026
|
try {
|
|
133718
|
-
const v = JSON.parse(
|
|
134027
|
+
const v = JSON.parse(text3);
|
|
133719
134028
|
if (!v || typeof v !== "object" || Array.isArray(v)) {
|
|
133720
134029
|
throw new Error("\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
133721
134030
|
}
|
|
@@ -133822,9 +134131,9 @@ function websiteDiagnosisRuntimePath() {
|
|
|
133822
134131
|
}
|
|
133823
134132
|
function readJsonFile(filePath) {
|
|
133824
134133
|
const raw = fsPromises.readFile(filePath, "utf8");
|
|
133825
|
-
return raw.then((
|
|
134134
|
+
return raw.then((text3) => {
|
|
133826
134135
|
try {
|
|
133827
|
-
return JSON.parse(
|
|
134136
|
+
return JSON.parse(text3);
|
|
133828
134137
|
} catch {
|
|
133829
134138
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
133830
134139
|
}
|
|
@@ -136549,7 +136858,7 @@ function collectGoldClaimTexts(data) {
|
|
|
136549
136858
|
if (rec) texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
|
|
136550
136859
|
}
|
|
136551
136860
|
}
|
|
136552
|
-
return texts.filter((
|
|
136861
|
+
return texts.filter((text3) => text3.trim().length > 0);
|
|
136553
136862
|
}
|
|
136554
136863
|
function findIdenticalTexts(texts, minCount) {
|
|
136555
136864
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -136557,8 +136866,8 @@ function findIdenticalTexts(texts, minCount) {
|
|
|
136557
136866
|
if (!t) continue;
|
|
136558
136867
|
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
136559
136868
|
}
|
|
136560
|
-
for (const [
|
|
136561
|
-
if (count2 >= minCount) return
|
|
136869
|
+
for (const [text3, count2] of counts) {
|
|
136870
|
+
if (count2 >= minCount) return text3;
|
|
136562
136871
|
}
|
|
136563
136872
|
return null;
|
|
136564
136873
|
}
|
|
@@ -136631,20 +136940,20 @@ function asRecord14(value) {
|
|
|
136631
136940
|
}
|
|
136632
136941
|
return null;
|
|
136633
136942
|
}
|
|
136634
|
-
function proseColonIndex(
|
|
136635
|
-
const cn =
|
|
136636
|
-
if (cn > 0 && cn <
|
|
136637
|
-
for (let i = 1; i <
|
|
136638
|
-
if (
|
|
136639
|
-
if (
|
|
136640
|
-
const scheme =
|
|
136943
|
+
function proseColonIndex(text3) {
|
|
136944
|
+
const cn = text3.indexOf("\uFF1A");
|
|
136945
|
+
if (cn > 0 && cn < text3.length - 1) return cn;
|
|
136946
|
+
for (let i = 1; i < text3.length - 1; i++) {
|
|
136947
|
+
if (text3[i] !== ":") continue;
|
|
136948
|
+
if (text3[i + 1] === "/") continue;
|
|
136949
|
+
const scheme = text3.slice(Math.max(0, i - 5), i);
|
|
136641
136950
|
if (/https?$/i.test(scheme)) continue;
|
|
136642
136951
|
return i;
|
|
136643
136952
|
}
|
|
136644
136953
|
return -1;
|
|
136645
136954
|
}
|
|
136646
|
-
function splitOverviewProse(
|
|
136647
|
-
const trimmed =
|
|
136955
|
+
function splitOverviewProse(text3) {
|
|
136956
|
+
const trimmed = text3.trim();
|
|
136648
136957
|
const cut = proseColonIndex(trimmed);
|
|
136649
136958
|
if (cut > 0) {
|
|
136650
136959
|
const title = trimmed.slice(0, cut).trim();
|
|
@@ -136655,9 +136964,9 @@ function splitOverviewProse(text2) {
|
|
|
136655
136964
|
}
|
|
136656
136965
|
function normalizeOverviewItem(item) {
|
|
136657
136966
|
if (typeof item === "string" || typeof item === "number") {
|
|
136658
|
-
const
|
|
136659
|
-
if (!
|
|
136660
|
-
return splitOverviewProse(
|
|
136967
|
+
const text3 = String(item).trim();
|
|
136968
|
+
if (!text3) return null;
|
|
136969
|
+
return splitOverviewProse(text3);
|
|
136661
136970
|
}
|
|
136662
136971
|
const rec = asRecord14(item);
|
|
136663
136972
|
if (!rec) return null;
|
|
@@ -136738,16 +137047,16 @@ function creativeSuggestionFromRow(row) {
|
|
|
136738
137047
|
function distinctCopies(rows, key) {
|
|
136739
137048
|
const counts = /* @__PURE__ */ new Map();
|
|
136740
137049
|
for (const row of rows) {
|
|
136741
|
-
const
|
|
136742
|
-
counts.set(
|
|
137050
|
+
const text3 = String(row[key] ?? "");
|
|
137051
|
+
counts.set(text3, (counts.get(text3) ?? 0) + 1);
|
|
136743
137052
|
}
|
|
136744
137053
|
const seen = /* @__PURE__ */ new Map();
|
|
136745
137054
|
return rows.map((row) => {
|
|
136746
|
-
const
|
|
136747
|
-
if ((counts.get(
|
|
136748
|
-
const n = (seen.get(
|
|
136749
|
-
seen.set(
|
|
136750
|
-
return { ...row, [key]: `${
|
|
137055
|
+
const text3 = String(row[key] ?? "");
|
|
137056
|
+
if ((counts.get(text3) ?? 0) < 3) return row;
|
|
137057
|
+
const n = (seen.get(text3) ?? 0) + 1;
|
|
137058
|
+
seen.set(text3, n);
|
|
137059
|
+
return { ...row, [key]: `${text3}\uFF08\u540C\u7ED3\u6784\u7B2C ${n} \u6761\uFF09` };
|
|
136751
137060
|
});
|
|
136752
137061
|
}
|
|
136753
137062
|
function mapRows(rows, write) {
|
|
@@ -138908,7 +139217,7 @@ function buildMetaPeriodExcelSheets(data) {
|
|
|
138908
139217
|
})
|
|
138909
139218
|
],
|
|
138910
139219
|
[],
|
|
138911
|
-
...buildSummaryNarrative(data).map((
|
|
139220
|
+
...buildSummaryNarrative(data).map((text3) => [text3])
|
|
138912
139221
|
];
|
|
138913
139222
|
const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
|
|
138914
139223
|
for (const raw of asArray3(tables.daily)) {
|
|
@@ -139281,9 +139590,9 @@ function parseRenderFormats(raw) {
|
|
|
139281
139590
|
return [...new Set(out)];
|
|
139282
139591
|
}
|
|
139283
139592
|
async function readJsonFile4(filePath) {
|
|
139284
|
-
const
|
|
139593
|
+
const text3 = await fsPromises3.readFile(filePath, "utf8");
|
|
139285
139594
|
try {
|
|
139286
|
-
return JSON.parse(
|
|
139595
|
+
return JSON.parse(text3);
|
|
139287
139596
|
} catch {
|
|
139288
139597
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
139289
139598
|
}
|
|
@@ -139742,9 +140051,9 @@ function metaDiagnosisReportTemplatePath() {
|
|
|
139742
140051
|
return resolveSkillTemplatePath5(TEMPLATE_BASENAME2);
|
|
139743
140052
|
}
|
|
139744
140053
|
async function readJsonFile5(filePath) {
|
|
139745
|
-
const
|
|
140054
|
+
const text3 = await fsPromises4.readFile(filePath, "utf8");
|
|
139746
140055
|
try {
|
|
139747
|
-
return JSON.parse(
|
|
140056
|
+
return JSON.parse(text3);
|
|
139748
140057
|
} catch {
|
|
139749
140058
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
139750
140059
|
}
|
|
@@ -141874,9 +142183,9 @@ function bingPeriodReportTemplatePath() {
|
|
|
141874
142183
|
return resolveSkillTemplatePath6(TEMPLATE_BASENAME3);
|
|
141875
142184
|
}
|
|
141876
142185
|
async function readJsonFile6(filePath) {
|
|
141877
|
-
const
|
|
142186
|
+
const text3 = await fsPromises5.readFile(filePath, "utf8");
|
|
141878
142187
|
try {
|
|
141879
|
-
return JSON.parse(
|
|
142188
|
+
return JSON.parse(text3);
|
|
141880
142189
|
} catch {
|
|
141881
142190
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
141882
142191
|
}
|
|
@@ -142773,9 +143082,9 @@ function tiktokPeriodReportTemplatePath() {
|
|
|
142773
143082
|
return resolveSkillTemplatePath7(TEMPLATE_BASENAME4);
|
|
142774
143083
|
}
|
|
142775
143084
|
async function readJsonFile7(filePath) {
|
|
142776
|
-
const
|
|
143085
|
+
const text3 = await fsPromises6.readFile(filePath, "utf8");
|
|
142777
143086
|
try {
|
|
142778
|
-
return JSON.parse(
|
|
143087
|
+
return JSON.parse(text3);
|
|
142779
143088
|
} catch {
|
|
142780
143089
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
142781
143090
|
}
|
|
@@ -144549,9 +144858,9 @@ function yandexPeriodReportTemplatePath() {
|
|
|
144549
144858
|
return resolveSkillTemplatePath8(TEMPLATE_BASENAME5);
|
|
144550
144859
|
}
|
|
144551
144860
|
async function readJsonFile8(filePath) {
|
|
144552
|
-
const
|
|
144861
|
+
const text3 = await fsPromises7.readFile(filePath, "utf8");
|
|
144553
144862
|
try {
|
|
144554
|
-
return JSON.parse(
|
|
144863
|
+
return JSON.parse(text3);
|
|
144555
144864
|
} catch {
|
|
144556
144865
|
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
144557
144866
|
}
|
|
@@ -145210,12 +145519,12 @@ function hasDateFromTo(args) {
|
|
|
145210
145519
|
}
|
|
145211
145520
|
var RERUN_HINT = "\u7ACB\u523B\u6539\u8DD1\u63D0\u793A\u4E2D\u7684\u90A3\u6761\uFF0C\u4E0D\u8981\u505C\u5728\u9519\u8BEF\u547D\u4EE4\u3002";
|
|
145212
145521
|
function fatal(body) {
|
|
145213
|
-
const
|
|
145214
|
-
if (
|
|
145215
|
-
${
|
|
145522
|
+
const text3 = body.replace(/\s+$/g, "");
|
|
145523
|
+
if (text3.includes(RERUN_HINT)) return `
|
|
145524
|
+
${text3}
|
|
145216
145525
|
`;
|
|
145217
145526
|
return `
|
|
145218
|
-
${
|
|
145527
|
+
${text3}
|
|
145219
145528
|
${RERUN_HINT}
|
|
145220
145529
|
`;
|
|
145221
145530
|
}
|