siluzan-tso-cli 1.1.28-beta.2 → 1.1.28-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
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.28-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.28-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -106072,6 +106072,55 @@ async function writeReportAnalysisSnapshot(params) {
|
|
|
106072
106072
|
|
|
106073
106073
|
// src/commands/report/main.ts
|
|
106074
106074
|
init_version();
|
|
106075
|
+
|
|
106076
|
+
// src/commands/facebook-analysis/fetch.ts
|
|
106077
|
+
init_auth();
|
|
106078
|
+
function normalizeFacebookAccountId(raw) {
|
|
106079
|
+
const t = raw.trim();
|
|
106080
|
+
if (!t) {
|
|
106081
|
+
console.error("\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\u3002\n");
|
|
106082
|
+
process.exit(1);
|
|
106083
|
+
}
|
|
106084
|
+
const digits = t.startsWith("act_") ? t.slice(4) : t;
|
|
106085
|
+
if (!/^\d+$/.test(digits)) {
|
|
106086
|
+
console.error(
|
|
106087
|
+
"\n\u274C --account \u987B\u4E3A Facebook \u5E7F\u544A\u8D26\u6237 ID\uFF08\u6570\u5B57 mediaCustomerId\uFF0C\u6216 act_<\u6570\u5B57>\uFF0C\u4E0E list-accounts -m MetaAd \u4E00\u81F4\uFF09\u3002\n"
|
|
106088
|
+
);
|
|
106089
|
+
process.exit(1);
|
|
106090
|
+
}
|
|
106091
|
+
return { apiId: `act_${digits}`, manifestId: digits };
|
|
106092
|
+
}
|
|
106093
|
+
function resolveFacebookDateRange(start, end) {
|
|
106094
|
+
if (start && end) return { startDate: start, endDate: end };
|
|
106095
|
+
if (!start && !end) {
|
|
106096
|
+
const endD = /* @__PURE__ */ new Date();
|
|
106097
|
+
endD.setDate(endD.getDate() - 1);
|
|
106098
|
+
const startD = new Date(endD);
|
|
106099
|
+
startD.setDate(startD.getDate() - 6);
|
|
106100
|
+
const fmt2 = (d) => d.toISOString().slice(0, 10);
|
|
106101
|
+
return { startDate: fmt2(startD), endDate: fmt2(endD) };
|
|
106102
|
+
}
|
|
106103
|
+
console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
|
|
106104
|
+
process.exit(1);
|
|
106105
|
+
}
|
|
106106
|
+
function facebookReportingUrl(config, apiId, segment, query) {
|
|
106107
|
+
const q = query ? query.startsWith("?") ? query : `?${query}` : "";
|
|
106108
|
+
return `${config.apiBaseUrl}/reporting/media-account/FacebookAds/${encodeURIComponent(apiId)}/${segment}${q}`;
|
|
106109
|
+
}
|
|
106110
|
+
async function fetchFacebookSectionPayload(def, opts, config, apiId) {
|
|
106111
|
+
const { startDate, endDate } = resolveFacebookDateRange(opts.start, opts.end);
|
|
106112
|
+
const params = new URLSearchParams({ startDate, endDate });
|
|
106113
|
+
if (def.countryLimitOption && opts.limit !== void 0 && Number.isFinite(opts.limit)) {
|
|
106114
|
+
params.set("limit", String(Math.max(1, Math.floor(opts.limit))));
|
|
106115
|
+
}
|
|
106116
|
+
const url = facebookReportingUrl(config, apiId, def.segment, params.toString());
|
|
106117
|
+
return apiFetch2(url, config, {}, opts.verbose ?? false);
|
|
106118
|
+
}
|
|
106119
|
+
function endpointHintForFacebookSection(def, apiId) {
|
|
106120
|
+
return `GET \u2026/FacebookAds/${apiId}/${def.segment}`;
|
|
106121
|
+
}
|
|
106122
|
+
|
|
106123
|
+
// src/commands/report/main.ts
|
|
106075
106124
|
async function runReportList(opts) {
|
|
106076
106125
|
if (!VALID_MEDIA_TYPES5.includes(opts.media)) {
|
|
106077
106126
|
console.error(`
|
|
@@ -106173,30 +106222,61 @@ function fmtNum2(n, digits = 2) {
|
|
|
106173
106222
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
106174
106223
|
return parts.join(".");
|
|
106175
106224
|
}
|
|
106225
|
+
function metaOverviewManifestId(raw) {
|
|
106226
|
+
const t = raw.trim();
|
|
106227
|
+
if (t.startsWith("act_")) return t.slice(4);
|
|
106228
|
+
return t;
|
|
106229
|
+
}
|
|
106230
|
+
function buildMetaOverviewUrl(config, accountId, mediaAccountType, startDate, endDate) {
|
|
106231
|
+
const { apiId, manifestId } = normalizeFacebookAccountId(accountId);
|
|
106232
|
+
const params = new URLSearchParams({ startDate, endDate }).toString();
|
|
106233
|
+
if (mediaAccountType === "FacebookAds") {
|
|
106234
|
+
return facebookReportingUrl(config, apiId, "OverviewSectionData", params);
|
|
106235
|
+
}
|
|
106236
|
+
return `${config.apiBaseUrl}/reporting/media-account/MetaAd/${manifestId}/OverviewSectionData?${params}`;
|
|
106237
|
+
}
|
|
106176
106238
|
async function runReportMetaOverview(opts) {
|
|
106177
|
-
const
|
|
106178
|
-
|
|
106179
|
-
|
|
106239
|
+
const rawAccount = opts.account.trim();
|
|
106240
|
+
let manifestId;
|
|
106241
|
+
try {
|
|
106242
|
+
manifestId = normalizeFacebookAccountId(rawAccount).manifestId;
|
|
106243
|
+
} catch {
|
|
106244
|
+
console.error(
|
|
106245
|
+
"\n\u274C --account \u987B\u4E3A\u6570\u5B57 mediaCustomerId \u6216 act_<\u6570\u5B57>\uFF08\u4E0E list-accounts -m MetaAd \u4E00\u81F4\uFF09\u3002\n"
|
|
106246
|
+
);
|
|
106180
106247
|
process.exit(1);
|
|
106181
106248
|
}
|
|
106182
106249
|
const { startDate, endDate } = resolveMetaOverviewDateRange(opts.startDate, opts.endDate);
|
|
106183
106250
|
const config = loadConfig(opts.token);
|
|
106184
|
-
const
|
|
106185
|
-
const
|
|
106251
|
+
const accountDetail = await lookupMetaAccountForOverview(config, manifestId, opts.verbose);
|
|
106252
|
+
const mediaAccountType = accountDetail?.mediaAccountType ?? "FacebookAds";
|
|
106253
|
+
const url = buildMetaOverviewUrl(config, rawAccount, mediaAccountType, startDate, endDate);
|
|
106186
106254
|
let data;
|
|
106187
106255
|
try {
|
|
106188
106256
|
data = await apiFetch2(url, config, {}, opts.verbose);
|
|
106189
106257
|
} catch (err) {
|
|
106190
|
-
|
|
106191
|
-
|
|
106258
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
106259
|
+
if (msg.includes("403")) {
|
|
106260
|
+
console.error(
|
|
106261
|
+
`
|
|
106262
|
+
\u274C \u8BF7\u6C42\u5931\u8D25\uFF1AHTTP 403
|
|
106263
|
+
\u8D26\u6237 ${manifestId} \u7684 mediaAccountType=${mediaAccountType ?? "\u672A\u77E5"}\u3002
|
|
106264
|
+
Facebook \u6388\u6743\u8D26\u6237\uFF08FacebookAds\uFF09\u987B\u8D70 FacebookAds/act_ \u8DEF\u5F84\uFF1B\u4E1D\u8DEF\u8D5E Meta \u5F00\u6237\u8D70 MetaAd \u8DEF\u5F84\u3002
|
|
106265
|
+
\u5468\u671F/\u591A\u7EF4\u5EA6\u62A5\u544A\u8BF7\u6539\u7528\uFF1Asiluzan-tso facebook-analysis -a ${manifestId} --sections overview --json-out <dir>
|
|
106266
|
+
`
|
|
106267
|
+
);
|
|
106268
|
+
} else {
|
|
106269
|
+
console.error(`
|
|
106270
|
+
\u274C \u8BF7\u6C42\u5931\u8D25\uFF1A${msg}
|
|
106192
106271
|
`);
|
|
106272
|
+
}
|
|
106193
106273
|
process.exit(1);
|
|
106194
106274
|
}
|
|
106195
106275
|
if (opts.jsonOut) {
|
|
106196
106276
|
const summary = await writeReportAnalysisSnapshot({
|
|
106197
106277
|
snapshotDir: opts.jsonOut,
|
|
106198
106278
|
section: "meta-overview",
|
|
106199
|
-
accountId:
|
|
106279
|
+
accountId: manifestId,
|
|
106200
106280
|
dateRange: { start: startDate, end: endDate },
|
|
106201
106281
|
payload: data,
|
|
106202
106282
|
cliVersion: getCurrentVersion2()
|
|
@@ -106211,7 +106291,7 @@ async function runReportMetaOverview(opts) {
|
|
|
106211
106291
|
const optRaw = row.optimizationScore;
|
|
106212
106292
|
const optPct = typeof optRaw === "number" && optRaw <= 1 && optRaw >= 0 ? (optRaw * 100).toFixed(0) : typeof optRaw === "number" ? String(optRaw) : "\u2014";
|
|
106213
106293
|
console.log(`
|
|
106214
|
-
\u2705 Meta \u8D26\u6237\u603B\u89C8 ${
|
|
106294
|
+
\u2705 Meta \u8D26\u6237\u603B\u89C8 ${manifestId} \u533A\u95F4 ${startDate} ~ ${endDate}
|
|
106215
106295
|
`);
|
|
106216
106296
|
console.log(
|
|
106217
106297
|
` \u8D27\u5E01 ${currency} \u4F18\u5316\u5F97\u5206 ${optPct}${typeof optRaw === "number" && optRaw <= 1 ? "%\uFF080\u20131 \u5DF2\u6362\u7B97\uFF09" : ""} \u603B\u6D88\u8017 ${fmtNum2(typeof row.totalCost === "number" ? row.totalCost : cur.spend)} \u4F59\u989D ${fmtNum2(typeof row.remainingAccountBudget === "number" ? row.remainingAccountBudget : void 0)} \u6D3B\u8DC3\u5929\u6570 ${row.activeDays ?? "\u2014"} \u65E5\u5747\u6D88\u8017 ${fmtNum2(typeof row.averageDailyCost === "number" ? row.averageDailyCost : void 0)}
|
|
@@ -106227,6 +106307,42 @@ async function runReportMetaOverview(opts) {
|
|
|
106227
106307
|
function toSlashDate(date) {
|
|
106228
106308
|
return date.replace(/-/g, "/");
|
|
106229
106309
|
}
|
|
106310
|
+
async function lookupMetaAccountForOverview(config, manifestId, verbose = false) {
|
|
106311
|
+
for (const idCandidate of [manifestId, `act_${manifestId}`]) {
|
|
106312
|
+
const params = new URLSearchParams({
|
|
106313
|
+
MediaTypes: "MetaAd|FacebookAds",
|
|
106314
|
+
advStatus: "",
|
|
106315
|
+
mediaAccountState: "Approved,Linked",
|
|
106316
|
+
isForce: "false",
|
|
106317
|
+
pageNum: "1",
|
|
106318
|
+
pageSize: "20",
|
|
106319
|
+
mediaCustomerIds: idCandidate
|
|
106320
|
+
});
|
|
106321
|
+
try {
|
|
106322
|
+
const data = await apiFetch2(
|
|
106323
|
+
`${config.apiBaseUrl}/query/media-account/SearchMediaAcountByCriteria?${params}`,
|
|
106324
|
+
config,
|
|
106325
|
+
{},
|
|
106326
|
+
verbose
|
|
106327
|
+
);
|
|
106328
|
+
for (const item of data?.mas ?? []) {
|
|
106329
|
+
const ma = item.ma ?? {};
|
|
106330
|
+
const cidDigits = metaOverviewManifestId(String(ma.mediaCustomerId ?? ""));
|
|
106331
|
+
if (cidDigits === manifestId) {
|
|
106332
|
+
return {
|
|
106333
|
+
entityId: String(ma.entityId ?? ""),
|
|
106334
|
+
mediaCustomerId: String(ma.mediaCustomerId ?? ""),
|
|
106335
|
+
mediaCustomerName: String(ma.mediaCustomerName ?? ""),
|
|
106336
|
+
mediaAccountType: String(ma.mediaAccountType ?? ""),
|
|
106337
|
+
mediaAccountGroupId: String(ma.mediaAccountGroupId ?? "")
|
|
106338
|
+
};
|
|
106339
|
+
}
|
|
106340
|
+
}
|
|
106341
|
+
} catch {
|
|
106342
|
+
}
|
|
106343
|
+
}
|
|
106344
|
+
return void 0;
|
|
106345
|
+
}
|
|
106230
106346
|
async function lookupAccountsByCustomerIds(apiBaseUrl, config, mediaType, customerIds, verbose = false) {
|
|
106231
106347
|
const params = new URLSearchParams({
|
|
106232
106348
|
MediaType: mediaType,
|
|
@@ -106239,14 +106355,17 @@ async function lookupAccountsByCustomerIds(apiBaseUrl, config, mediaType, custom
|
|
|
106239
106355
|
{},
|
|
106240
106356
|
verbose
|
|
106241
106357
|
);
|
|
106242
|
-
const idSet = new Set(
|
|
106358
|
+
const idSet = new Set(
|
|
106359
|
+
customerIds.map((id) => metaOverviewManifestId(id.trim())).filter(Boolean)
|
|
106360
|
+
);
|
|
106243
106361
|
const result = /* @__PURE__ */ new Map();
|
|
106244
106362
|
const items = Array.isArray(data) ? data : [];
|
|
106245
106363
|
for (const item of items) {
|
|
106246
106364
|
const ma = item.ma ?? {};
|
|
106247
106365
|
const cid = String(ma.mediaCustomerId ?? "");
|
|
106248
|
-
|
|
106249
|
-
|
|
106366
|
+
const cidDigits = metaOverviewManifestId(cid);
|
|
106367
|
+
if (idSet.has(cidDigits)) {
|
|
106368
|
+
result.set(cidDigits, {
|
|
106250
106369
|
entityId: String(ma.entityId ?? ""),
|
|
106251
106370
|
mediaCustomerId: cid,
|
|
106252
106371
|
mediaCustomerName: String(ma.mediaCustomerName ?? ""),
|
|
@@ -107480,7 +107599,9 @@ function register13(program2) {
|
|
|
107480
107599
|
verbose: opts.verbose
|
|
107481
107600
|
});
|
|
107482
107601
|
});
|
|
107483
|
-
reportCmd.command("meta-overview").description(
|
|
107602
|
+
reportCmd.command("meta-overview").description(
|
|
107603
|
+
"Meta \u8D26\u6237\u5206\u6790\u603B\u89C8\uFF08OverviewSectionData\uFF1BFacebookAds \u6388\u6743\u6237\u8D70 FacebookAds/act_\uFF0CMetaAd \u5F00\u6237\u8D70 MetaAd\uFF09"
|
|
107604
|
+
).requiredOption("-a, --account <id>", "Meta \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6570\u5B57\u6216 act_<\u6570\u5B57>\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("--token <token>", "Auth Token").option(
|
|
107484
107605
|
"--json-out <path>",
|
|
107485
107606
|
"\u843D\u76D8\u76EE\u5F55\u5E76\u66F4\u65B0 report-manifest[-<accountId>].json\uFF1B\u6587\u4EF6\u540D\u4E3A `<section>[-<accountId>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09"
|
|
107486
107607
|
).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
@@ -122431,53 +122552,6 @@ var FACEBOOK_SECTION_ALIASES = {
|
|
|
122431
122552
|
videos: "material"
|
|
122432
122553
|
};
|
|
122433
122554
|
|
|
122434
|
-
// src/commands/facebook-analysis/fetch.ts
|
|
122435
|
-
init_auth();
|
|
122436
|
-
function normalizeFacebookAccountId(raw) {
|
|
122437
|
-
const t = raw.trim();
|
|
122438
|
-
if (!t) {
|
|
122439
|
-
console.error("\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\u3002\n");
|
|
122440
|
-
process.exit(1);
|
|
122441
|
-
}
|
|
122442
|
-
const digits = t.startsWith("act_") ? t.slice(4) : t;
|
|
122443
|
-
if (!/^\d+$/.test(digits)) {
|
|
122444
|
-
console.error(
|
|
122445
|
-
"\n\u274C --account \u987B\u4E3A Facebook \u5E7F\u544A\u8D26\u6237 ID\uFF08\u6570\u5B57 mediaCustomerId\uFF0C\u6216 act_<\u6570\u5B57>\uFF0C\u4E0E list-accounts -m MetaAd \u4E00\u81F4\uFF09\u3002\n"
|
|
122446
|
-
);
|
|
122447
|
-
process.exit(1);
|
|
122448
|
-
}
|
|
122449
|
-
return { apiId: `act_${digits}`, manifestId: digits };
|
|
122450
|
-
}
|
|
122451
|
-
function resolveFacebookDateRange(start, end) {
|
|
122452
|
-
if (start && end) return { startDate: start, endDate: end };
|
|
122453
|
-
if (!start && !end) {
|
|
122454
|
-
const endD = /* @__PURE__ */ new Date();
|
|
122455
|
-
endD.setDate(endD.getDate() - 1);
|
|
122456
|
-
const startD = new Date(endD);
|
|
122457
|
-
startD.setDate(startD.getDate() - 6);
|
|
122458
|
-
const fmt2 = (d) => d.toISOString().slice(0, 10);
|
|
122459
|
-
return { startDate: fmt2(startD), endDate: fmt2(endD) };
|
|
122460
|
-
}
|
|
122461
|
-
console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
|
|
122462
|
-
process.exit(1);
|
|
122463
|
-
}
|
|
122464
|
-
function facebookReportingUrl(config, apiId, segment, query) {
|
|
122465
|
-
const q = query ? query.startsWith("?") ? query : `?${query}` : "";
|
|
122466
|
-
return `${config.apiBaseUrl}/reporting/media-account/FacebookAds/${encodeURIComponent(apiId)}/${segment}${q}`;
|
|
122467
|
-
}
|
|
122468
|
-
async function fetchFacebookSectionPayload(def, opts, config, apiId) {
|
|
122469
|
-
const { startDate, endDate } = resolveFacebookDateRange(opts.start, opts.end);
|
|
122470
|
-
const params = new URLSearchParams({ startDate, endDate });
|
|
122471
|
-
if (def.countryLimitOption && opts.limit !== void 0 && Number.isFinite(opts.limit)) {
|
|
122472
|
-
params.set("limit", String(Math.max(1, Math.floor(opts.limit))));
|
|
122473
|
-
}
|
|
122474
|
-
const url = facebookReportingUrl(config, apiId, def.segment, params.toString());
|
|
122475
|
-
return apiFetch2(url, config, {}, opts.verbose ?? false);
|
|
122476
|
-
}
|
|
122477
|
-
function endpointHintForFacebookSection(def, apiId) {
|
|
122478
|
-
return `GET \u2026/FacebookAds/${apiId}/${def.segment}`;
|
|
122479
|
-
}
|
|
122480
|
-
|
|
122481
122555
|
// src/commands/facebook-analysis/register-cli.ts
|
|
122482
122556
|
import { Command } from "commander";
|
|
122483
122557
|
|
package/dist/skill/_meta.json
CHANGED
|
@@ -265,7 +265,7 @@ const data = d.record ?? d.items; // record 非空=汇总维度;否则=列表
|
|
|
265
265
|
|
|
266
266
|
> 周期/诊断报告:**`facebook-analysis`**(`FacebookAds` 路径,7 Section,对齐 Google 周期报告能 cover 的部分)。
|
|
267
267
|
> 撰写与 Google 对照表:**`references/analytics/facebook-analysis-guide.md`**(必读)。
|
|
268
|
-
> `report meta-overview`
|
|
268
|
+
> `report meta-overview` 仅为遗留单维总览:按 `list-accounts` 的 `mediaAccountType` 自动选路径——**FacebookAds**(OAuth 授权)→ `FacebookAds/act_<id>`;**MetaAd**(丝路赞开户)→ `MetaAd/<id>`。多维度请用 `facebook-analysis`。
|
|
269
269
|
|
|
270
270
|
### 周期报告(默认 6 维,等同 Google 周期报告主流程)
|
|
271
271
|
|
|
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.28-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.28-beta.3'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
15
|
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.28-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.28-beta.3"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
15
|
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|