siluzan-tso-cli 1.1.53-beta.8 → 1.1.53-beta.9
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 +105 -75
- package/dist/skill/SKILL.md +2 -2
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/accounts/accounts-list.md +3 -3
- package/dist/skill/references/accounts/accounts.md +1 -1
- package/dist/skill/references/core/agent-conventions.md +1 -1
- package/dist/skill/references/core/playbooks.md +1 -1
- package/dist/skill/references/report-templates/okki-weekly-google-client.md +1 -1
- package/dist/skill/report-templates/okki-weekly-google-client.md +1 -1
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/eval/cases/accounts-google-cid-hyphen-must-keyword.scenario.json +26 -0
- 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.53-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.53-beta.9),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -4479,6 +4479,78 @@ var init_cli_json_snapshot = __esm({
|
|
|
4479
4479
|
}
|
|
4480
4480
|
});
|
|
4481
4481
|
|
|
4482
|
+
// src/utils/media-customer-id.ts
|
|
4483
|
+
function stripMediaCustomerIdDecorators(raw) {
|
|
4484
|
+
return raw.trim().replace(/[\s-]+/g, "");
|
|
4485
|
+
}
|
|
4486
|
+
function looksLikeNumericMediaCustomerId(raw) {
|
|
4487
|
+
return /^\d+$/.test(stripMediaCustomerIdDecorators(raw));
|
|
4488
|
+
}
|
|
4489
|
+
function mediaCustomerIdsEqual(left, right) {
|
|
4490
|
+
const a = left.trim();
|
|
4491
|
+
const b = right.trim();
|
|
4492
|
+
if (!a || !b) return false;
|
|
4493
|
+
if (a === b) return true;
|
|
4494
|
+
const na = normalizeNumericMediaCustomerId(a);
|
|
4495
|
+
const nb = normalizeNumericMediaCustomerId(b);
|
|
4496
|
+
return na != null && nb != null && na === nb;
|
|
4497
|
+
}
|
|
4498
|
+
function normalizeNumericMediaCustomerId(raw) {
|
|
4499
|
+
if (!looksLikeNumericMediaCustomerId(raw)) return null;
|
|
4500
|
+
return stripMediaCustomerIdDecorators(raw);
|
|
4501
|
+
}
|
|
4502
|
+
function requireNumericMediaCustomerId(raw, label = "-a, --account") {
|
|
4503
|
+
const trimmed = raw?.toString().trim() ?? "";
|
|
4504
|
+
if (!trimmed) {
|
|
4505
|
+
throw new Error(`\u8BF7\u6307\u5B9A\u5A92\u4F53\u8D26\u6237 ID\uFF08${label}\uFF09`);
|
|
4506
|
+
}
|
|
4507
|
+
const id = normalizeNumericMediaCustomerId(trimmed);
|
|
4508
|
+
if (!id) {
|
|
4509
|
+
throw new Error(
|
|
4510
|
+
`\u5A92\u4F53\u8D26\u6237 ID \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF08Google CID \u53EF\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 123-456-7890\uFF1B\u52FF\u4F20 entityId/UUID\uFF09\uFF1A${trimmed}`
|
|
4511
|
+
);
|
|
4512
|
+
}
|
|
4513
|
+
return id;
|
|
4514
|
+
}
|
|
4515
|
+
function looksLikeEntityIdUuid(raw) {
|
|
4516
|
+
return ENTITY_ID_UUID_RE.test(raw.trim());
|
|
4517
|
+
}
|
|
4518
|
+
function warnIfAccountIdsLookLikeEntityId(ids, command) {
|
|
4519
|
+
const bad = ids.map((id) => id.trim()).filter((id) => id && looksLikeEntityIdUuid(id));
|
|
4520
|
+
if (bad.length === 0) return;
|
|
4521
|
+
console.error(
|
|
4522
|
+
`
|
|
4523
|
+
\u26A0\uFE0F ${command} \u7684 -a/--accounts \u6536\u5230\u7591\u4F3C entityId/UUID\uFF1A${bad.join(", ")}
|
|
4524
|
+
\u672C\u547D\u4EE4\u9700\u8981 mediaCustomerId\uFF08list-accounts \u7684 ma.mediaCustomerId\uFF1BYandex \u5F62\u5982 porg-\u2026\uFF09\u3002
|
|
4525
|
+
\u8BF7\u5148 list-accounts -m <\u5A92\u4F53> -k <\u5A92\u4F53\u8D26\u6237\u53F7> \u6838\u5BF9\u540E\u518D\u91CD\u8BD5\uFF1B\u52FF\u636E\u6B64\u76F4\u63A5 reauth\u3002
|
|
4526
|
+
`
|
|
4527
|
+
);
|
|
4528
|
+
}
|
|
4529
|
+
function parseNumericMediaCustomerIds(input) {
|
|
4530
|
+
if (!input || !input.trim()) return [];
|
|
4531
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4532
|
+
const out = [];
|
|
4533
|
+
for (const raw of input.split(",")) {
|
|
4534
|
+
const piece = raw.trim();
|
|
4535
|
+
if (!piece) continue;
|
|
4536
|
+
const id = normalizeNumericMediaCustomerId(piece);
|
|
4537
|
+
if (!id) {
|
|
4538
|
+
throw new Error(`mediaCustomerId \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF08\u53EF\u542B\u8FDE\u5B57\u7B26\uFF09\uFF1A${piece}`);
|
|
4539
|
+
}
|
|
4540
|
+
if (seen.has(id)) continue;
|
|
4541
|
+
seen.add(id);
|
|
4542
|
+
out.push(id);
|
|
4543
|
+
}
|
|
4544
|
+
return out;
|
|
4545
|
+
}
|
|
4546
|
+
var ENTITY_ID_UUID_RE;
|
|
4547
|
+
var init_media_customer_id = __esm({
|
|
4548
|
+
"src/utils/media-customer-id.ts"() {
|
|
4549
|
+
"use strict";
|
|
4550
|
+
ENTITY_ID_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4551
|
+
}
|
|
4552
|
+
});
|
|
4553
|
+
|
|
4482
4554
|
// src/utils/currency-display.ts
|
|
4483
4555
|
function formatMoneyDisplay(amount, currencyCode, options) {
|
|
4484
4556
|
if (amount == null || Number.isNaN(Number(amount))) return "-";
|
|
@@ -5025,69 +5097,6 @@ var init_balance = __esm({
|
|
|
5025
5097
|
}
|
|
5026
5098
|
});
|
|
5027
5099
|
|
|
5028
|
-
// src/utils/media-customer-id.ts
|
|
5029
|
-
function stripMediaCustomerIdDecorators(raw) {
|
|
5030
|
-
return raw.trim().replace(/[\s-]+/g, "");
|
|
5031
|
-
}
|
|
5032
|
-
function looksLikeNumericMediaCustomerId(raw) {
|
|
5033
|
-
return /^\d+$/.test(stripMediaCustomerIdDecorators(raw));
|
|
5034
|
-
}
|
|
5035
|
-
function normalizeNumericMediaCustomerId(raw) {
|
|
5036
|
-
if (!looksLikeNumericMediaCustomerId(raw)) return null;
|
|
5037
|
-
return stripMediaCustomerIdDecorators(raw);
|
|
5038
|
-
}
|
|
5039
|
-
function requireNumericMediaCustomerId(raw, label = "-a, --account") {
|
|
5040
|
-
const trimmed = raw?.toString().trim() ?? "";
|
|
5041
|
-
if (!trimmed) {
|
|
5042
|
-
throw new Error(`\u8BF7\u6307\u5B9A\u5A92\u4F53\u8D26\u6237 ID\uFF08${label}\uFF09`);
|
|
5043
|
-
}
|
|
5044
|
-
const id = normalizeNumericMediaCustomerId(trimmed);
|
|
5045
|
-
if (!id) {
|
|
5046
|
-
throw new Error(
|
|
5047
|
-
`\u5A92\u4F53\u8D26\u6237 ID \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF08Google CID \u53EF\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 123-456-7890\uFF1B\u52FF\u4F20 entityId/UUID\uFF09\uFF1A${trimmed}`
|
|
5048
|
-
);
|
|
5049
|
-
}
|
|
5050
|
-
return id;
|
|
5051
|
-
}
|
|
5052
|
-
function looksLikeEntityIdUuid(raw) {
|
|
5053
|
-
return ENTITY_ID_UUID_RE.test(raw.trim());
|
|
5054
|
-
}
|
|
5055
|
-
function warnIfAccountIdsLookLikeEntityId(ids, command) {
|
|
5056
|
-
const bad = ids.map((id) => id.trim()).filter((id) => id && looksLikeEntityIdUuid(id));
|
|
5057
|
-
if (bad.length === 0) return;
|
|
5058
|
-
console.error(
|
|
5059
|
-
`
|
|
5060
|
-
\u26A0\uFE0F ${command} \u7684 -a/--accounts \u6536\u5230\u7591\u4F3C entityId/UUID\uFF1A${bad.join(", ")}
|
|
5061
|
-
\u672C\u547D\u4EE4\u9700\u8981 mediaCustomerId\uFF08list-accounts \u7684 ma.mediaCustomerId\uFF1BYandex \u5F62\u5982 porg-\u2026\uFF09\u3002
|
|
5062
|
-
\u8BF7\u5148 list-accounts -m <\u5A92\u4F53> -k <\u5A92\u4F53\u8D26\u6237\u53F7> \u6838\u5BF9\u540E\u518D\u91CD\u8BD5\uFF1B\u52FF\u636E\u6B64\u76F4\u63A5 reauth\u3002
|
|
5063
|
-
`
|
|
5064
|
-
);
|
|
5065
|
-
}
|
|
5066
|
-
function parseNumericMediaCustomerIds(input) {
|
|
5067
|
-
if (!input || !input.trim()) return [];
|
|
5068
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5069
|
-
const out = [];
|
|
5070
|
-
for (const raw of input.split(",")) {
|
|
5071
|
-
const piece = raw.trim();
|
|
5072
|
-
if (!piece) continue;
|
|
5073
|
-
const id = normalizeNumericMediaCustomerId(piece);
|
|
5074
|
-
if (!id) {
|
|
5075
|
-
throw new Error(`mediaCustomerId \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF08\u53EF\u542B\u8FDE\u5B57\u7B26\uFF09\uFF1A${piece}`);
|
|
5076
|
-
}
|
|
5077
|
-
if (seen.has(id)) continue;
|
|
5078
|
-
seen.add(id);
|
|
5079
|
-
out.push(id);
|
|
5080
|
-
}
|
|
5081
|
-
return out;
|
|
5082
|
-
}
|
|
5083
|
-
var ENTITY_ID_UUID_RE;
|
|
5084
|
-
var init_media_customer_id = __esm({
|
|
5085
|
-
"src/utils/media-customer-id.ts"() {
|
|
5086
|
-
"use strict";
|
|
5087
|
-
ENTITY_ID_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5088
|
-
}
|
|
5089
|
-
});
|
|
5090
|
-
|
|
5091
5100
|
// src/utils/media-account-batch.ts
|
|
5092
5101
|
function mediaAccountDataBatchSize(media) {
|
|
5093
5102
|
switch (media) {
|
|
@@ -107485,6 +107494,7 @@ function register5(program2) {
|
|
|
107485
107494
|
// src/commands/list-accounts/_shared.ts
|
|
107486
107495
|
init_dist();
|
|
107487
107496
|
init_auth();
|
|
107497
|
+
init_media_customer_id();
|
|
107488
107498
|
var SCOPE_ACTIVATION_BYPASSED_HEADER = "x-scope-activation-bypassed";
|
|
107489
107499
|
function isScopeActivationBypassed(headers) {
|
|
107490
107500
|
if (!headers) return false;
|
|
@@ -107503,11 +107513,20 @@ var VALID_MEDIA_TYPES = [
|
|
|
107503
107513
|
"MetaAd",
|
|
107504
107514
|
"BingV2"
|
|
107505
107515
|
];
|
|
107516
|
+
var DEFAULT_LIST_ACCOUNTS_PAGE_SIZE = 20;
|
|
107517
|
+
var AGENT_LIST_ACCOUNTS_PAGE_SIZE = 999;
|
|
107518
|
+
function resolveListAccountsPageSize(opts) {
|
|
107519
|
+
const n = opts.pageSize;
|
|
107520
|
+
if (typeof n === "number" && Number.isFinite(n) && n > 0) {
|
|
107521
|
+
return n;
|
|
107522
|
+
}
|
|
107523
|
+
if (opts.jsonOut) return AGENT_LIST_ACCOUNTS_PAGE_SIZE;
|
|
107524
|
+
return DEFAULT_LIST_ACCOUNTS_PAGE_SIZE;
|
|
107525
|
+
}
|
|
107506
107526
|
function applyListAccountsSearchKeyword(params, keyword) {
|
|
107507
107527
|
const kw = (keyword ?? "").trim();
|
|
107508
|
-
if (kw)
|
|
107509
|
-
|
|
107510
|
-
}
|
|
107528
|
+
if (!kw) return;
|
|
107529
|
+
params.set("keyword", normalizeNumericMediaCustomerId(kw) ?? kw);
|
|
107511
107530
|
}
|
|
107512
107531
|
var PLATFORM_CONFIG = {
|
|
107513
107532
|
Google: {
|
|
@@ -107632,12 +107651,14 @@ async function fetchGoogleAccountByMediaCustomerId(config, mediaCustomerId, verb
|
|
|
107632
107651
|
}
|
|
107633
107652
|
params.set(cfg.pageParam, "1");
|
|
107634
107653
|
params.set("pageSize", "50");
|
|
107635
|
-
|
|
107654
|
+
const id = normalizeNumericMediaCustomerId(mediaCustomerId) ?? mediaCustomerId.trim();
|
|
107655
|
+
params.set(cfg.idSearchParam, id);
|
|
107636
107656
|
const url = `${config.apiBaseUrl}${cfg.path}?${params}`;
|
|
107637
107657
|
const res = await apiFetchWithHeaders2(url, config, {}, verbose);
|
|
107638
107658
|
const items3 = Array.isArray(res.data) ? res.data : [];
|
|
107639
|
-
const
|
|
107640
|
-
|
|
107659
|
+
const match = items3.find(
|
|
107660
|
+
(it) => mediaCustomerIdsEqual(String(it.ma?.mediaCustomerId ?? ""), mediaCustomerId)
|
|
107661
|
+
);
|
|
107641
107662
|
return match ?? null;
|
|
107642
107663
|
}
|
|
107643
107664
|
|
|
@@ -107996,7 +108017,7 @@ async function runListAccounts(opts) {
|
|
|
107996
108017
|
process.exit(1);
|
|
107997
108018
|
}
|
|
107998
108019
|
const page = opts.page ?? 1;
|
|
107999
|
-
const pageSize = opts
|
|
108020
|
+
const pageSize = resolveListAccountsPageSize(opts);
|
|
108000
108021
|
const platformCfg = opts.media ? PLATFORM_CONFIG[opts.media] : null;
|
|
108001
108022
|
let items3;
|
|
108002
108023
|
let total;
|
|
@@ -108075,6 +108096,8 @@ async function runListAccounts(opts) {
|
|
|
108075
108096
|
const allFail = items3.every((it) => it.ma?.invalidOAuthToken === true);
|
|
108076
108097
|
return allFail ? "\u68C0\u6D4B\u5230\u672C\u9875\u6240\u6709\u8D26\u6237\u5747\u6807\u8BB0\u4E3A OAuth \u5931\u6548\uFF0C\u8FD9\u901A\u5E38\u662F\u670D\u52A1\u7AEF\u4F1A\u8BDD\u5F02\u5E38\u6216\u6743\u9650\u6F02\u79FB\uFF08\u975E\u771F\u5931\u6548\uFF09\u3002\u5EFA\u8BAE\u6309\u987A\u5E8F\u6392\u67E5\uFF1A\n 1) siluzan-tso list-accounts --refresh-dp # \u5F3A\u5236\u5237\u65B0 Datapermission\n 2) siluzan-tso login # \u91CD\u65B0\u767B\u5F55\u83B7\u53D6\u65B0 authToken\n 3) 1 \u5206\u949F\u540E\u91CD\u8BD5\uFF1B\u82E5\u4ECD\u590D\u73B0\uFF0C\u8BF7\u5E26\u4E0A --verbose \u8F93\u51FA\u53CD\u9988\u7ED9\u5E73\u53F0\u3002" : null;
|
|
108077
108098
|
})();
|
|
108099
|
+
const incompletePageWarning = total !== void 0 && items3.length < total ? "\u672C\u9875\u4E0D\u5B8C\u6574\uFF08itemCount < total\uFF09\u3002\u7981\u6B62\u636E\u6B64\u5224\u5B9A\u8D26\u6237\u672A\u7ED1\u5B9A\u6216\u672A\u6388\u6743\u3002\u7528\u6237\u7ED9\u4E86\u8D26\u6237\u53F7\u65F6\u5FC5\u987B list-accounts -m <\u5A92\u4F53> -k <\u7528\u6237\u539F\u6837ID>\uFF08Google CID \u5E26\u6A2A\u6760\u4E5F\u53EF\uFF0CCLI \u4F1A\u53BB\u8FDE\u5B57\u7B26\uFF09\u3002\u5217\u5168\u90E8\u987B --page-size 999\u3002" : null;
|
|
108100
|
+
const combinedWarning = [oauthFailWarning, incompletePageWarning].filter(Boolean).join("\n") || null;
|
|
108078
108101
|
const listPayload = {
|
|
108079
108102
|
...wrapListJson({
|
|
108080
108103
|
page,
|
|
@@ -108082,7 +108105,7 @@ async function runListAccounts(opts) {
|
|
|
108082
108105
|
total: total ?? null,
|
|
108083
108106
|
items: items3
|
|
108084
108107
|
}),
|
|
108085
|
-
...
|
|
108108
|
+
...combinedWarning ? { warning: combinedWarning } : {}
|
|
108086
108109
|
};
|
|
108087
108110
|
if (await emitCliJsonOrSnapshot(opts, {
|
|
108088
108111
|
section: `list-accounts-${(opts.media ?? "unknown").replace(/\s+/g, "-")}`,
|
|
@@ -108132,9 +108155,9 @@ async function runListAccounts(opts) {
|
|
|
108132
108155
|
);
|
|
108133
108156
|
console.log(` siluzan-tso account withdraw-list`);
|
|
108134
108157
|
}
|
|
108135
|
-
if (
|
|
108158
|
+
if (combinedWarning) {
|
|
108136
108159
|
console.log(`
|
|
108137
|
-
\u26A0\uFE0F ${
|
|
108160
|
+
\u26A0\uFE0F ${combinedWarning}`);
|
|
108138
108161
|
}
|
|
108139
108162
|
console.log();
|
|
108140
108163
|
}
|
|
@@ -108146,11 +108169,18 @@ function register6(program2) {
|
|
|
108146
108169
|
).option(
|
|
108147
108170
|
"-m, --media <type>",
|
|
108148
108171
|
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2\uFF08\u7559\u7A7A\u5219\u67E5\u8BE2\u5168\u90E8\u5A92\u4F53\uFF09"
|
|
108149
|
-
).option(
|
|
108172
|
+
).option(
|
|
108173
|
+
"-k, --keyword <text>",
|
|
108174
|
+
"\u5173\u952E\u5B57\uFF08\u516C\u53F8/\u8D26\u6237\u540D/\u8D26\u6237ID\uFF1BGoogle CID \u5E26\u6A2A\u6760\u5982 928-780-1878 \u4F1A\u53BB\u8FDE\u5B57\u7B26\uFF09"
|
|
108175
|
+
).option(
|
|
108150
108176
|
"-s, --status <status>",
|
|
108151
108177
|
"\u8D26\u6237\u72B6\u6001\uFF1Anormal\uFF08\u6B63\u5E38\uFF09| invalid\uFF08\u5931\u6548\uFF09| all\uFF08\u5168\u90E8\uFF0C\u9ED8\u8BA4\uFF09",
|
|
108152
108178
|
"all"
|
|
108153
|
-
).option("-p, --page <n>", "\u9875\u7801\uFF08\u9ED8\u8BA4 1\uFF09", parseInt).option(
|
|
108179
|
+
).option("-p, --page <n>", "\u9875\u7801\uFF08\u9ED8\u8BA4 1\uFF09", parseInt).option(
|
|
108180
|
+
"--page-size <n>",
|
|
108181
|
+
"\u6BCF\u9875\u6570\u91CF\uFF08\u4EA4\u4E92\u9ED8\u8BA4 20\uFF1B\u5E26 --json-out \u4E14\u672A\u6307\u5B9A\u65F6 999\uFF09",
|
|
108182
|
+
parseInt
|
|
108183
|
+
).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option(
|
|
108154
108184
|
"--json-out <path>",
|
|
108155
108185
|
"\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
|
|
108156
108186
|
void 0
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -39,13 +39,13 @@ siluzan-tso -h
|
|
|
39
39
|
## 即时规范
|
|
40
40
|
|
|
41
41
|
- `entityId`(UUID)≠ `mediaCustomerId`(`list-accounts` 的 `ma.mediaCustomerId`:Google/TikTok/Bing 多为数字;**Yandex=`porg-…`**;Meta 常带 `act_`,`balance`/`stats`/`balance-scan`/`accounts-digest` 裸数字会补前缀)。`stats`/`balance`/`accounts-digest`/`ad *` 的 `-a` **只传 mediaCustomerId**;空结果或 verbose 打出 403 时**先核验 ID**,禁止把 UUID/`entityId` 传给 `-a`,也**禁止**据此直接 `reauth`。
|
|
42
|
-
- **Google CID 特殊性**:UI 常写 `123-456-7890`(带连字符),平台 `mediaCustomerId` 为纯数字 `1234567890
|
|
42
|
+
- **Google CID 特殊性**:UI 常写 `123-456-7890`(带连字符),平台 `mediaCustomerId` 为纯数字 `1234567890`。用户给了账户号时必须 `list-accounts -m Google -k <用户原样>`(带横杠也可,CLI 去连字符);**禁止**无 `-k` 拉默认 20 条再判定未绑定/引导授权。`stats`/`balance`/`ad *`/`google-analysis` 的 `-a` 也可带横杠。**勿**把带横杠 403 误判为 OAuth 失效。
|
|
43
43
|
- **禁止臆测授权过期**:见 403/`HTTP 403`/拉数失败/「可能 OAuth 失效」时,**禁止**口头推断授权过期或直接 `reauth`。须先核验 ID(及 Google 连字符)。**`account check-access` 仅支持 Google**(无 `-m`,禁止对 TikTok/Meta/Bing/Yandex 调用):Google 跑 `account check-access -a <mediaCustomerId>`,以 `accessible` / `reauth_required` / `no_permission` 为准;非 Google 看 `list-accounts` 的 `invalidOAuthToken`。仅当 `list-accounts` 输出含激活字段且可判定未激活时才跳过用其判断授权过期;细则见 `accounts-permissions.md`。
|
|
44
44
|
- **Google 广告命令名**:列表是 `ad campaigns`(不是 `ad-campaigns` / `campaign list`);`balance`/`stats` 须带 `-m Google`;单国地域用 `ad geo search … --json-out`(或 `geo resolve`)。
|
|
45
45
|
- **广告搭建媒体边界**:仅 **Google**(`ad`,Search + PMax)与 **Meta**(`meta-ad`,Instant Form 线索)。TikTok / BingV2 / Yandex **不能**创建或改广告结构;用户要搭建时须说明不支持,可改做账户分析(P4)或开户(W2)。**禁止**用 `ad` 冒充 Meta,**禁止**用 `meta-ad` 冒充 Google。
|
|
46
46
|
- **Google 广告类型边界**:CLI/Skill **仅支持** Google **搜索广告(Search)** 与 **Performance Max(PMax)** 的方案、创建与精细管理;**不支持展示广告(Display)**(含自适应展示广告 RDA、独立 Display 系列)。用户要做展示广告时须明确告知不支持,可改推 Search / PMax;**禁止**用 `campaign-create` / `ad-create` 伪装创建 Display。
|
|
47
47
|
- **创建完成后交付(硬性)**:`ad batch diff` 的 stdout 含 `BEGIN_USER_DELIVERY_MARKDOWN`…`END_USER_DELIVERY_MARKDOWN`——**立刻**把中间全文原样发给用户(可先于补建);禁止只摘要、禁止只说「创建成功/详情已交付/未发现缺失」、禁止等全部补建结束再交付。
|
|
48
|
-
- `list-accounts` 无余额/消耗;列全部用 `--page-size 999
|
|
48
|
+
- `list-accounts` 无余额/消耗;列全部用 `--page-size 999`。查单户必须 `-k`;`itemCount < total` 时**禁止**判定账户未绑定。
|
|
49
49
|
- 多户余额用 `balance-scan`(P2),多户消耗 / **转化成本·CPA 巡检**用 `accounts-digest`(P3,`--max-cpa`;**没有** `cpa-risk-scan`)。禁止外层 for-loop 逐户拉数。
|
|
50
50
|
- `stats` 的 `spend` = **区间合计**,不是日消耗。
|
|
51
51
|
- 行业/市场报告禁止纯 WebSearch 当终稿;须 P9 `market-analysis collect`+`render`。
|
package/dist/skill/_meta.json
CHANGED
|
@@ -17,10 +17,10 @@ siluzan-tso list-accounts [选项]
|
|
|
17
17
|
| 选项 | 说明 |
|
|
18
18
|
| ----------------------- | ---------------------------------------------------------------------------------- | ---------------------- |
|
|
19
19
|
| `-m, --media <type>` | 媒体类型(留空查全部):`Google \| TikTok \| Yandex \| MetaAd \| BingV2` |
|
|
20
|
-
| `-k, --keyword <text>` | 统一模糊搜索:账户名称 **或** ID(含 Google
|
|
20
|
+
| `-k, --keyword <text>` | 统一模糊搜索:账户名称 **或** ID。数字型 ID(含 Google `928-780-1878`)CLI 先去连字符再搜;**查单户必须带 `-k`** |
|
|
21
21
|
| `-s, --status <status>` | 账户状态:`normal \| invalid \| all`(默认 all) |
|
|
22
22
|
| `-p, --page <n>` | 页码(默认 1) |
|
|
23
|
-
| `--page-size <n>` |
|
|
23
|
+
| `--page-size <n>` | 每页数量(交互默认 20;`--json-out` 未指定时 999) |
|
|
24
24
|
| `--json-out` | 输出原始 JSON |
|
|
25
25
|
| `--unicode` | 表格使用 Unicode 线框;**默认**为 ASCII `+- | ` 线框(兼容各类终端) |
|
|
26
26
|
| `--plain` | 已默认 ASCII,无需再传;保留兼容旧脚本 |
|
|
@@ -37,7 +37,7 @@ siluzan-tso list-accounts [选项]
|
|
|
37
37
|
| 列出全部某媒体账户 | `list-accounts -m <媒体> --page-size 999 --json-out <dir>` | `items[]`(`ma.mediaCustomerId`、`ma.mediaCustomerName`、`ma.currencyCode`、`ma.invalidOAuthToken` 等) |
|
|
38
38
|
| 哪些账户 OAuth / 授权失效 | 同上(或 `-s invalid`);表格看「授权状态」列 | **`ma.invalidOAuthToken === true`**(勿用审核状态 / `mediaAccountState`) |
|
|
39
39
|
| 有多少个账户 | 同上 | **`total`**(无需翻页;`itemCount < total` 时说明 page-size 不够大) |
|
|
40
|
-
| 只查某一个户 | `list-accounts -m <媒体> -k
|
|
40
|
+
| 只查某一个户 | `list-accounts -m <媒体> -k <用户原样ID或名称> --json-out <dir>` | Google CID 带横杠可原样;**禁止**无 `-k` 拉首页再判定未绑定 |
|
|
41
41
|
| **Meta 全部账户 + 余额/消耗** | **`accounts-digest -m MetaAd --json-out <dir>`**(一步;内部翻页+分批) | `accounts-digest-metaad.json` → `data.items[]`(含 `balance`、`spend`) |
|
|
42
42
|
| Meta 余额续航预警 | `balance-scan -m MetaAd --json-out <dir>` | `balance-scan-metaad.json` |
|
|
43
43
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
- `list-accounts` **不含**余额/消耗;列全部账户用 `--page-size 999`,禁止默认 20 再翻页。
|
|
20
20
|
- `entityId`(UUID,分享/delink/账单/`reauth`)≠ `mediaCustomerId`(`balance`/`stats`/`accounts-digest`/`ad` 的 `-a`)。**Yandex 的 mediaCustomerId 形如 `porg-…`,不是 UUID。**
|
|
21
21
|
- MetaAd OAuth 户官方 `mediaCustomerId` 带 `act_`。`balance` / `stats` / `balance-scan` / `accounts-digest` 的 `-a` 传裸数字或 `act_` 均可,CLI 会规范成清单官方 ID 再打 TSO。
|
|
22
|
-
- **Google CID**:广告后台展示常为 `XXX-XXX-XXXX
|
|
22
|
+
- **Google CID**:广告后台展示常为 `XXX-XXX-XXXX`(连字符),平台 `mediaCustomerId` 是**纯数字**。查单户必须 `list-accounts -m Google -k <用户原样>`(CLI 去横杠);**禁止**无 `-k` 拉首页 20 条再判定未绑定。`stats`/`balance`/`ad *`/`google-analysis` 的 `-a` 可带连字符(CLI 会去掉);若仍见 `HTTP 403:123-456-7890` 这类**回显带横杠 ID**,优先改成纯数字重试,**不要**直接当 OAuth 失效去 `reauth`。
|
|
23
23
|
- **禁止臆测授权过期**:403 / 拉数失败时**禁止**口头说「可能授权过期」。须 ID 核验后,**仅 Google** 执行 `account check-access -a <mediaCustomerId>`(无 `-m`,其他媒体禁止调用),以返回 `status` 为准(见 [`accounts-permissions.md`](accounts-permissions.md));仅当 `list-accounts` 输出含激活字段且可判定未激活时,勿用其判断授权过期;非 Google 看 `invalidOAuthToken`。
|
|
24
24
|
- `stats`/`balance` 空结果 + verbose `HTTP 403`:先确认 `-a` 是否为 `ma.mediaCustomerId`(且 Google 已去连字符);**禁止**把 `entityId` / tokenId 当 `-a`;未跑 `account check-access`(或未见 `invalidOAuthToken=true`)**禁止** `reauth`。
|
|
25
25
|
- 多账户余额预警用 `balance-scan`(P2),多账户消耗汇总用 `accounts-digest`(P3);**禁止**外层 for-loop 逐户 `balance`/`stats`。
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
|
|
185
185
|
**例外**(不反问):
|
|
186
186
|
|
|
187
|
-
- `list-accounts` 列全部 / 数个数:一次 `list-accounts -m <媒体> --page-size 999 --json-out <dir>`,脚本读落盘 `total` / `items[]`;**禁止**默认 page-size 20 再翻页(详见 `references/accounts/accounts-list.md` § Agent
|
|
187
|
+
- `list-accounts` 列全部 / 数个数:一次 `list-accounts -m <媒体> --page-size 999 --json-out <dir>`,脚本读落盘 `total` / `items[]`;**禁止**默认 page-size 20 再翻页(详见 `references/accounts/accounts-list.md` § Agent 意图速查)。用户给了账户号(含 Google `123-456-7890`)必须加 `-k <原样>`;`itemCount < total` 时**禁止**判定未绑定或引导授权。
|
|
188
188
|
- 「昨天」单日 stats:默认 `Asia/Shanghai` 日历日;先 `list-accounts` 再 `stats`。
|
|
189
189
|
- `forewarning records`、`invoice list`「本月」、TikTok `clue`「最近一周」:见对应 references。
|
|
190
190
|
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
- **必读**:`report-templates/okki-weekly-google-client.md`(**全文**)+ `references/analytics/account-analytics.md`;可选 `references/core/subagent-orchestration.md`。
|
|
139
139
|
- **步骤**:
|
|
140
140
|
1. (可选)Read `subagent-orchestration.md` § P6 决定是否分阶段委派。
|
|
141
|
-
2.
|
|
141
|
+
2. `list-accounts -m Google -k <用户给的账户号>`(`928-780-1878` 可原样,CLI 去连字符)确认 `mediaCustomerId`;无 `-k` 的默认首页或 `itemCount < total` **禁止**判定未绑定。确认 `--start` / `--end`。
|
|
142
142
|
3. 同一 `--json-out` 目录执行模板命令组合:`stats`、`balance`、`google-analysis --sections overview,campaigns,keywords,search-terms,campaign-device,campaign-geo-matched`。
|
|
143
143
|
4. 脚本读盘 → 只写 `okki-weekly-report.json` 的 `meta` + `narrative`(5 Sheet 表末分析 + 账户 Sheet 固定 5 维数据复盘;表为空也须写)。`deviceType` 是 `Desktop`/`Mobile`,禁止 `.get("DESKTOP")`,按大小写不敏感分类累加后再写设备金额。
|
|
144
144
|
5. `google-analysis okki-render --data ./okki-weekly-report.json --snapshot-dir ./snap-okki --out <xlsx>`。缺分析 / 缺 5 维复盘 / 缺 `campaign-device` 或 `campaign-geo-matched` 会拒绝出文件;按 stderr 补 JSON 后重跑。**禁止** Agent 手写 xlsx。
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
## 须先确认
|
|
31
31
|
|
|
32
|
-
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k
|
|
32
|
+
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k <用户原样账户号>`(`928-780-1878` 可原样,CLI 去连字符),禁止猜 ID;**禁止**无 `-k` 拉默认 20 条后判定未绑定。
|
|
33
33
|
2. **统计区间**:`--start` / `--end`(用户未给齐时按 SKILL 反问;授权默认时可用「上一完整自然周」白名单并写明)。
|
|
34
34
|
3. **询盘口径**:默认使用区间内 `conversions`(转化次数,来自 `stats` 或 `overview`)。若运营定义为某类转化,须在首段脚注说明(必要时补拉 `google-analysis --sections conversion-actions` 仅作说明)。
|
|
35
35
|
4. **日期写法**:`2026.4.1`、`2026/4/1` 等先规范为 `YYYY-MM-DD`(如 `2026-04-01`)再传 `--start` / `--end`。
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
## 须先确认
|
|
31
31
|
|
|
32
|
-
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k
|
|
32
|
+
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k <用户原样账户号>`(`928-780-1878` 可原样,CLI 去连字符),禁止猜 ID;**禁止**无 `-k` 拉默认 20 条后判定未绑定。
|
|
33
33
|
2. **统计区间**:`--start` / `--end`(用户未给齐时按 SKILL 反问;授权默认时可用「上一完整自然周」白名单并写明)。
|
|
34
34
|
3. **询盘口径**:默认使用区间内 `conversions`(转化次数,来自 `stats` 或 `overview`)。若运营定义为某类转化,须在首段脚注说明(必要时补拉 `google-analysis --sections conversion-actions` 仅作说明)。
|
|
35
35
|
4. **日期写法**:`2026.4.1`、`2026/4/1` 等先规范为 `YYYY-MM-DD`(如 `2026-04-01`)再传 `--start` / `--end`。
|
|
@@ -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.53-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.53-beta.9'
|
|
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.53-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.53-beta.9"
|
|
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"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "accounts-google-cid-hyphen-must-keyword",
|
|
3
|
+
"description": "带横杠 Google CID 必须 -k 查单户,禁止默认 20 条后判定未绑定",
|
|
4
|
+
"turns": [
|
|
5
|
+
"帮我查一下谷歌账户开禾科技(宁波)有限公司:928-780-1878 有没有绑在丝路赞上,用 siluzan-tso,需要 JSON。"
|
|
6
|
+
],
|
|
7
|
+
"judgeExpectation": "路径:用户给出带连字符的 Google CID(如 928-780-1878)时,必须 `list-accounts -m Google -k <该ID>`(带横杠或去横杠均可);禁止无 -k 只拉默认 20 条再本地 grep。\n禁止:因首页 20 条未出现该户就判定未绑定、引导授权/present_connect。\n输出:说明是否查到该户即可;stub 即可。",
|
|
8
|
+
"skillMapping": "SKILL.md Google CID;references/accounts/accounts-list.md(查单户必须 -k)",
|
|
9
|
+
"judgeReferencePaths": [
|
|
10
|
+
"references/accounts/accounts-list.md",
|
|
11
|
+
"references/core/agent-conventions.md"
|
|
12
|
+
],
|
|
13
|
+
"commandMustInclude": [
|
|
14
|
+
[
|
|
15
|
+
"list-accounts"
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"-k",
|
|
19
|
+
"--keyword"
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"928-780-1878",
|
|
23
|
+
"9287801878"
|
|
24
|
+
]
|
|
25
|
+
]
|
|
26
|
+
}
|