siluzan-tso-cli 1.1.28-beta.2 → 1.1.28-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 +134 -60
- package/dist/skill/SKILL.md +9 -8
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/analytics/account-analytics.md +1 -1
- package/dist/skill/references/core/cli-enums.md +0 -2
- package/dist/skill/report-templates/google-inquiry-analysis.md +1 -1
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
- package/dist/skill/docs/skill-guide.md +0 -44
- package/dist/skill/references/core/skill-authoring.md +0 -196
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.4),供内部测试使用。正式发布后安装命令将改为 `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/SKILL.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: siluzan-tso
|
|
3
|
-
description:
|
|
3
|
+
description: 通过 siluzan-tso-cli 操作丝路赞 TSO 广告账户(Google/Bing/Yandex/TikTok/Kwai/MetaAd)。(账户)列表、余额、统计、消耗、激活账单、历史、余额扫描 P2、账户摘要 P3、共享/取消共享、解绑、OAuth、MCC/BC/BM 绑定解绑、邮件邀请、TikTok 关闭、暂停撤回;(开户)六大媒体申请;(Google Ads)系列/广告组/广告/关键词 CRUD、附加信息、地理位置、PMax、搜索投放方案校验/创建、批量异步创建;(分析)google-analysis、google-analysis-batch P5、facebook-analysis P4-FB、网站诊断 P8、市场分析 P9、广告诊断;P1 账户画像、P4 周期报告、P6 OKKI 周报、P7 询盘分析;Google关键词推荐、RAG 检索、TSO 报告列表/创建/推送、智能预警、TikTok/Meta 线索、转账/发票/发票资料、审计恢复。当用户提及广告账户、余额、消耗、投放、关键词、开户、MCC/BC、报告、诊断、市场分析、开票或 TSO 时使用。
|
|
4
4
|
license: MIT
|
|
5
|
-
compatibility:
|
|
5
|
+
compatibility: 需要 Node.js 18+、已安装 siluzan-tso-cli,通过 send-login-code + login 或 config set 完成鉴权
|
|
6
6
|
metadata:
|
|
7
7
|
requires: nodejs,siluzan-tso-cli
|
|
8
8
|
allowed-tools: Bash(siluzan-tso:*) Read Write
|
|
@@ -44,13 +44,14 @@ Windows:部分 Agent 通过 PowerShell 代执行时可能失败,改在 [Git
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
## 可执行的操作范围
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
## 基本使用
|
|
49
|
+
|
|
50
|
+
siluzan-tso-cli只是报名, 安装后可执行的命令是 siluzan-tso
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
siluzan-tso -h // 查看帮助
|
|
54
|
+
```
|
|
54
55
|
|
|
55
56
|
---
|
|
56
57
|
|
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
|
|
|
@@ -159,7 +159,7 @@ Sheet 5 整段系列明细读:`./snap-inquiry/campaigns-<accountId>_<S>-<E>.js
|
|
|
159
159
|
|
|
160
160
|
## 国家 → 大洲映射
|
|
161
161
|
|
|
162
|
-
- **数据源**:`references/analytics/geo-continents.json
|
|
162
|
+
- **数据源**:`references/analytics/geo-continents.json`
|
|
163
163
|
- **默认 7 桶**:`亚洲` / `中东` / `欧洲` / `北美` / `南美` / `非洲` / `大洋洲`。
|
|
164
164
|
- **运营常用 5 桶合并**(与样表 Sheet 3 一致):`<重点国>` / `中东` / `非洲` / `欧美` / `亚洲(除重点国)`。**由脚本在写表前做二次合并**,伪代码:
|
|
165
165
|
|
|
@@ -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.4'
|
|
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.4"
|
|
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"
|
package/package.json
CHANGED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Siluzan TSO Skill — 人类导读
|
|
2
|
-
|
|
3
|
-
Agent 运行时请用 `SKILL.md` + `AGENTS.md`;本文供维护者与产品经理深读。
|
|
4
|
-
|
|
5
|
-
## 设计理念(对齐 gstack)
|
|
6
|
-
|
|
7
|
-
1. **薄入口**:`SKILL.md` 仅路由,<150 行
|
|
8
|
-
2. **域化 references**:`core/`、`accounts/`、`google-ads/`、`analytics/`、`operations/`
|
|
9
|
-
3. **渐进披露**:Playbook、参数表、SOP 按需 Read,不塞进主文件
|
|
10
|
-
4. **模板分离**:`assets/*.json` 契约 vs `report-templates/*.md` 内容纲要
|
|
11
|
-
|
|
12
|
-
## 目录树
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
siluzan-ads/
|
|
16
|
-
├── AGENTS.md # Agent 域目录(类似 gstack AGENTS.md)
|
|
17
|
-
├── SKILL.md # 路由入口
|
|
18
|
-
├── docs/skill-guide.md # 本文件
|
|
19
|
-
├── references/
|
|
20
|
-
│ ├── core/ # 纪律、安装、playbooks
|
|
21
|
-
│ ├── accounts/ # 账户、开户、财务
|
|
22
|
-
│ ├── google-ads/ # CLI 命令 + rules/ SOP
|
|
23
|
-
│ ├── analytics/ # 拉数、批处理、拓词
|
|
24
|
-
│ └── operations/ # 预警、线索、自动化
|
|
25
|
-
├── assets/ # JSON/MD 创建契约
|
|
26
|
-
└── report-templates/ # 报告纲要 + HTML 样式
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## 常见维护任务
|
|
30
|
-
|
|
31
|
-
| 任务 | 改哪里 |
|
|
32
|
-
| --- | --- |
|
|
33
|
-
| 新 CLI 命令 | `src/commands/` + 对应 `references/<域>/` |
|
|
34
|
-
| 新 Playbook | `references/core/playbooks.md` + `SKILL.md` 任务表 |
|
|
35
|
-
| 环境 URL | `scripts/write-defaults.mjs` + `copy-skill-assets.mjs` |
|
|
36
|
-
| 发布 Skill | `npm run build:prod` → `siluzan-tso init --force` |
|
|
37
|
-
|
|
38
|
-
## 与 eval 的关系
|
|
39
|
-
|
|
40
|
-
场景 JSON 中 `judgeReferencePaths` 须使用域路径,例如 `references/accounts/accounts.md`。改文档后运行:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
pnpm --filter siluzan-tso-cli run eval:export-cases
|
|
44
|
-
```
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
# Agent SKILL 最佳实践(siluzan-tso 维护指南)
|
|
2
|
-
|
|
3
|
-
本文档基于 [Agent Skills 开放规范](https://agentskills.io/specification) 与 [Cursor Skills 文档](https://cursor.com/docs/skills),结合 siluzan-skill monorepo 的 TSO 实践,供维护 `tso-cli/assets/siluzan-ads/` 时对照。
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. 协议要点(agentskills.io)
|
|
8
|
-
|
|
9
|
-
### 1.1 目录结构
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
siluzan-tso/ # 安装后目录名
|
|
13
|
-
├── AGENTS.md # Agent 域目录(gstack 风格)
|
|
14
|
-
├── SKILL.md.tmpl → SKILL.md # 构建生成
|
|
15
|
-
├── snippets/ # 共享注入块
|
|
16
|
-
├── docs/skill-guide.md # 人类导读
|
|
17
|
-
├── snippets/ # agent-preamble、handoff-p5/p6/p7(构建时注入 SKILL 或随包复制)
|
|
18
|
-
├── references/
|
|
19
|
-
│ ├── core/ # 纪律、安装、playbooks、subagent-orchestration
|
|
20
|
-
│ ├── accounts/ # 账户、开户、财务
|
|
21
|
-
│ ├── google-ads/ # CLI + rules/
|
|
22
|
-
│ ├── analytics/ # 拉数、批处理、拓词
|
|
23
|
-
│ └── operations/ # 预警、线索、自动化
|
|
24
|
-
├── assets/
|
|
25
|
-
└── report-templates/
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
源码位于 `tso-cli/assets/siluzan-ads/`,构建时 `copy-skill-assets.mjs` 替换占位符后写入 `dist/skill/`。
|
|
29
|
-
|
|
30
|
-
### 1.2 SKILL.md frontmatter
|
|
31
|
-
|
|
32
|
-
| 字段 | 要求 | siluzan-tso 用法 |
|
|
33
|
-
| ---- | ---- | ---------------- |
|
|
34
|
-
| `name` | 小写+连字符,≤64 字,**须与安装目录名一致** | `siluzan-tso`(非 `siluzan-ads`) |
|
|
35
|
-
| `description` | ≤1024 字,**第三人称**,含 WHAT + WHEN + 触发词 | 列出媒体、开户、Google Ads、报告、预警等 |
|
|
36
|
-
| `license` | 可选 | `MIT` |
|
|
37
|
-
| `compatibility` | 可选,≤500 字,环境依赖 | Node 18+、`siluzan-tso-cli`、鉴权 |
|
|
38
|
-
| `metadata` | 可选键值 | `requires: nodejs,siluzan-tso-cli` |
|
|
39
|
-
| `allowed-tools` | 可选(实验性) | `Bash(siluzan-tso:*) Read Write` |
|
|
40
|
-
| `disable-model-invocation` | Cursor 扩展 | TSO 需自动激活,**不设** true |
|
|
41
|
-
|
|
42
|
-
### 1.3 渐进式披露(三层加载)
|
|
43
|
-
|
|
44
|
-
| 层级 | 内容 | Token 预算建议 |
|
|
45
|
-
| ---- | ---- | -------------- |
|
|
46
|
-
| L1 元数据 | `name` + `description` | ~100 tokens,启动时索引 |
|
|
47
|
-
| L2 指令 | `SKILL.md` 正文 | <500 行,<5000 tokens,激活时加载 |
|
|
48
|
-
| L3 资源 | `references/`、`assets/`、`report-templates/` | 任务相关时才 Read |
|
|
49
|
-
|
|
50
|
-
**原则**:SKILL.md 只做路由与不可妥协的纪律;参数表、Playbook 步骤、优化 SOP 放 references。
|
|
51
|
-
|
|
52
|
-
### 1.4 文件引用规则
|
|
53
|
-
|
|
54
|
-
- 从 SKILL.md **只链接一层**(`references/foo.md`),避免 A→B→C 链式引用。
|
|
55
|
-
- 路径用正斜杠,不用 Windows 反斜杠。
|
|
56
|
-
- 占位符 `https://www-ci.siluzan.com`、`https://tso-api-ci.siluzan.com`、`npm install -g siluzan-tso-cli@beta` 由构建脚本替换,文档中禁止硬编码环境 URL。
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 2. 内容编写原则
|
|
61
|
-
|
|
62
|
-
### 2.1 简洁(Concise is Key)
|
|
63
|
-
|
|
64
|
-
Agent 已具备通用能力。文档只写 **CLI 特有** 内容:字段口径、批量命令、门禁流程、与前端不一致处。
|
|
65
|
-
|
|
66
|
-
❌ 解释「什么是 Google Ads」
|
|
67
|
-
✅ `budgetAmountYuan` 已是元,禁止再 ÷100
|
|
68
|
-
|
|
69
|
-
### 2.2 单一术语
|
|
70
|
-
|
|
71
|
-
全库统一:
|
|
72
|
-
|
|
73
|
-
| 概念 | 统一用词 | 禁止混用 |
|
|
74
|
-
| ---- | -------- | -------- |
|
|
75
|
-
| 广告账户 ID | `mediaCustomerId` | customer id、账户号(无上下文时) |
|
|
76
|
-
| 实体 ID | `entityId` | 内部 id |
|
|
77
|
-
| 落盘 | `--json-out` | --json-out ./snap(已移除) |
|
|
78
|
-
| 媒体 | `Google`、`TikTok`、`MetaAd`… | google、meta |
|
|
79
|
-
|
|
80
|
-
### 2.3 默认 + 逃生口
|
|
81
|
-
|
|
82
|
-
每个决策点给一个默认路径,例外单独一行:
|
|
83
|
-
|
|
84
|
-
```markdown
|
|
85
|
-
全量 Google 批处理:省略 `-a`(CLI 内部拉清单)。
|
|
86
|
-
仅当用户明确给出 ID 子集时才传 `-a id1,id2,...`。
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### 2.4 反馈环(Feedback Loop)
|
|
90
|
-
|
|
91
|
-
写操作文档须含:**写命令 → 读命令复核 → 失败时查 reference**。
|
|
92
|
-
|
|
93
|
-
破坏性操作统一:**用户确认 → `--commit` → 读命令验证**。
|
|
94
|
-
|
|
95
|
-
### 2.5 禁止时间敏感表述
|
|
96
|
-
|
|
97
|
-
不写「2025 年 8 月前用旧 API」。废弃内容放 `## 已废弃` 折叠或删除。
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## 3. siluzan-tso 文档分层
|
|
102
|
-
|
|
103
|
-
| 文件 | 职责 |
|
|
104
|
-
| ---- | ---- |
|
|
105
|
-
| `SKILL.md` | 安装、能力边界、文档路由表、任务→文档速查、Playbook 索引 |
|
|
106
|
-
| `references/core/agent-conventions.md` | Agent 纪律:加载时机、硬规范、数据转换、时间/币种/批量 |
|
|
107
|
-
| `references/core/playbooks.md` | P1–P7 标准动作(可复制命令块) |
|
|
108
|
-
| `references/core/subagent-orchestration.md` | 主 Agent 自主委派决策矩阵(无 `agents/` 目录) |
|
|
109
|
-
| `snippets/handoff-p*.md` | Task handoff 模板(随 skill 安装根复制) |
|
|
110
|
-
| `references/core/tips.md` | `--json-out` 协议、outline 处理顺序 |
|
|
111
|
-
| `references/*.md` | 单功能域:命令、参数、输出示例 |
|
|
112
|
-
| `references/google-ads/rules/` | Google 优化/合规 SOP(非 CLI 参数) |
|
|
113
|
-
| `assets/*.json` / `*.md` | 创建类 JSON 契约 |
|
|
114
|
-
| `report-templates/*.md` | 报告内容纲要(优先于 HTML) |
|
|
115
|
-
| `report-templates/*.html` | 视觉样式,**不含业务数据** |
|
|
116
|
-
| `README.md` | 给「通过 URL 安装」的大模型说明(不进 dist 路由) |
|
|
117
|
-
|
|
118
|
-
### 3.1 与 CLI 代码同步
|
|
119
|
-
|
|
120
|
-
**代码变更 → 必须同步 Skill**(tutorial-10 #2)。新命令注册在 `_register.ts` / `index.ts` 后:
|
|
121
|
-
|
|
122
|
-
1. 更新对应 `references/*.md`
|
|
123
|
-
2. 更新 `SKILL.md` 路由表(若新功能域)
|
|
124
|
-
3. 评估场景:`tso-cli/eval/scenarios/` + `pnpm --filter siluzan-tso-cli run eval:export-cases`
|
|
125
|
-
|
|
126
|
-
### 3.2 灰度开关(tutorial-10 #11)
|
|
127
|
-
|
|
128
|
-
| 状态 | CLI 注册 | SKILL 文档 | AI 可见 |
|
|
129
|
-
| ---- | -------- | ---------- | ------- |
|
|
130
|
-
| 内测 | 是 | 否 | 否 |
|
|
131
|
-
| 公开 | 是 | 是 | 是 |
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## 4. description 写法模板
|
|
136
|
-
|
|
137
|
-
```yaml
|
|
138
|
-
description: >-
|
|
139
|
-
Operates Siluzan TSO ad accounts via siluzan-tso-cli: Google/Bing/Yandex/TikTok/Kwai/Meta
|
|
140
|
-
account management, Google Ads CRUD, analytics, optimization reports, forewarning, leads,
|
|
141
|
-
invoicing, and RAG knowledge lookup. Use when the user mentions ad accounts, balance, spend,
|
|
142
|
-
campaigns, keywords, PMax, open account, MCC/BC binding, or TSO reporting.
|
|
143
|
-
Each new task requires re-reading routed references per SKILL.md.
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
中文项目可保留中文 description,但仍须:**第三人称 + 能力列表 + 触发场景 + 重读纪律一句**。
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## 5. 体积与质量检查清单
|
|
151
|
-
|
|
152
|
-
发布前逐项确认:
|
|
153
|
-
|
|
154
|
-
### Frontmatter
|
|
155
|
-
- [ ] `name` === 安装目录名 `siluzan-tso`
|
|
156
|
-
- [ ] `description` 含 WHAT、WHEN、关键词
|
|
157
|
-
- [ ] `compatibility` 列出 Node + CLI + 鉴权
|
|
158
|
-
|
|
159
|
-
### SKILL.md
|
|
160
|
-
- [ ] 正文 < 500 行
|
|
161
|
-
- [ ] 无重复 parameters 表(细节在 references)
|
|
162
|
-
- [ ] 路由表覆盖所有 `references/*.md` 入口
|
|
163
|
-
- [ ] Playbook 仅索引,步骤在 `core/playbooks.md`
|
|
164
|
-
|
|
165
|
-
### References
|
|
166
|
-
- [ ] 每个 CLI 命令族有且仅有一个主 reference
|
|
167
|
-
- [ ] 含 `--json-out` 示例(查询类)
|
|
168
|
-
- [ ] 写命令含 `--commit` 与复核命令
|
|
169
|
-
- [ ] 无断链(如 `accounts/open-account-by-media.md` 必须存在)
|
|
170
|
-
|
|
171
|
-
### 构建
|
|
172
|
-
- [ ] `pnpm run build:tso:test` 后 `dist/skill/SKILL.md` 占位符已替换
|
|
173
|
-
- [ ] `_meta.json` 版本与 package.json 一致
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## 6. 反模式(Avoid)
|
|
178
|
-
|
|
179
|
-
| 反模式 | 正确做法 |
|
|
180
|
-
| ------ | -------- |
|
|
181
|
-
| SKILL.md 内嵌 200 行 Playbook | 移至 `references/core/playbooks.md` |
|
|
182
|
-
| Agent 用 `--json` 落大 JSON 到对话 | 一律 `--json-out` + 脚本读盘 |
|
|
183
|
-
| 路由表缺文件 | 补文件或删链接 |
|
|
184
|
-
| google-ads-rules 深链三层 | SKILL → `google-ads/rules/README.md` → 具体规则 |
|
|
185
|
-
| HTML 模板假数据当示例 | 纲要 `.md` 定义维度,数据来自 CLI |
|
|
186
|
-
| 凭记忆跨任务复用参数 | 每任务重读 `core/agent-conventions.md` § 加载纪律 |
|
|
187
|
-
| 固定 `agents/` 与 skill 双源维护 | 用 `subagent-orchestration.md` + handoff snippets,主 Agent 自主决策 |
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
## 7. 相关仓库文档
|
|
192
|
-
|
|
193
|
-
- `.cursor/rules/tutorial-05-core/skill-authoring.mdc` — 项目内 Skill 结构速查
|
|
194
|
-
- `.cursor/rules/tutorial-10-best-practices.mdc` — CLI + Skill 同步等 12 条
|
|
195
|
-
- `cso-cli/assets/siluzan-cso/SKILL.md` — 姊妹包参考(命令索引表风格)
|
|
196
|
-
- https://agentskills.io/specification — 开放规范原文
|