siluzan-tso-cli 1.1.32 → 1.1.33-beta.2
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 +2 -1
- package/dist/index.js +213 -96
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/accounts/accounts.md +42 -8
- package/dist/skill/references/accounts/finance.md +1 -1
- package/dist/skill/references/accounts/open-account-by-media.md +1 -1
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/agent-conventions.md +1 -1
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/workflows.md +2 -1
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/references/report-templates/bing-period-report.md +1 -0
- package/dist/skill/report-templates/bing-period-report.md +1 -0
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板外部资源:**ECharts** 统一使用 `https://staticpn.siluz
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli@beta
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,6 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
> **注意**:当前为测试版(1.1.33-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
54
55
|
|
|
55
56
|
| 助手 | 建议 `--ai` |
|
|
56
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -1980,6 +1980,7 @@ import * as fs3 from "fs/promises";
|
|
|
1980
1980
|
import * as path3 from "path";
|
|
1981
1981
|
import * as fs4 from "fs/promises";
|
|
1982
1982
|
import * as path4 from "path";
|
|
1983
|
+
import { spawn as spawn2 } from "child_process";
|
|
1983
1984
|
import * as path5 from "path";
|
|
1984
1985
|
import { chmod, mkdir as mkdir3, open, readdir, stat, unlink } from "fs/promises";
|
|
1985
1986
|
import * as path6 from "path";
|
|
@@ -2933,6 +2934,60 @@ function installProcessHandlers() {
|
|
|
2933
2934
|
process.exit(1);
|
|
2934
2935
|
});
|
|
2935
2936
|
}
|
|
2937
|
+
function tryOpenHttpsUrlInBrowser(url) {
|
|
2938
|
+
try {
|
|
2939
|
+
const parsed = new URL(url);
|
|
2940
|
+
if (parsed.protocol !== "https:") {
|
|
2941
|
+
return false;
|
|
2942
|
+
}
|
|
2943
|
+
if (process.platform === "win32") {
|
|
2944
|
+
const child = spawn2("rundll32", ["url.dll,FileProtocolHandler", parsed.toString()], {
|
|
2945
|
+
detached: true,
|
|
2946
|
+
stdio: "ignore",
|
|
2947
|
+
windowsHide: true
|
|
2948
|
+
});
|
|
2949
|
+
child.unref();
|
|
2950
|
+
} else if (process.platform === "darwin") {
|
|
2951
|
+
const child = spawn2("open", [parsed.toString()], { detached: true, stdio: "ignore" });
|
|
2952
|
+
child.unref();
|
|
2953
|
+
} else {
|
|
2954
|
+
const child = spawn2("xdg-open", [parsed.toString()], { detached: true, stdio: "ignore" });
|
|
2955
|
+
child.unref();
|
|
2956
|
+
}
|
|
2957
|
+
return true;
|
|
2958
|
+
} catch {
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
function deliverMediaAccountOAuthLink(opts) {
|
|
2963
|
+
const { mediaLabel, redirectUrl, tryOpenBrowser: tryOpenBrowser2 } = opts;
|
|
2964
|
+
if (isSiluzanAgentEnv()) {
|
|
2965
|
+
console.log(
|
|
2966
|
+
`
|
|
2967
|
+
\u2139\uFE0F \u68C0\u6D4B\u5230 Siluzan Agent \u73AF\u5883\uFF08IS_SILUZAN_AGENT_ENV=true\uFF09\u3002
|
|
2968
|
+
\u8BF7\u6253\u5F00\u4EE5\u4E0B\u94FE\u63A5\u5B8C\u6210 ${mediaLabel} \u5E7F\u544A\u8D26\u6237\u6388\u6743\uFF08\u6C99\u7BB1\u5185\u4E0D\u4F1A\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF09\uFF1A
|
|
2969
|
+
|
|
2970
|
+
${redirectUrl}
|
|
2971
|
+
`
|
|
2972
|
+
);
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2975
|
+
if (tryOpenBrowser2) {
|
|
2976
|
+
const opened = tryOpenBrowser2(redirectUrl);
|
|
2977
|
+
if (opened) {
|
|
2978
|
+
console.log(`
|
|
2979
|
+
\u2705 \u5DF2\u5728\u9ED8\u8BA4\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 ${mediaLabel} \u6388\u6743\u9875\u9762\u3002`);
|
|
2980
|
+
console.log(` \u5B8C\u6210\u6388\u6743\u540E\u6D4F\u89C8\u5668\u4F1A\u81EA\u52A8\u8DF3\u56DE\u4E1D\u8DEF\u8D5E\uFF0C\u8D26\u6237\u7ED1\u5B9A\u5373\u751F\u6548\u3002
|
|
2981
|
+
`);
|
|
2982
|
+
} else {
|
|
2983
|
+
console.log(`
|
|
2984
|
+
\u26A0\uFE0F \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u4EE5\u4E0B\u94FE\u63A5\u5230\u6D4F\u89C8\u5668\u4E2D\u5B8C\u6210\u6388\u6743\uFF1A
|
|
2985
|
+
`);
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
console.log(` ${redirectUrl}
|
|
2989
|
+
`);
|
|
2990
|
+
}
|
|
2936
2991
|
function printAuthMissingHelp(binName) {
|
|
2937
2992
|
if (isSiluzanAgentEnv()) {
|
|
2938
2993
|
console.error(
|
|
@@ -3774,7 +3829,7 @@ var DEFAULT_API_BASE;
|
|
|
3774
3829
|
var init_defaults = __esm({
|
|
3775
3830
|
"src/config/defaults.ts"() {
|
|
3776
3831
|
"use strict";
|
|
3777
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
3832
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
3778
3833
|
}
|
|
3779
3834
|
});
|
|
3780
3835
|
|
|
@@ -4274,6 +4329,44 @@ function groupAccountIdsByOverviewRoute(cliMedia, accountIds, accountMediaTypes)
|
|
|
4274
4329
|
}
|
|
4275
4330
|
return groups;
|
|
4276
4331
|
}
|
|
4332
|
+
function routeToBalanceMedia(route) {
|
|
4333
|
+
if (route === "FacebookAds") return "MetaAd";
|
|
4334
|
+
if (BALANCE_SUPPORTED_MEDIA.includes(route)) {
|
|
4335
|
+
return route;
|
|
4336
|
+
}
|
|
4337
|
+
return null;
|
|
4338
|
+
}
|
|
4339
|
+
function applyRealtimeBalanceIfNeeded(item, bal) {
|
|
4340
|
+
if (bal == null || typeof bal.remainingAccountBudget !== "number") return;
|
|
4341
|
+
if (bal.remainingAccountBudget > 0) {
|
|
4342
|
+
item.remainingAccountBudget = bal.remainingAccountBudget;
|
|
4343
|
+
}
|
|
4344
|
+
if (bal.currencyCode) item.currencyCode = bal.currencyCode;
|
|
4345
|
+
if (bal.status) item.status = bal.status;
|
|
4346
|
+
}
|
|
4347
|
+
async function overlayRealtimeBalanceOnOverviewMap(route, overviewMap, config, verbose) {
|
|
4348
|
+
const media = routeToBalanceMedia(route);
|
|
4349
|
+
if (!media || overviewMap.size === 0) return;
|
|
4350
|
+
const ids = [...overviewMap.keys()];
|
|
4351
|
+
const balanceMap = await fetchBalanceMap(media, ids, config, void 0, void 0, verbose);
|
|
4352
|
+
for (const [id, item] of overviewMap) {
|
|
4353
|
+
applyRealtimeBalanceIfNeeded(item, balanceMap.get(id));
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
async function enrichOverviewRecordWithRealtimeBalance(media, accountId, config, record, verbose) {
|
|
4357
|
+
if (!BALANCE_SUPPORTED_MEDIA.includes(media)) {
|
|
4358
|
+
return record;
|
|
4359
|
+
}
|
|
4360
|
+
const balanceMap = await fetchBalanceMap(media, [accountId], config, void 0, void 0, verbose);
|
|
4361
|
+
const bal = balanceMap.get(accountId);
|
|
4362
|
+
if (bal == null) return record;
|
|
4363
|
+
const out = { ...record };
|
|
4364
|
+
applyRealtimeBalanceIfNeeded(out, bal);
|
|
4365
|
+
if (bal.name && out["accountName"] == null && out["mediaCustomerName"] == null) {
|
|
4366
|
+
out["mediaCustomerName"] = bal.name;
|
|
4367
|
+
}
|
|
4368
|
+
return out;
|
|
4369
|
+
}
|
|
4277
4370
|
async function fetchBalanceMap(media, accountIds, config, startDate, endDate, verbose) {
|
|
4278
4371
|
const result = /* @__PURE__ */ new Map();
|
|
4279
4372
|
if (accountIds.length === 0) return result;
|
|
@@ -4407,70 +4500,73 @@ async function fetchOverviewMap(route, accountIds, config, startDate, endDate, v
|
|
|
4407
4500
|
for (const row of rows) {
|
|
4408
4501
|
result.set(row.mediaAccountId, row);
|
|
4409
4502
|
}
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4503
|
+
} else {
|
|
4504
|
+
const fetchLegacyBatch = async (ids) => {
|
|
4505
|
+
const batch = /* @__PURE__ */ new Map();
|
|
4506
|
+
const params = new URLSearchParams({
|
|
4507
|
+
period: "true",
|
|
4508
|
+
startDate: start,
|
|
4509
|
+
endDate: end,
|
|
4510
|
+
mediaCustomerIds: ids.join(",")
|
|
4511
|
+
});
|
|
4512
|
+
const url = `${config.apiBaseUrl}/report/media-account/${route}/accountsoverview?${params}`;
|
|
4513
|
+
const raw = await apiFetch2(url, config, {}, verbose);
|
|
4514
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
4515
|
+
for (const item of items) {
|
|
4516
|
+
if (item.mediaAccountId != null) {
|
|
4517
|
+
batch.set(String(item.mediaAccountId), item);
|
|
4518
|
+
}
|
|
4426
4519
|
}
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
process.stderr.write(
|
|
4447
|
-
`[fetchOverviewMap] \u9010\u6237\u91CD\u8BD5\u5931\u8D25 ${id}\uFF1A${singleErr instanceof Error ? singleErr.message : String(singleErr)}
|
|
4520
|
+
return batch;
|
|
4521
|
+
};
|
|
4522
|
+
const mergeOverview = (batch) => {
|
|
4523
|
+
for (const [k, v] of batch) result.set(k, v);
|
|
4524
|
+
};
|
|
4525
|
+
if (accountIds.length === 1) {
|
|
4526
|
+
mergeOverview(await fetchLegacyBatch(accountIds));
|
|
4527
|
+
} else {
|
|
4528
|
+
try {
|
|
4529
|
+
const batch = await fetchLegacyBatch(accountIds);
|
|
4530
|
+
mergeOverview(batch);
|
|
4531
|
+
if (batch.size === 0) {
|
|
4532
|
+
for (const id of accountIds) {
|
|
4533
|
+
try {
|
|
4534
|
+
mergeOverview(await fetchLegacyBatch([id]));
|
|
4535
|
+
} catch (singleErr) {
|
|
4536
|
+
if (verbose) {
|
|
4537
|
+
process.stderr.write(
|
|
4538
|
+
`[fetchOverviewMap] \u9010\u6237\u91CD\u8BD5\u5931\u8D25 ${id}\uFF1A${singleErr instanceof Error ? singleErr.message : String(singleErr)}
|
|
4448
4539
|
`
|
|
4449
|
-
|
|
4540
|
+
);
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4450
4543
|
}
|
|
4451
4544
|
}
|
|
4452
|
-
}
|
|
4453
|
-
}
|
|
4454
|
-
} catch (err) {
|
|
4455
|
-
if (verbose) {
|
|
4456
|
-
process.stderr.write(
|
|
4457
|
-
`[fetchOverviewMap] \u6279\u91CF\u5F02\u5E38\uFF0C\u9010\u6237\u91CD\u8BD5\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
4458
|
-
`
|
|
4459
|
-
);
|
|
4460
|
-
}
|
|
4461
|
-
for (const id of accountIds) {
|
|
4462
|
-
try {
|
|
4463
|
-
mergeOverview(await fetchLegacyBatch([id]));
|
|
4464
|
-
} catch (singleErr) {
|
|
4545
|
+
} catch (err) {
|
|
4465
4546
|
if (verbose) {
|
|
4466
4547
|
process.stderr.write(
|
|
4467
|
-
`[fetchOverviewMap] \u9010\u6237\u91CD\u8BD5\
|
|
4548
|
+
`[fetchOverviewMap] \u6279\u91CF\u5F02\u5E38\uFF0C\u9010\u6237\u91CD\u8BD5\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
4468
4549
|
`
|
|
4469
4550
|
);
|
|
4470
4551
|
}
|
|
4552
|
+
for (const id of accountIds) {
|
|
4553
|
+
try {
|
|
4554
|
+
mergeOverview(await fetchLegacyBatch([id]));
|
|
4555
|
+
} catch (singleErr) {
|
|
4556
|
+
if (verbose) {
|
|
4557
|
+
process.stderr.write(
|
|
4558
|
+
`[fetchOverviewMap] \u9010\u6237\u91CD\u8BD5\u5931\u8D25 ${id}\uFF1A${singleErr instanceof Error ? singleErr.message : String(singleErr)}
|
|
4559
|
+
`
|
|
4560
|
+
);
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4471
4564
|
}
|
|
4472
4565
|
}
|
|
4473
4566
|
}
|
|
4567
|
+
if (result.size > 0) {
|
|
4568
|
+
await overlayRealtimeBalanceOnOverviewMap(route, result, config, verbose);
|
|
4569
|
+
}
|
|
4474
4570
|
} catch (err) {
|
|
4475
4571
|
if (verbose) {
|
|
4476
4572
|
process.stderr.write(
|
|
@@ -106155,11 +106251,15 @@ async function runStats(opts) {
|
|
|
106155
106251
|
}
|
|
106156
106252
|
}
|
|
106157
106253
|
} else {
|
|
106158
|
-
const
|
|
106159
|
-
|
|
106160
|
-
|
|
106161
|
-
|
|
106162
|
-
|
|
106254
|
+
const map = await fetchOverviewMap(
|
|
106255
|
+
opts.media,
|
|
106256
|
+
ids,
|
|
106257
|
+
config,
|
|
106258
|
+
startDate,
|
|
106259
|
+
endDate,
|
|
106260
|
+
opts.verbose
|
|
106261
|
+
);
|
|
106262
|
+
items = [...map.values()];
|
|
106163
106263
|
}
|
|
106164
106264
|
} catch (err) {
|
|
106165
106265
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -107693,6 +107793,7 @@ async function fetchBingJson(config, url, verbose) {
|
|
|
107693
107793
|
|
|
107694
107794
|
// src/commands/report-bing-analysis/run.ts
|
|
107695
107795
|
init_auth();
|
|
107796
|
+
init_balance();
|
|
107696
107797
|
async function runReportBingOverview(opts) {
|
|
107697
107798
|
const id = assertBingAccountId(opts.account);
|
|
107698
107799
|
const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end);
|
|
@@ -107700,7 +107801,14 @@ async function runReportBingOverview(opts) {
|
|
|
107700
107801
|
const params = new URLSearchParams({ startDate, endDate });
|
|
107701
107802
|
const url = reportingUrl2(config, id, "OverviewSectionData", params.toString());
|
|
107702
107803
|
try {
|
|
107703
|
-
const
|
|
107804
|
+
const raw = await fetchBingJson(config, url, !!opts.verbose);
|
|
107805
|
+
const data = raw && typeof raw === "object" && !Array.isArray(raw) ? await enrichOverviewRecordWithRealtimeBalance(
|
|
107806
|
+
"BingV2",
|
|
107807
|
+
id,
|
|
107808
|
+
config,
|
|
107809
|
+
raw,
|
|
107810
|
+
opts.verbose
|
|
107811
|
+
) : raw;
|
|
107704
107812
|
if (opts.jsonOut) {
|
|
107705
107813
|
await emitBingSnapshot(opts, "bing-overview", id, startDate, endDate, data);
|
|
107706
107814
|
return;
|
|
@@ -120909,35 +121017,11 @@ async function runAccountShareDetail(opts) {
|
|
|
120909
121017
|
|
|
120910
121018
|
// src/commands/account-manage/oauth.ts
|
|
120911
121019
|
init_auth();
|
|
120912
|
-
|
|
121020
|
+
init_dist();
|
|
120913
121021
|
function toApiMediaType(media) {
|
|
120914
121022
|
return media === "Meta" ? "FacebookAds" : media;
|
|
120915
121023
|
}
|
|
120916
|
-
|
|
120917
|
-
try {
|
|
120918
|
-
const parsed = new URL(url);
|
|
120919
|
-
if (parsed.protocol !== "https:") {
|
|
120920
|
-
return false;
|
|
120921
|
-
}
|
|
120922
|
-
if (process.platform === "win32") {
|
|
120923
|
-
const child = spawn2("rundll32", ["url.dll,FileProtocolHandler", parsed.toString()], {
|
|
120924
|
-
detached: true,
|
|
120925
|
-
stdio: "ignore",
|
|
120926
|
-
windowsHide: true
|
|
120927
|
-
});
|
|
120928
|
-
child.unref();
|
|
120929
|
-
} else if (process.platform === "darwin") {
|
|
120930
|
-
const child = spawn2("open", [parsed.toString()], { detached: true, stdio: "ignore" });
|
|
120931
|
-
child.unref();
|
|
120932
|
-
} else {
|
|
120933
|
-
const child = spawn2("xdg-open", [parsed.toString()], { detached: true, stdio: "ignore" });
|
|
120934
|
-
child.unref();
|
|
120935
|
-
}
|
|
120936
|
-
return true;
|
|
120937
|
-
} catch {
|
|
120938
|
-
return false;
|
|
120939
|
-
}
|
|
120940
|
-
}
|
|
121024
|
+
var tryOpenBrowser = tryOpenHttpsUrlInBrowser;
|
|
120941
121025
|
async function runAccountAuth(opts) {
|
|
120942
121026
|
const config = loadConfig(opts.token);
|
|
120943
121027
|
const apiMediaType = toApiMediaType(opts.media);
|
|
@@ -120963,17 +121047,32 @@ async function runAccountAuth(opts) {
|
|
|
120963
121047
|
`);
|
|
120964
121048
|
process.exit(1);
|
|
120965
121049
|
}
|
|
120966
|
-
|
|
120967
|
-
|
|
120968
|
-
|
|
120969
|
-
|
|
120970
|
-
|
|
120971
|
-
|
|
120972
|
-
|
|
120973
|
-
|
|
121050
|
+
deliverMediaAccountOAuthLink({
|
|
121051
|
+
mediaLabel: opts.media,
|
|
121052
|
+
redirectUrl,
|
|
121053
|
+
tryOpenBrowser: tryOpenHttpsUrlInBrowser
|
|
121054
|
+
});
|
|
121055
|
+
}
|
|
121056
|
+
async function runAccountReauth(opts) {
|
|
121057
|
+
if (!opts.id && (!opts.ids || opts.ids.length === 0)) {
|
|
121058
|
+
console.error(
|
|
121059
|
+
"\n\u274C \u91CD\u65B0\u6388\u6743\u987B\u6307\u5B9A\u8981\u89E3\u7ED1\u7684\u8D26\u6237 entityId\uFF1A--id <entityId> \u6216 --ids id1,id2\n entityId \u6765\u81EA list-accounts --json-out \u7684 ma.entityId\uFF08\u4E0D\u662F mediaCustomerId\uFF09\n"
|
|
121060
|
+
);
|
|
121061
|
+
process.exit(1);
|
|
120974
121062
|
}
|
|
120975
|
-
console.log(
|
|
120976
|
-
|
|
121063
|
+
console.log("\n\u6B65\u9AA4 1/2\uFF1A\u65AD\u5F00\u5173\u8054\uFF08\u91CD\u65B0\u6388\u6743\u524D\u5FC5\u987B\u5148\u89E3\u7ED1\uFF0C\u5BF9\u9F50\u7F51\u9875\u300C\u91CD\u65B0\u6388\u6743\u300D\uFF09\u2026\n");
|
|
121064
|
+
await runAccountDelink({
|
|
121065
|
+
token: opts.token,
|
|
121066
|
+
id: opts.id,
|
|
121067
|
+
ids: opts.ids,
|
|
121068
|
+
verbose: opts.verbose
|
|
121069
|
+
});
|
|
121070
|
+
console.log("\u6B65\u9AA4 2/2\uFF1A\u53D1\u8D77 OAuth \u6388\u6743\u2026\n");
|
|
121071
|
+
await runAccountAuth({
|
|
121072
|
+
token: opts.token,
|
|
121073
|
+
media: opts.media,
|
|
121074
|
+
verbose: opts.verbose
|
|
121075
|
+
});
|
|
120977
121076
|
}
|
|
120978
121077
|
|
|
120979
121078
|
// src/commands/account-manage/google-mcc.ts
|
|
@@ -121934,12 +122033,30 @@ function register23(program2) {
|
|
|
121934
122033
|
});
|
|
121935
122034
|
}
|
|
121936
122035
|
);
|
|
121937
|
-
accountCmd.command("auth").description(
|
|
122036
|
+
accountCmd.command("auth").description(
|
|
122037
|
+
"\u6DFB\u52A0\u6388\u6743\uFF1A\u9996\u6B21\u7ED1\u5B9A\u5A92\u4F53\u8D26\u6237 OAuth\uFF08\u7F51\u9875 manageAccounts\u300C\u6DFB\u52A0\u6388\u6743\u300D\uFF09\uFF1BOAuth \u5931\u6548\u8BF7\u7528 reauth"
|
|
122038
|
+
).requiredOption(
|
|
121938
122039
|
"-m, --media <type>",
|
|
121939
122040
|
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Meta | Yandex | BingV2 | Kwai"
|
|
121940
122041
|
).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
121941
122042
|
await runAccountAuth({ token: opts.token, media: opts.media, verbose: opts.verbose });
|
|
121942
122043
|
});
|
|
122044
|
+
accountCmd.command("reauth").description(
|
|
122045
|
+
"\u91CD\u65B0\u6388\u6743\uFF1A\u5148\u89E3\u7ED1\u518D OAuth\uFF08\u7F51\u9875 manageAccounts\u300C\u91CD\u65B0\u6388\u6743\u300D\uFF1BinvalidOAuthToken \u5931\u6548\u65F6\u5FC5\u8D70\u6B64\u547D\u4EE4\uFF09"
|
|
122046
|
+
).requiredOption(
|
|
122047
|
+
"-m, --media <type>",
|
|
122048
|
+
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Meta | Yandex | BingV2 | Kwai"
|
|
122049
|
+
).option("--id <entityId>", "\u5355\u4E2A\u8D26\u6237 entityId\uFF08\u6765\u81EA list-accounts \u7684 ma.entityId\uFF09").option("--ids <entityIds>", "\u6279\u91CF entityId\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u4E0E --id \u4E8C\u9009\u4E00\uFF0C\u53EF\u540C\u65F6\u4F20\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
|
|
122050
|
+
async (opts) => {
|
|
122051
|
+
await runAccountReauth({
|
|
122052
|
+
token: opts.token,
|
|
122053
|
+
media: opts.media,
|
|
122054
|
+
id: opts.id,
|
|
122055
|
+
ids: opts.ids ? opts.ids.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
|
|
122056
|
+
verbose: opts.verbose
|
|
122057
|
+
});
|
|
122058
|
+
}
|
|
122059
|
+
);
|
|
121943
122060
|
accountCmd.command("mcc-bind").description("Google\uFF1A\u5C06\u5B50\u8D26\u6237\u7ED1\u5B9A\u5230\u7ECF\u7406\u8D26\u6237\uFF08MCC\uFF09\uFF0C\u9700\u5DF2\u914D\u7F6E googleApiUrl").requiredOption(
|
|
121944
122061
|
"--customers <ids>",
|
|
121945
122062
|
"\u5B50\u8D26\u6237 mediaCustomerId\uFF0C\u591A\u4E2A\u9017\u53F7\u5206\u9694\uFF08\u6765\u81EA list-accounts \u7684 ma.mediaCustomerId\uFF09"
|
package/dist/skill/_meta.json
CHANGED
|
@@ -280,7 +280,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
|
|
|
280
280
|
| 状态 | 含义 | 下一步操作 |
|
|
281
281
|
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
282
282
|
| `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
|
|
283
|
-
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
|
|
283
|
+
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
|
|
284
284
|
| `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
|
|
285
285
|
|
|
286
286
|
---
|
|
@@ -307,9 +307,11 @@ siluzan-tso account me --check-phone 15130150466 --json-out ./snap-me
|
|
|
307
307
|
|
|
308
308
|
---
|
|
309
309
|
|
|
310
|
-
### auth — 添加媒体平台 OAuth
|
|
310
|
+
### auth — 添加媒体平台 OAuth 授权(首次绑定)
|
|
311
311
|
|
|
312
|
-
在浏览器中打开对应媒体的 OAuth
|
|
312
|
+
在浏览器中打开对应媒体的 OAuth 授权页面,授权后账户自动绑定到丝路赞。对应网页 **「添加授权」**。
|
|
313
|
+
|
|
314
|
+
> **OAuth 已失效**(`invalidOAuthToken=true`)时**不要**用本命令,须走下方 **`reauth`**(重新授权必须先解绑)。
|
|
313
315
|
|
|
314
316
|
```bash
|
|
315
317
|
siluzan-tso account auth -m <媒体类型>
|
|
@@ -322,13 +324,13 @@ siluzan-tso account auth -m <媒体类型>
|
|
|
322
324
|
**示例:**
|
|
323
325
|
|
|
324
326
|
```bash
|
|
325
|
-
#
|
|
327
|
+
# 首次授权 Google Ads 账户
|
|
326
328
|
siluzan-tso account auth -m Google
|
|
327
329
|
|
|
328
|
-
#
|
|
330
|
+
# 首次授权 TikTok Ads 账户
|
|
329
331
|
siluzan-tso account auth -m TikTok
|
|
330
332
|
|
|
331
|
-
#
|
|
333
|
+
# 首次授权 Meta(Facebook)Ads 账户
|
|
332
334
|
siluzan-tso account auth -m Meta
|
|
333
335
|
```
|
|
334
336
|
|
|
@@ -336,6 +338,38 @@ siluzan-tso account auth -m Meta
|
|
|
336
338
|
|
|
337
339
|
---
|
|
338
340
|
|
|
341
|
+
### reauth — 重新授权(先解绑再 OAuth)
|
|
342
|
+
|
|
343
|
+
OAuth 失效时恢复授权。对齐 TSO 网页 **「重新授权」**:程序会先 **delink** 断开关联,再跳转媒体 OAuth。**禁止**对失效账户跳过解绑直接用 `account auth`。
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
siluzan-tso account reauth -m <媒体类型> --id <entityId>
|
|
347
|
+
siluzan-tso account reauth -m Google --ids <id1,id2>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| 选项 | 说明 |
|
|
351
|
+
| -------------------- | ------------------------------------------------------------------------ |
|
|
352
|
+
| `-m, --media <type>` | 媒体类型(必填) |
|
|
353
|
+
| `--id <entityId>` | 单个账户 `entityId`(来自 `list-accounts` 的 `ma.entityId`) |
|
|
354
|
+
| `--ids <id1,id2>` | 批量 `entityId`,逗号分隔(与 `--id` 二选一) |
|
|
355
|
+
|
|
356
|
+
**示例:**
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# 1. 查失效账户的 entityId
|
|
360
|
+
siluzan-tso list-accounts -m Google --json-out ./snap
|
|
361
|
+
|
|
362
|
+
# 2. 重新授权(内置 delink → OAuth)
|
|
363
|
+
siluzan-tso account reauth -m Google --id abc123def456
|
|
364
|
+
|
|
365
|
+
# 3. 验证
|
|
366
|
+
siluzan-tso list-accounts -m Google
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
> 手动两步等价于 `reauth`:`account delink --id …` → `account auth -m …`(须用户确认解绑风险)。
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
339
373
|
### delink — 解除授权 / 断开账户关联
|
|
340
374
|
|
|
341
375
|
从当前丝路赞账号下移除媒体账户绑定。
|
|
@@ -854,7 +888,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
854
888
|
|
|
855
889
|
| 功能 | 媒体 | 网页路径 |
|
|
856
890
|
| --------------------------------------- | ------ | ------------------------------------------------- |
|
|
857
|
-
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
891
|
+
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
858
892
|
|
|
859
893
|
**Agent 建议话术**:
|
|
860
894
|
|
|
@@ -863,5 +897,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
863
897
|
siluzan-tso config show # 查看 webUrl 字段
|
|
864
898
|
|
|
865
899
|
# 账户激活(Google)→ 引导至账户管理页
|
|
866
|
-
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
900
|
+
# https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
867
901
|
```
|
|
@@ -117,7 +117,7 @@ siluzan-tso config show
|
|
|
117
117
|
|
|
118
118
|
### 充值页链接(按媒体 × 类型)
|
|
119
119
|
|
|
120
|
-
链接模式:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
|
|
120
|
+
链接模式:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
|
|
121
121
|
|
|
122
122
|
| 充值类型 | `<page>` | 支持媒体(`mediaType` 参数) |
|
|
123
123
|
| ------------------------- | --------------------- | ------------------------------------------- |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 各媒体开户
|
|
2
2
|
|
|
3
|
-
> 网页链接:`https://www.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
|
|
3
|
+
> 网页链接:`https://www-ci.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
|
|
4
4
|
> 多命令串联见 `references/core/workflows.md` § 流程一。
|
|
5
5
|
|
|
6
6
|
## 首次响应硬规范(必读)
|
|
@@ -60,7 +60,7 @@ siluzan-tso open-account google-wizard
|
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
62
|
siluzan-tso account-history -m Google
|
|
63
|
-
# 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
63
|
+
# 审核通过后:config show → https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
---
|
|
@@ -192,9 +192,9 @@ siluzan-tso report push receive-emails -m Google [--json-out ./snap]
|
|
|
192
192
|
|
|
193
193
|
| 媒体 | 报告类型 | URL 模板 |
|
|
194
194
|
| ------ | ---------------- | ----------------------------------------------------------- |
|
|
195
|
-
| Google | 日报(Daily) | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
196
|
-
| Google | 小时报(Hourly) | `https://www.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
|
|
197
|
-
| TikTok | 日报 | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
195
|
+
| Google | 日报(Daily) | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
196
|
+
| Google | 小时报(Hourly) | `https://www-ci.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
|
|
197
|
+
| TikTok | 日报 | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
198
198
|
|
|
199
199
|
`entityId` 来自 `siluzan-tso report list --json-out ./snap` 中每条记录的 `entityId` 字段。
|
|
200
200
|
|
|
@@ -207,8 +207,8 @@ siluzan-tso report list -m Google --json-out ./snap
|
|
|
207
207
|
|
|
208
208
|
# 第二步:查看 webUrl
|
|
209
209
|
siluzan-tso config show
|
|
210
|
-
# webUrl: https://www.siluzan.com
|
|
210
|
+
# webUrl: https://www-ci.siluzan.com
|
|
211
211
|
|
|
212
212
|
# 第三步:拼接链接(Google 日报)
|
|
213
|
-
# https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
213
|
+
# https://www-ci.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
214
214
|
```
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
## 十一、常见 HTTP 状态码
|
|
220
220
|
|
|
221
221
|
- **400**:参数错误,查看对应 reference 或 `-h`
|
|
222
|
-
- **401
|
|
222
|
+
- **401**:媒体 OAuth 失效 → `account reauth -m <媒体> --id <entityId>`(须先 delink,见 W9);**丝路赞登录凭据失效** → `send-login-code` + `login --phone --code`,见 `references/core/setup.md`
|
|
223
223
|
- **500**:服务可能正在部署/升级,建议反馈 Siluzan 相关人员
|
|
224
224
|
|
|
225
225
|
---
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
## 安装 CLI
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g siluzan-tso-cli
|
|
13
|
+
npm install -g siluzan-tso-cli@beta
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -64,7 +64,7 @@ siluzan-tso config set --api-key <Key> # 或 config 直接写入
|
|
|
64
64
|
siluzan-tso config set --token <Token> # 备用:设置 JWT Token
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
API Key 获取入口:`https://www.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
|
|
67
|
+
API Key 获取入口:`https://www-ci.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
70
|
# 第 1 步:让用户报出手机号后,立刻发码(命令立即返回,不会等待输入)
|
|
@@ -129,9 +129,9 @@ siluzan-tso config show
|
|
|
129
129
|
|
|
130
130
|
```
|
|
131
131
|
构建环境 : production
|
|
132
|
-
apiBaseUrl : https://tso-api.siluzan.com
|
|
133
|
-
googleApiUrl : https://googleapi.mysiluzan.com
|
|
134
|
-
webUrl : https://www.siluzan.com
|
|
132
|
+
apiBaseUrl : https://tso-api-ci.siluzan.com
|
|
133
|
+
googleApiUrl : https://googleapi-ci.mysiluzan.com
|
|
134
|
+
webUrl : https://www-ci.siluzan.com
|
|
135
135
|
apiKey : abcd****1234
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -152,7 +152,8 @@
|
|
|
152
152
|
- **步骤(按场景)**:
|
|
153
153
|
- **分享**:`list-accounts --json-out` 取 `entityId` → `account share --id <entityId> --phone <手机号>`;查 `account share-detail --customer-id <mediaCustomerId>`;取消 `account unshare --id <entityId> --account-id <userId>`。
|
|
154
154
|
- **解绑**:`account delink --id <entityId>` / `--ids id1,id2`。
|
|
155
|
-
- **OAuth 重授权**:`invalidOAuthToken=true` → `account
|
|
155
|
+
- **OAuth 重授权**:`invalidOAuthToken=true` → `list-accounts --json-out` 取 `ma.entityId` → **`account reauth -m <媒体> --id <entityId>`**(内置先 delink 再 OAuth,对齐网页「重新授权」)→ `list-accounts` 验证。**禁止**对失效账户直接用 `account auth`(首次「添加授权」专用)。
|
|
156
|
+
- **首次 OAuth 添加授权**:`account auth -m <媒体>`(无需先 delink)。
|
|
156
157
|
- **MCC**:`account mcc-bind --customers <mediaCustomerId,...> --mcc <MCC客户ID>` / `mcc-unbind`(走 `googleApiUrl`,先 `config show`)。
|
|
157
158
|
- **BC(TikTok)**:`account bc-bind --customers <id> --bc-ids <id>` / `bc-unbind --bc-id <id>`(解绑一次一个)。
|
|
158
159
|
- **BM(Meta)**:`account bm-bind --account-id <mediaCustomerId> --bm-id <bmId>`。
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
siluzan-tso config show # 取 webUrl
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
首页地址:`https://www.siluzan.com/v3/foreign_trade/tso/home`
|
|
9
|
+
首页地址:`https://www-ci.siluzan.com/v3/foreign_trade/tso/home`
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -25,7 +25,7 @@ siluzan-tso config show # 取 webUrl
|
|
|
25
25
|
|
|
26
26
|
## 推荐话术
|
|
27
27
|
|
|
28
|
-
1. **「和首页一样的总览」** → 打开 `https://www.siluzan.com/v3/foreign_trade/tso/home`。
|
|
28
|
+
1. **「和首页一样的总览」** → 打开 `https://www-ci.siluzan.com/v3/foreign_trade/tso/home`。
|
|
29
29
|
2. **「某个 Google 账户昨天花了多少」** → `list-accounts -m Google` + `stats -m Google -a <id>`。
|
|
30
30
|
3. **「有待充值账户」** → 说明聚合数据在首页;CLI 可 `list-accounts` + `balance` 逐户排查,或引导充值页。
|
|
31
31
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
## 1. 执行摘要(总览)
|
|
19
19
|
|
|
20
20
|
- **CLI**:`siluzan-tso report bing-overview -a <mediaCustomerId> [--start … --end …] --json-out <dir>`
|
|
21
|
+
- **余额**:若 `OverviewSectionData` 误返 `remainingAccountBudget: 0`,CLI 会自动用 `GetMediaAccountInfo` 实时余额回填(与 Web 账户列表一致);**仍建议**单查余额用 `balance -m BingV2`。
|
|
21
22
|
|
|
22
23
|
## 2. 设备与地域
|
|
23
24
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
## 1. 执行摘要(总览)
|
|
19
19
|
|
|
20
20
|
- **CLI**:`siluzan-tso report bing-overview -a <mediaCustomerId> [--start … --end …] --json-out <dir>`
|
|
21
|
+
- **余额**:若 `OverviewSectionData` 误返 `remainingAccountBudget: 0`,CLI 会自动用 `GetMediaAccountInfo` 实时余额回填(与 Web 账户列表一致);**仍建议**单查余额用 `balance -m BingV2`。
|
|
21
22
|
|
|
22
23
|
## 2. 设备与地域
|
|
23
24
|
|
|
@@ -9,11 +9,11 @@ $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.
|
|
12
|
+
$PKG_VERSION = '1.1.33-beta.2'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
|
-
$INSTALL_CMD = 'npm install -g siluzan-tso-cli'
|
|
16
|
-
$WEB_BASE = 'https://www.siluzan.com'
|
|
15
|
+
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
16
|
+
$WEB_BASE = 'https://www-ci.siluzan.com'
|
|
17
17
|
|
|
18
18
|
# -- Constants ----------------------------------------------------------------
|
|
19
19
|
$NODE_MAJOR_MIN = 18
|
|
@@ -9,11 +9,11 @@ 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.
|
|
12
|
+
readonly PKG_VERSION="1.1.33-beta.2"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
|
-
readonly INSTALL_CMD="npm install -g siluzan-tso-cli"
|
|
16
|
-
readonly WEB_BASE="https://www.siluzan.com"
|
|
15
|
+
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|
|
16
|
+
readonly WEB_BASE="https://www-ci.siluzan.com"
|
|
17
17
|
|
|
18
18
|
# -- Constants ----------------------------------------------------------------
|
|
19
19
|
readonly NODE_MAJOR_MIN=18
|