siluzan-tso-cli 1.1.27-beta.3 → 1.1.28-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +350 -51
- package/dist/skill/SKILL.md +4 -4
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/meta-period-report.schema.json +199 -0
- package/dist/skill/references/analytics/account-analytics.md +1 -1
- package/dist/skill/references/analytics/facebook-analysis-guide.md +22 -3
- package/dist/skill/report-templates/README.md +2 -1
- package/dist/skill/report-templates/meta-period-report-excel.md +204 -0
- package/dist/skill/report-templates/meta-period-report.html +534 -0
- package/dist/skill/report-templates/meta-period-report.md +104 -48
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.
|
|
54
|
+
> **注意**:当前为测试版(1.1.28-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -258,9 +258,9 @@ var require_semver = __commonJS({
|
|
|
258
258
|
} else {
|
|
259
259
|
this.prerelease = m[4].split(".").map((id) => {
|
|
260
260
|
if (/^[0-9]+$/.test(id)) {
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
return
|
|
261
|
+
const num2 = +id;
|
|
262
|
+
if (num2 >= 0 && num2 < MAX_SAFE_INTEGER) {
|
|
263
|
+
return num2;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
return id;
|
|
@@ -101099,14 +101099,14 @@ function computeBackoffMs(attempt, policy) {
|
|
|
101099
101099
|
return capped + jitter;
|
|
101100
101100
|
}
|
|
101101
101101
|
function sleep3(ms, signal) {
|
|
101102
|
-
return new Promise((
|
|
101102
|
+
return new Promise((resolve15, reject) => {
|
|
101103
101103
|
if (signal?.aborted) {
|
|
101104
101104
|
reject(new Error("retry sleep aborted"));
|
|
101105
101105
|
return;
|
|
101106
101106
|
}
|
|
101107
101107
|
const timer = setTimeout(() => {
|
|
101108
101108
|
signal?.removeEventListener("abort", onAbort);
|
|
101109
|
-
|
|
101109
|
+
resolve15();
|
|
101110
101110
|
}, ms);
|
|
101111
101111
|
const onAbort = () => {
|
|
101112
101112
|
clearTimeout(timer);
|
|
@@ -102726,9 +102726,9 @@ var init_google_analysis3 = __esm({
|
|
|
102726
102726
|
// src/index.ts
|
|
102727
102727
|
init_dist();
|
|
102728
102728
|
init_dist();
|
|
102729
|
-
import * as
|
|
102730
|
-
import * as
|
|
102731
|
-
import { fileURLToPath as
|
|
102729
|
+
import * as fs18 from "fs";
|
|
102730
|
+
import * as path26 from "path";
|
|
102731
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
102732
102732
|
import { Command } from "commander";
|
|
102733
102733
|
|
|
102734
102734
|
// src/commands/login/urls.ts
|
|
@@ -103212,8 +103212,8 @@ function deriveWebUrl(apiBaseUrl) {
|
|
|
103212
103212
|
}
|
|
103213
103213
|
var TSO_UMI_ROUTE_PREFIX = "/v3umijs/tso";
|
|
103214
103214
|
function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
103215
|
-
const
|
|
103216
|
-
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${
|
|
103215
|
+
const path27 = tsoSubRoute.replace(/^\/+/, "");
|
|
103216
|
+
const umiPath = `${TSO_UMI_ROUTE_PREFIX}/${path27}`;
|
|
103217
103217
|
const q = new URLSearchParams({ tso: umiPath });
|
|
103218
103218
|
if (extraQuery) {
|
|
103219
103219
|
for (const [key, value] of Object.entries(extraQuery)) {
|
|
@@ -103221,7 +103221,7 @@ function buildTsoPageWebUrl(webUrl, tsoSubRoute, extraQuery) {
|
|
|
103221
103221
|
if (v) q.set(key, v);
|
|
103222
103222
|
}
|
|
103223
103223
|
}
|
|
103224
|
-
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${
|
|
103224
|
+
return `${webUrl.replace(/\/+$/, "")}/v3/foreign_trade/tso/${path27}?${q.toString()}`;
|
|
103225
103225
|
}
|
|
103226
103226
|
function cmdConfigShow() {
|
|
103227
103227
|
const shared = readSharedConfig();
|
|
@@ -110408,7 +110408,7 @@ function cloneKeywordBlockShell(block) {
|
|
|
110408
110408
|
delete shell["matchTypeV2"];
|
|
110409
110409
|
return shell;
|
|
110410
110410
|
}
|
|
110411
|
-
function splitKeywordsForBatchJobBlockIfMixed(block,
|
|
110411
|
+
function splitKeywordsForBatchJobBlockIfMixed(block, path27, warnings) {
|
|
110412
110412
|
const declaredUi = matchTypeV2ToUi(readBlockMatchTypeRaw(block));
|
|
110413
110413
|
const entries = collectKeywordEntriesFromBlock(block);
|
|
110414
110414
|
if (entries.length === 0) return [block];
|
|
@@ -110427,7 +110427,7 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path25, warnings) {
|
|
|
110427
110427
|
(ui) => matchTypeUiToV2(ui)
|
|
110428
110428
|
);
|
|
110429
110429
|
warnings.push(
|
|
110430
|
-
`${
|
|
110430
|
+
`${path27} \u542B\u591A\u79CD\u5339\u914D\u7C7B\u578B\uFF0C\u5DF2\u81EA\u52A8\u62C6\u5206\u4E3A ${groups.size} \u4E2A KeywordsForBatchJob \u5757\uFF08${labels.join("\u3001")}\uFF09`
|
|
110431
110431
|
);
|
|
110432
110432
|
const shell = cloneKeywordBlockShell(block);
|
|
110433
110433
|
const splitBlocks = [];
|
|
@@ -110447,16 +110447,16 @@ function splitKeywordsForBatchJobBlockIfMixed(block, path25, warnings) {
|
|
|
110447
110447
|
}
|
|
110448
110448
|
return splitBlocks;
|
|
110449
110449
|
}
|
|
110450
|
-
function validateKeywordCore(core,
|
|
110450
|
+
function validateKeywordCore(core, path27, errors, lengthViolations) {
|
|
110451
110451
|
const trimmed = core.trim();
|
|
110452
110452
|
if (!trimmed) {
|
|
110453
|
-
errors.push(`${
|
|
110453
|
+
errors.push(`${path27} \u5173\u952E\u8BCD\u8BCD\u5E72\u4E0D\u80FD\u4E3A\u7A7A`);
|
|
110454
110454
|
return false;
|
|
110455
110455
|
}
|
|
110456
110456
|
if (trimmed.length > GOOGLE_KEYWORD_MAX_CORE_LENGTH) {
|
|
110457
110457
|
if (lengthViolations) {
|
|
110458
110458
|
pushLengthViolation(lengthViolations, {
|
|
110459
|
-
path:
|
|
110459
|
+
path: path27,
|
|
110460
110460
|
field: "KeywordText",
|
|
110461
110461
|
kind: "keyword_core",
|
|
110462
110462
|
limit: GOOGLE_KEYWORD_MAX_CORE_LENGTH,
|
|
@@ -110466,13 +110466,13 @@ function validateKeywordCore(core, path25, errors, lengthViolations) {
|
|
|
110466
110466
|
});
|
|
110467
110467
|
}
|
|
110468
110468
|
errors.push(
|
|
110469
|
-
`${
|
|
110469
|
+
`${path27} \u5173\u952E\u8BCD\u8BCD\u5E72\u8D85\u8FC7 ${GOOGLE_KEYWORD_MAX_CORE_LENGTH} \u5B57\u7B26\uFF08\u5F53\u524D ${trimmed.length}\uFF09\uFF1A"${trimmed}"`
|
|
110470
110470
|
);
|
|
110471
110471
|
return false;
|
|
110472
110472
|
}
|
|
110473
110473
|
if (!VALID_CORE_REGEX.test(trimmed)) {
|
|
110474
110474
|
errors.push(
|
|
110475
|
-
`${
|
|
110475
|
+
`${path27} \u542B Google \u4E0D\u5141\u8BB8\u7684\u5B57\u7B26\uFF08\u8BCD\u5E72\u4EC5\u5141\u8BB8\u5B57\u6BCD/\u6570\u5B57/\u7A7A\u683C/\u8FDE\u5B57\u7B26/\u53E5\u70B9\uFF09\uFF1A"${trimmed.slice(0, 40)}${trimmed.length > 40 ? "\u2026" : ""}"`
|
|
110476
110476
|
);
|
|
110477
110477
|
return false;
|
|
110478
110478
|
}
|
|
@@ -110529,24 +110529,24 @@ function canonicalizeKeywordBatchBlock(block, resolvedMatchV2, normalizedTexts,
|
|
|
110529
110529
|
}
|
|
110530
110530
|
}
|
|
110531
110531
|
}
|
|
110532
|
-
function pushKeywordAutoFixWarning(warnings,
|
|
110532
|
+
function pushKeywordAutoFixWarning(warnings, path27, fieldLabel, trimmedRaw, formatted, declaredUi, beforeUi, matchType, inferredMatchType) {
|
|
110533
110533
|
if (inferredMatchType) {
|
|
110534
110534
|
warnings.push(
|
|
110535
|
-
`${
|
|
110535
|
+
`${path27}.${fieldLabel} \u672A\u6307\u5B9A MatchTypeV2\uFF0C\u5DF2\u6309\u8BCD\u9762\u63A8\u65AD\u4E3A ${matchTypeUiToV2(matchType)}`
|
|
110536
110536
|
);
|
|
110537
110537
|
return;
|
|
110538
110538
|
}
|
|
110539
110539
|
if (declaredUi && beforeUi !== declaredUi) {
|
|
110540
110540
|
warnings.push(
|
|
110541
|
-
`${
|
|
110541
|
+
`${path27}.${fieldLabel} MatchTypeV2=${matchTypeUiToV2(declaredUi)} \u4E0E\u8BCD\u9762\u4E0D\u4E00\u81F4\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\u4E3A\uFF1A${formatted}`
|
|
110542
110542
|
);
|
|
110543
110543
|
return;
|
|
110544
110544
|
}
|
|
110545
110545
|
if (formatted !== trimmedRaw) {
|
|
110546
|
-
warnings.push(`${
|
|
110546
|
+
warnings.push(`${path27}.${fieldLabel} \u5DF2\u81EA\u52A8\u4FEE\u590D\u8BCD\u9762\uFF1A${trimmedRaw} \u2192 ${formatted}`);
|
|
110547
110547
|
}
|
|
110548
110548
|
}
|
|
110549
|
-
function normalizeKeywordTextList(texts, matchTypeRaw,
|
|
110549
|
+
function normalizeKeywordTextList(texts, matchTypeRaw, path27, fieldLabel, errors, warnings, lengthViolations) {
|
|
110550
110550
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110551
110551
|
const normalized = [];
|
|
110552
110552
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -110554,7 +110554,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110554
110554
|
for (let k = 0; k < texts.length; k++) {
|
|
110555
110555
|
const raw = texts[k];
|
|
110556
110556
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
110557
|
-
errors.push(`${
|
|
110557
|
+
errors.push(`${path27}.${fieldLabel}[${k}] \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110558
110558
|
continue;
|
|
110559
110559
|
}
|
|
110560
110560
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110562,7 +110562,7 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110562
110562
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110563
110563
|
pushKeywordAutoFixWarning(
|
|
110564
110564
|
warnings,
|
|
110565
|
-
|
|
110565
|
+
path27,
|
|
110566
110566
|
fieldLabel,
|
|
110567
110567
|
trimmedRaw,
|
|
110568
110568
|
formatted,
|
|
@@ -110572,10 +110572,10 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110572
110572
|
inferredMatchType
|
|
110573
110573
|
);
|
|
110574
110574
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110575
|
-
if (!validateKeywordCore(core, `${
|
|
110575
|
+
if (!validateKeywordCore(core, `${path27}.${fieldLabel}[${k}]`, errors, lengthViolations)) continue;
|
|
110576
110576
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110577
110577
|
if (seen.has(dedupeKey)) {
|
|
110578
|
-
warnings.push(`${
|
|
110578
|
+
warnings.push(`${path27}.${fieldLabel}[${k}] \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110579
110579
|
continue;
|
|
110580
110580
|
}
|
|
110581
110581
|
seen.add(dedupeKey);
|
|
@@ -110584,12 +110584,12 @@ function normalizeKeywordTextList(texts, matchTypeRaw, path25, fieldLabel, error
|
|
|
110584
110584
|
}
|
|
110585
110585
|
return { normalized, resolvedUi };
|
|
110586
110586
|
}
|
|
110587
|
-
function normalizeKeywordsForBatchJobBlock(block,
|
|
110587
|
+
function normalizeKeywordsForBatchJobBlock(block, path27, errors, warnings, lengthViolations) {
|
|
110588
110588
|
const matchTypeRaw = readBlockMatchTypeRaw(block);
|
|
110589
110589
|
const declaredUi = matchTypeV2ToUi(matchTypeRaw);
|
|
110590
110590
|
if (matchTypeRaw !== void 0 && declaredUi === null) {
|
|
110591
110591
|
errors.push(
|
|
110592
|
-
`${
|
|
110592
|
+
`${path27}.MatchTypeV2 \u65E0\u6548\uFF08${String(matchTypeRaw)}\uFF09\uFF0C\u5408\u6CD5\u503C\uFF1ABROAD | PHRASE | EXACT`
|
|
110593
110593
|
);
|
|
110594
110594
|
return;
|
|
110595
110595
|
}
|
|
@@ -110604,7 +110604,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110604
110604
|
const result = normalizeKeywordTextList(
|
|
110605
110605
|
texts,
|
|
110606
110606
|
matchTypeRaw,
|
|
110607
|
-
|
|
110607
|
+
path27,
|
|
110608
110608
|
"KeywordText",
|
|
110609
110609
|
errors,
|
|
110610
110610
|
warnings,
|
|
@@ -110613,7 +110613,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110613
110613
|
normalizedTexts = result.normalized;
|
|
110614
110614
|
if (result.resolvedUi) resolvedUi = result.resolvedUi;
|
|
110615
110615
|
if (normalizedTexts.length === 0 && texts.length > 0) {
|
|
110616
|
-
errors.push(`${
|
|
110616
|
+
errors.push(`${path27}.KeywordText \u7ECF\u6821\u9A8C\u540E\u65E0\u6709\u6548\u5173\u952E\u8BCD\uFF0C\u8BF7\u4FEE\u6B63\u8BCD\u9762\u6216 MatchTypeV2`);
|
|
110617
110617
|
}
|
|
110618
110618
|
}
|
|
110619
110619
|
if (hasItems && items) {
|
|
@@ -110621,12 +110621,12 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110621
110621
|
for (let k = 0; k < items.length; k++) {
|
|
110622
110622
|
const item = items[k];
|
|
110623
110623
|
if (!item || typeof item !== "object") {
|
|
110624
|
-
errors.push(`${
|
|
110624
|
+
errors.push(`${path27}.Items[${k}] \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
110625
110625
|
continue;
|
|
110626
110626
|
}
|
|
110627
110627
|
const raw = readItemText(item);
|
|
110628
110628
|
if (raw === null || !raw.trim()) {
|
|
110629
|
-
errors.push(`${
|
|
110629
|
+
errors.push(`${path27}.Items[${k}].Text \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
110630
110630
|
continue;
|
|
110631
110631
|
}
|
|
110632
110632
|
const trimmedRaw = collapseDuplicateSpacesInKeywordText(raw.trim());
|
|
@@ -110634,7 +110634,7 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110634
110634
|
const { formatted, matchType, inferredMatchType } = normalizeKeywordSurface(trimmedRaw, matchTypeRaw);
|
|
110635
110635
|
pushKeywordAutoFixWarning(
|
|
110636
110636
|
warnings,
|
|
110637
|
-
|
|
110637
|
+
path27,
|
|
110638
110638
|
`Items[${k}].Text`,
|
|
110639
110639
|
trimmedRaw,
|
|
110640
110640
|
formatted,
|
|
@@ -110644,10 +110644,10 @@ function normalizeKeywordsForBatchJobBlock(block, path25, errors, warnings, leng
|
|
|
110644
110644
|
inferredMatchType
|
|
110645
110645
|
);
|
|
110646
110646
|
const core = unwrapKeywordDisplayTextForEdit(formatted);
|
|
110647
|
-
if (!validateKeywordCore(core, `${
|
|
110647
|
+
if (!validateKeywordCore(core, `${path27}.Items[${k}].Text`, errors, lengthViolations)) continue;
|
|
110648
110648
|
const dedupeKey = `${matchTypeUiToV2(matchType)}:${core.toLowerCase()}`;
|
|
110649
110649
|
if (seen.has(dedupeKey)) {
|
|
110650
|
-
warnings.push(`${
|
|
110650
|
+
warnings.push(`${path27}.Items[${k}].Text \u4E0E\u540C\u7EC4\u91CD\u590D\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${formatted}`);
|
|
110651
110651
|
continue;
|
|
110652
110652
|
}
|
|
110653
110653
|
seen.add(dedupeKey);
|
|
@@ -113255,12 +113255,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113255
113255
|
for (let ki = 0; ki < texts.length; ki++) {
|
|
113256
113256
|
const t = texts[ki];
|
|
113257
113257
|
if (typeof t !== "string" || !t.trim()) continue;
|
|
113258
|
-
const
|
|
113258
|
+
const path27 = `${groupPath}.KeywordsForBatchJob[${bi}].KeywordText[${ki}]`;
|
|
113259
113259
|
const key = keywordKey(t, matchTypeV2);
|
|
113260
113260
|
if (!liveKwKeys.has(key)) {
|
|
113261
113261
|
missing.push({
|
|
113262
113262
|
layer: "keyword",
|
|
113263
|
-
path:
|
|
113263
|
+
path: path27,
|
|
113264
113264
|
adGroupName: groupName,
|
|
113265
113265
|
plannedContent: `\u8BCD\u9762: ${t} | \u5339\u914D: ${matchTypeV2}`,
|
|
113266
113266
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveKwInGroup.length} \u6761\u5173\u952E\u8BCD\uFF0C\u65E0\u952E ${key}`,
|
|
@@ -113278,12 +113278,12 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113278
113278
|
for (let ai = 0; ai < ads.length; ai++) {
|
|
113279
113279
|
const ad = asRecord2(ads[ai]);
|
|
113280
113280
|
if (!ad) continue;
|
|
113281
|
-
const
|
|
113281
|
+
const path27 = `${groupPath}.AdsForBatchJob[${ai}]`;
|
|
113282
113282
|
const primary = pickString(ad["headlinePart1"], ad["AdTitle"]);
|
|
113283
113283
|
if (!primary) {
|
|
113284
113284
|
missing.push({
|
|
113285
113285
|
layer: "ad",
|
|
113286
|
-
path:
|
|
113286
|
+
path: path27,
|
|
113287
113287
|
adGroupName: groupName,
|
|
113288
113288
|
plannedContent: `AdsForBatchJob[${ai}]\uFF08\u7F3A\u5C11 headlinePart1\uFF0C\u65E0\u6CD5\u6BD4\u5BF9\uFF09`,
|
|
113289
113289
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761\u521B\u610F`,
|
|
@@ -113296,7 +113296,7 @@ function compareCampaignCreateToLive(cfg, campaignId, live, meta) {
|
|
|
113296
113296
|
if (!found) {
|
|
113297
113297
|
missing.push({
|
|
113298
113298
|
layer: "ad",
|
|
113299
|
-
path:
|
|
113299
|
+
path: path27,
|
|
113300
113300
|
adGroupName: groupName,
|
|
113301
113301
|
plannedContent: `RSA \u9996\u6807\u9898: ${primary}${finalUrl ? ` | \u843D\u5730\u9875: ${finalUrl}` : ""}`,
|
|
113302
113302
|
liveNote: `\u540C\u7EC4\u5DF2\u6709 ${liveAdsInGroup.length} \u6761 RSA\uFF0C\u65E0\u6B64\u9996\u6807\u9898`,
|
|
@@ -114494,13 +114494,13 @@ function pmaxChannelTypesUrl(googleApiUrl) {
|
|
|
114494
114494
|
}
|
|
114495
114495
|
function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
|
|
114496
114496
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114497
|
-
const
|
|
114498
|
-
return campaignId ? `${
|
|
114497
|
+
const path27 = `${base}/accounts/${accountId}/campaign/pmax`;
|
|
114498
|
+
return campaignId ? `${path27}/${campaignId}` : path27;
|
|
114499
114499
|
}
|
|
114500
114500
|
function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
|
|
114501
114501
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
114502
|
-
const
|
|
114503
|
-
return suffix ? `${
|
|
114502
|
+
const path27 = `${base}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
|
|
114503
|
+
return suffix ? `${path27}/${suffix.replace(/^\//, "")}` : path27;
|
|
114504
114504
|
}
|
|
114505
114505
|
function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
|
|
114506
114506
|
const base = googleApiUrl.replace(/\/$/, "");
|
|
@@ -122476,9 +122476,296 @@ function endpointHintForFacebookSection(def, apiId) {
|
|
|
122476
122476
|
return `GET \u2026/FacebookAds/${apiId}/${def.segment}`;
|
|
122477
122477
|
}
|
|
122478
122478
|
|
|
122479
|
+
// src/commands/facebook-analysis/render-report.ts
|
|
122480
|
+
import fs17 from "fs";
|
|
122481
|
+
import fsPromises2 from "fs/promises";
|
|
122482
|
+
import path24 from "path";
|
|
122483
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
122484
|
+
|
|
122485
|
+
// src/commands/facebook-analysis/merge-snapshot.ts
|
|
122486
|
+
import * as fs16 from "fs/promises";
|
|
122487
|
+
import * as path23 from "path";
|
|
122488
|
+
function asRecord5(value) {
|
|
122489
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
122490
|
+
return value;
|
|
122491
|
+
}
|
|
122492
|
+
return null;
|
|
122493
|
+
}
|
|
122494
|
+
function num(value) {
|
|
122495
|
+
const n = Number(value);
|
|
122496
|
+
return Number.isFinite(n) ? n : void 0;
|
|
122497
|
+
}
|
|
122498
|
+
function audienceLabel(age, gender) {
|
|
122499
|
+
const g = String(gender ?? "").toLowerCase();
|
|
122500
|
+
const genderZh = g === "male" ? "male" : g === "female" ? "female" : String(gender ?? "");
|
|
122501
|
+
return `${age ?? "\u2014"} \xB7 ${genderZh}`;
|
|
122502
|
+
}
|
|
122503
|
+
function fatigueFromFrequency(freq) {
|
|
122504
|
+
if (freq == null) return { level: "\u4F4E", score: 25 };
|
|
122505
|
+
if (freq >= 2.2) return { level: "\u9AD8", score: 75 };
|
|
122506
|
+
if (freq >= 1.6) return { level: "\u4E2D", score: 55 };
|
|
122507
|
+
return { level: "\u4F4E", score: 25 };
|
|
122508
|
+
}
|
|
122509
|
+
function statusFromCpl(cpl, avg) {
|
|
122510
|
+
if (cpl == null || avg <= 0) return { tag: "yellow", label: "\u89C2\u5BDF" };
|
|
122511
|
+
if (cpl <= avg * 0.9) return { tag: "green", label: "\u76C8\u5229" };
|
|
122512
|
+
if (cpl >= avg * 1.15) return { tag: "red", label: "\u5371\u9669" };
|
|
122513
|
+
return { tag: "yellow", label: "\u89C2\u5BDF" };
|
|
122514
|
+
}
|
|
122515
|
+
async function readManifest(snapshotDir) {
|
|
122516
|
+
const entries = await fs16.readdir(snapshotDir);
|
|
122517
|
+
const manifestNames = entries.filter((n) => n.startsWith("report-manifest") && n.endsWith(".json"));
|
|
122518
|
+
const ordered = [
|
|
122519
|
+
...manifestNames.filter((n) => n !== REPORT_MANIFEST_FILE),
|
|
122520
|
+
...manifestNames.includes(REPORT_MANIFEST_FILE) ? [REPORT_MANIFEST_FILE] : []
|
|
122521
|
+
];
|
|
122522
|
+
for (const name2 of ordered) {
|
|
122523
|
+
try {
|
|
122524
|
+
const raw = await fs16.readFile(path23.join(snapshotDir, name2), "utf8");
|
|
122525
|
+
const parsed = JSON.parse(raw);
|
|
122526
|
+
if (parsed?.artifacts?.length) return parsed;
|
|
122527
|
+
} catch {
|
|
122528
|
+
}
|
|
122529
|
+
}
|
|
122530
|
+
return null;
|
|
122531
|
+
}
|
|
122532
|
+
async function loadSectionFile(snapshotDir, file) {
|
|
122533
|
+
try {
|
|
122534
|
+
const raw = await fs16.readFile(path23.join(snapshotDir, file), "utf8");
|
|
122535
|
+
return asRecord5(JSON.parse(raw));
|
|
122536
|
+
} catch {
|
|
122537
|
+
return null;
|
|
122538
|
+
}
|
|
122539
|
+
}
|
|
122540
|
+
function aggregatePlatform(networks) {
|
|
122541
|
+
const map = /* @__PURE__ */ new Map();
|
|
122542
|
+
for (const row of networks) {
|
|
122543
|
+
const platform = String(row.publisherPlatform ?? row.network ?? "unknown");
|
|
122544
|
+
const prev = map.get(platform) ?? { spend: 0, results: 0 };
|
|
122545
|
+
map.set(platform, {
|
|
122546
|
+
spend: prev.spend + (num(row.spend) ?? 0),
|
|
122547
|
+
results: prev.results + (num(row.results) ?? 0)
|
|
122548
|
+
});
|
|
122549
|
+
}
|
|
122550
|
+
const labels = [];
|
|
122551
|
+
const cpl = [];
|
|
122552
|
+
const spend = [];
|
|
122553
|
+
for (const [label, agg] of [...map.entries()].sort((a, b) => b[1].spend - a[1].spend)) {
|
|
122554
|
+
labels.push(label);
|
|
122555
|
+
spend.push(agg.spend);
|
|
122556
|
+
cpl.push(agg.results > 0 ? agg.spend / agg.results : 0);
|
|
122557
|
+
}
|
|
122558
|
+
return { labels, cpl, spend };
|
|
122559
|
+
}
|
|
122560
|
+
function buildAudienceRows(audiences) {
|
|
122561
|
+
return audiences.map((a) => ({
|
|
122562
|
+
label: audienceLabel(a.age, a.gender),
|
|
122563
|
+
spend: num(a.spend) ?? 0,
|
|
122564
|
+
results: num(a.results) ?? 0,
|
|
122565
|
+
costPerResult: num(a.costPerResult) ?? (num(a.results) ? (num(a.spend) ?? 0) / (num(a.results) ?? 1) : 0),
|
|
122566
|
+
frequency: num(a.frequency)
|
|
122567
|
+
})).filter((r) => r.spend > 0 || r.results > 0);
|
|
122568
|
+
}
|
|
122569
|
+
async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
122570
|
+
const absDir = path23.resolve(snapshotDir);
|
|
122571
|
+
const manifest = await readManifest(snapshotDir);
|
|
122572
|
+
if (!manifest) {
|
|
122573
|
+
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C facebook-analysis --json-out`);
|
|
122574
|
+
}
|
|
122575
|
+
const sectionMap = /* @__PURE__ */ new Map();
|
|
122576
|
+
for (const art of manifest.artifacts) {
|
|
122577
|
+
const data = await loadSectionFile(absDir, art.file);
|
|
122578
|
+
if (data) sectionMap.set(art.section, data);
|
|
122579
|
+
}
|
|
122580
|
+
const overview = sectionMap.get("overview");
|
|
122581
|
+
const current = asRecord5(overview?.currentPeriod);
|
|
122582
|
+
const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
|
|
122583
|
+
const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
|
|
122584
|
+
const kpis = { ...payload.kpis ?? {} };
|
|
122585
|
+
if (current) {
|
|
122586
|
+
if (kpis.spend == null) kpis.spend = current.spend;
|
|
122587
|
+
if (kpis.results == null) kpis.results = current.results;
|
|
122588
|
+
if (kpis.costPerResult == null) kpis.costPerResult = current.costPerResult;
|
|
122589
|
+
if (kpis.reach == null) kpis.reach = current.reach;
|
|
122590
|
+
if (kpis.impressions == null) kpis.impressions = current.impressions;
|
|
122591
|
+
if (kpis.frequency == null) kpis.frequency = current.frequency;
|
|
122592
|
+
}
|
|
122593
|
+
const meta = { ...payload.meta ?? {} };
|
|
122594
|
+
if (!meta.accountName && accountName) meta.accountName = accountName;
|
|
122595
|
+
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
122596
|
+
if (!meta.startDate && manifest.dateRange?.start) meta.startDate = manifest.dateRange.start;
|
|
122597
|
+
if (!meta.endDate && manifest.dateRange?.end) meta.endDate = manifest.dateRange.end;
|
|
122598
|
+
if (!meta.attributionSetting && current?.attributionSetting) {
|
|
122599
|
+
meta.attributionSetting = String(current.attributionSetting);
|
|
122600
|
+
}
|
|
122601
|
+
if (!meta.resultType && current?.resultType) meta.resultType = String(current.resultType);
|
|
122602
|
+
const charts = { ...payload.charts ?? {} };
|
|
122603
|
+
const avgCpl = num(kpis.costPerResult) ?? 0;
|
|
122604
|
+
if (!charts.platform) {
|
|
122605
|
+
const platform = sectionMap.get("platform");
|
|
122606
|
+
const networks = Array.isArray(platform?.networks) ? platform.networks : [];
|
|
122607
|
+
if (networks.length) charts.platform = aggregatePlatform(networks);
|
|
122608
|
+
}
|
|
122609
|
+
if (!charts.country) {
|
|
122610
|
+
const country = sectionMap.get("country");
|
|
122611
|
+
const countries = Array.isArray(country?.countries) ? country.countries : [];
|
|
122612
|
+
if (countries.length) {
|
|
122613
|
+
const sorted = [...countries].sort((a, b) => (num(b.spend) ?? 0) - (num(a.spend) ?? 0));
|
|
122614
|
+
charts.country = {
|
|
122615
|
+
labels: sorted.map((c) => String(c.countryOrRegion ?? "\u2014")),
|
|
122616
|
+
cpl: sorted.map((c) => num(c.costPerResult) ?? 0)
|
|
122617
|
+
};
|
|
122618
|
+
}
|
|
122619
|
+
}
|
|
122620
|
+
if (!charts.audience) {
|
|
122621
|
+
const audience = sectionMap.get("audience");
|
|
122622
|
+
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
122623
|
+
if (audiences.length) {
|
|
122624
|
+
const rows = buildAudienceRows(audiences).sort((a, b) => a.costPerResult - b.costPerResult);
|
|
122625
|
+
charts.audience = {
|
|
122626
|
+
labels: rows.map((r) => r.label),
|
|
122627
|
+
cpl: rows.map((r) => r.costPerResult),
|
|
122628
|
+
leads: rows.map((r) => r.results)
|
|
122629
|
+
};
|
|
122630
|
+
}
|
|
122631
|
+
}
|
|
122632
|
+
if (!charts.funnel && num(kpis.reach) != null) {
|
|
122633
|
+
charts.funnel = { reach: kpis.reach, results: kpis.results ?? 0 };
|
|
122634
|
+
}
|
|
122635
|
+
const tables = { ...payload.tables ?? {} };
|
|
122636
|
+
if (!tables.adSets) {
|
|
122637
|
+
const adSets = sectionMap.get("ad-sets");
|
|
122638
|
+
const groups = Array.isArray(adSets?.adGroups) ? adSets.adGroups : [];
|
|
122639
|
+
if (groups.length) {
|
|
122640
|
+
tables.adSets = groups.map((g) => {
|
|
122641
|
+
const cpl = num(g.costPerResult);
|
|
122642
|
+
const freq = num(g.frequency);
|
|
122643
|
+
const fatigue = fatigueFromFrequency(freq);
|
|
122644
|
+
const status = statusFromCpl(cpl, avgCpl);
|
|
122645
|
+
return {
|
|
122646
|
+
name: String(g.adGroupName ?? g.campaignName ?? "\u2014"),
|
|
122647
|
+
spend: num(g.spend) ?? 0,
|
|
122648
|
+
results: num(g.results) ?? 0,
|
|
122649
|
+
costPerResult: cpl ?? 0,
|
|
122650
|
+
frequency: freq,
|
|
122651
|
+
fatigueLevel: fatigue.level,
|
|
122652
|
+
fatigueScore: fatigue.score,
|
|
122653
|
+
statusTag: status.tag,
|
|
122654
|
+
statusLabel: status.label
|
|
122655
|
+
};
|
|
122656
|
+
}).sort((a, b) => b.spend - a.spend);
|
|
122657
|
+
}
|
|
122658
|
+
}
|
|
122659
|
+
if (!tables.audienceTop || !tables.audienceBottom) {
|
|
122660
|
+
const audience = sectionMap.get("audience");
|
|
122661
|
+
const audiences = Array.isArray(audience?.audiences) ? audience.audiences : [];
|
|
122662
|
+
if (audiences.length) {
|
|
122663
|
+
const rows = buildAudienceRows(audiences).sort((a, b) => a.costPerResult - b.costPerResult);
|
|
122664
|
+
const topN = rows.slice(0, 10);
|
|
122665
|
+
const bottomN = [...rows].reverse().slice(0, 10);
|
|
122666
|
+
if (!tables.audienceTop) tables.audienceTop = topN;
|
|
122667
|
+
if (!tables.audienceBottom) tables.audienceBottom = bottomN;
|
|
122668
|
+
}
|
|
122669
|
+
}
|
|
122670
|
+
return {
|
|
122671
|
+
...payload,
|
|
122672
|
+
meta,
|
|
122673
|
+
kpis,
|
|
122674
|
+
charts,
|
|
122675
|
+
tables
|
|
122676
|
+
};
|
|
122677
|
+
}
|
|
122678
|
+
|
|
122679
|
+
// src/commands/facebook-analysis/render-report.ts
|
|
122680
|
+
var TEMPLATE_BASENAMES2 = {
|
|
122681
|
+
html: "meta-period-report.html",
|
|
122682
|
+
runtime: "meta-period-report.runtime.js"
|
|
122683
|
+
};
|
|
122684
|
+
var INJECT_MARKER = "window.__META_PERIOD_REPORT__ = window.__META_PERIOD_REPORT__ || null;";
|
|
122685
|
+
function resolveSkillTemplatePath2(basename11) {
|
|
122686
|
+
const dir = path24.dirname(fileURLToPath5(import.meta.url));
|
|
122687
|
+
const candidates = [
|
|
122688
|
+
path24.join(dir, "skill", "report-templates", basename11),
|
|
122689
|
+
path24.join(dir, "skill", "siluzan-ads", "report-templates", basename11),
|
|
122690
|
+
path24.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename11)
|
|
122691
|
+
];
|
|
122692
|
+
for (const p of candidates) {
|
|
122693
|
+
if (fs17.existsSync(p)) return p;
|
|
122694
|
+
}
|
|
122695
|
+
return candidates[0];
|
|
122696
|
+
}
|
|
122697
|
+
function metaPeriodReportTemplatePath() {
|
|
122698
|
+
return resolveSkillTemplatePath2(TEMPLATE_BASENAMES2.html);
|
|
122699
|
+
}
|
|
122700
|
+
function metaPeriodReportRuntimePath() {
|
|
122701
|
+
return resolveSkillTemplatePath2(TEMPLATE_BASENAMES2.runtime);
|
|
122702
|
+
}
|
|
122703
|
+
async function readJsonFile2(filePath) {
|
|
122704
|
+
const text = await fsPromises2.readFile(filePath, "utf8");
|
|
122705
|
+
try {
|
|
122706
|
+
return JSON.parse(text);
|
|
122707
|
+
} catch {
|
|
122708
|
+
throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
|
|
122709
|
+
}
|
|
122710
|
+
}
|
|
122711
|
+
function asRecord6(value) {
|
|
122712
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
122713
|
+
return value;
|
|
122714
|
+
}
|
|
122715
|
+
throw new Error("\u62A5\u544A\u6570\u636E\u987B\u4E3A JSON \u5BF9\u8C61");
|
|
122716
|
+
}
|
|
122717
|
+
function injectReportData2(html, payload) {
|
|
122718
|
+
const json = JSON.stringify(payload).replace(/</g, "\\u003c");
|
|
122719
|
+
if (!html.includes(INJECT_MARKER)) {
|
|
122720
|
+
throw new Error("\u62A5\u544A\u6A21\u677F\u7F3A\u5C11\u6570\u636E\u6CE8\u5165\u951A\u70B9\uFF0C\u8BF7\u66F4\u65B0 meta-period-report.html");
|
|
122721
|
+
}
|
|
122722
|
+
return html.replace(INJECT_MARKER, `window.__META_PERIOD_REPORT__ = ${json};`);
|
|
122723
|
+
}
|
|
122724
|
+
async function runFacebookAnalysisRender(opts) {
|
|
122725
|
+
const dataPath = path24.resolve(opts.dataFile);
|
|
122726
|
+
let data = asRecord6(await readJsonFile2(dataPath));
|
|
122727
|
+
if (opts.snapshotDir?.trim()) {
|
|
122728
|
+
data = await mergeFacebookSnapshotIntoReport(data, path24.resolve(opts.snapshotDir));
|
|
122729
|
+
}
|
|
122730
|
+
const templatePath = metaPeriodReportTemplatePath();
|
|
122731
|
+
let html;
|
|
122732
|
+
try {
|
|
122733
|
+
html = await fsPromises2.readFile(templatePath, "utf8");
|
|
122734
|
+
} catch {
|
|
122735
|
+
console.error(`
|
|
122736
|
+
\u274C \u672A\u627E\u5230\u62A5\u544A\u6A21\u677F\uFF1A${templatePath}
|
|
122737
|
+
\u8BF7\u5148\u6267\u884C npm run build
|
|
122738
|
+
`);
|
|
122739
|
+
process.exit(1);
|
|
122740
|
+
}
|
|
122741
|
+
const outPath = path24.resolve(
|
|
122742
|
+
opts.out ?? path24.join(path24.dirname(dataPath), "meta-period-report.html")
|
|
122743
|
+
);
|
|
122744
|
+
const outDir = path24.dirname(outPath);
|
|
122745
|
+
await fsPromises2.mkdir(outDir, { recursive: true });
|
|
122746
|
+
await fsPromises2.writeFile(outPath, injectReportData2(html, data), "utf8");
|
|
122747
|
+
const runtimeSrc = metaPeriodReportRuntimePath();
|
|
122748
|
+
const runtimeOut = path24.join(outDir, TEMPLATE_BASENAMES2.runtime);
|
|
122749
|
+
try {
|
|
122750
|
+
await fsPromises2.copyFile(runtimeSrc, runtimeOut);
|
|
122751
|
+
} catch {
|
|
122752
|
+
console.error(`
|
|
122753
|
+
\u274C \u672A\u627E\u5230\u62A5\u544A\u8FD0\u884C\u65F6\uFF1A${runtimeSrc}
|
|
122754
|
+
\u8BF7\u5148\u6267\u884C npm run build
|
|
122755
|
+
`);
|
|
122756
|
+
process.exit(1);
|
|
122757
|
+
}
|
|
122758
|
+
console.log(`
|
|
122759
|
+
\u2705 Meta/Facebook \u5468\u671F\u5206\u6790 HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
|
|
122760
|
+
`);
|
|
122761
|
+
console.log(` \u8FD0\u884C\u65F6\u811A\u672C\uFF1A${runtimeOut}
|
|
122762
|
+
`);
|
|
122763
|
+
console.log("\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 HTML \u6587\u4EF6\u5373\u53EF\u67E5\u770B\u56FE\u8868\u4E0E\u5B8C\u6574\u7AE0\u8282\uFF08\u9700\u8054\u7F51\u52A0\u8F7D Chart.js CDN\uFF09\u3002\n");
|
|
122764
|
+
}
|
|
122765
|
+
|
|
122479
122766
|
// src/commands/facebook-analysis/run-batch.ts
|
|
122480
122767
|
init_auth();
|
|
122481
|
-
import * as
|
|
122768
|
+
import * as path25 from "path";
|
|
122482
122769
|
import { performance as performance5 } from "perf_hooks";
|
|
122483
122770
|
init_version();
|
|
122484
122771
|
|
|
@@ -122582,7 +122869,7 @@ async function runAllFacebookSections(opts) {
|
|
|
122582
122869
|
const results = await runWithConcurrency2(tasks, concurrency);
|
|
122583
122870
|
const succeeded = results.filter((r) => r.ok).length;
|
|
122584
122871
|
const failed = results.length - succeeded;
|
|
122585
|
-
const absoluteSnapshotDir =
|
|
122872
|
+
const absoluteSnapshotDir = path25.resolve(opts.jsonOut);
|
|
122586
122873
|
const summary = {
|
|
122587
122874
|
kind: "siluzan-tso-facebook-analysis-snapshot-batch",
|
|
122588
122875
|
absoluteSnapshotDir,
|
|
@@ -122602,7 +122889,7 @@ async function runAllFacebookSections(opts) {
|
|
|
122602
122889
|
// src/commands/facebook-analysis/register-cli.ts
|
|
122603
122890
|
function registerFacebookAnalysisCommands(program2) {
|
|
122604
122891
|
const sectionHelp = FACEBOOK_SECTION_NAMES.join(", ");
|
|
122605
|
-
program2.command("facebook-analysis").description(
|
|
122892
|
+
const root = program2.command("facebook-analysis").description(
|
|
122606
122893
|
"Facebook Ads \u8D26\u6237\u5206\u6790\u6279\u91CF\u62C9\u53D6\uFF08TSO reporting/media-account/FacebookAds/\u2026\uFF0C7 \u4E2A Section\uFF09"
|
|
122607
122894
|
).requiredOption(
|
|
122608
122895
|
"-a, --account <id>",
|
|
@@ -122623,6 +122910,18 @@ function registerFacebookAnalysisCommands(program2) {
|
|
|
122623
122910
|
).option("--concurrency <n>", "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 16", (v) => parseInt(v, 10)).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
122624
122911
|
await runAllFacebookSections(opts);
|
|
122625
122912
|
});
|
|
122913
|
+
root.command("render").description(
|
|
122914
|
+
"\u6839\u636E Agent \u64B0\u5199\u7684\u62A5\u544A JSON \u751F\u6210 Meta/Facebook \u5468\u671F\u5206\u6790 HTML \u7EC8\u7A3F\uFF08meta-period-report.html\uFF09"
|
|
122915
|
+
).requiredOption("--data <file>", "Agent \u4EA7\u51FA\u7684 meta-period-report.json").option(
|
|
122916
|
+
"--snapshot-dir <dir>",
|
|
122917
|
+
"\u53EF\u9009\uFF1Afacebook-analysis --json-out \u76EE\u5F55\uFF0C\u81EA\u52A8\u5408\u5E76 KPI / \u56FE\u8868 / \u8868\u683C"
|
|
122918
|
+
).option("--out <file>", "\u8F93\u51FA HTML \u8DEF\u5F84\uFF08\u9ED8\u8BA4\u540C --data \u76EE\u5F55\uFF09").action(async (opts) => {
|
|
122919
|
+
await runFacebookAnalysisRender({
|
|
122920
|
+
dataFile: opts.data,
|
|
122921
|
+
snapshotDir: opts.snapshotDir,
|
|
122922
|
+
out: opts.out
|
|
122923
|
+
});
|
|
122924
|
+
});
|
|
122626
122925
|
}
|
|
122627
122926
|
|
|
122628
122927
|
// src/index.ts
|
|
@@ -122631,9 +122930,9 @@ init_cli_json_snapshot();
|
|
|
122631
122930
|
installProcessHandlers();
|
|
122632
122931
|
function getVersion() {
|
|
122633
122932
|
try {
|
|
122634
|
-
const __dirname3 =
|
|
122635
|
-
const pkgPath =
|
|
122636
|
-
const pkg = JSON.parse(
|
|
122933
|
+
const __dirname3 = path26.dirname(fileURLToPath6(import.meta.url));
|
|
122934
|
+
const pkgPath = path26.join(__dirname3, "..", "package.json");
|
|
122935
|
+
const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
|
|
122637
122936
|
return pkg.version ?? "0.0.0";
|
|
122638
122937
|
} catch {
|
|
122639
122938
|
return "0.0.0";
|