siluzan-tso-cli 1.1.37-beta.12 → 1.1.37-beta.13
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 +193 -93
- package/dist/skill/AGENTS.md +1 -0
- package/dist/skill/SKILL.md +1 -0
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +1 -0
- package/dist/skill/references/accounts/accounts.md +9 -17
- package/dist/skill/references/core/agent-conventions.md +3 -2
- package/dist/skill/references/core/intent-routing.md +2 -1
- package/dist/skill/references/core/playbooks.md +9 -0
- package/dist/skill/references/core/workflows.md +1 -1
- package/dist/skill/references/report-templates/README.md +1 -0
- package/dist/skill/references/report-templates/google-ads-diagnosis.md +1 -1
- package/dist/skill/references/report-templates/google-period-report-excel.md +2 -9
- package/dist/skill/references/report-templates/okki-weekly-google-client.md +1 -0
- package/dist/skill/references/report-templates/stats-daily-excel.md +10 -0
- package/dist/skill/report-templates/README.md +1 -0
- package/dist/skill/report-templates/google-ads-diagnosis.md +1 -1
- package/dist/skill/report-templates/google-period-report-excel.md +2 -9
- package/dist/skill/report-templates/okki-weekly-google-client.md +1 -0
- package/dist/skill/report-templates/stats-daily-excel.md +10 -0
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.37-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.37-beta.13),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -4385,6 +4385,40 @@ var init_currency_display = __esm({
|
|
|
4385
4385
|
}
|
|
4386
4386
|
});
|
|
4387
4387
|
|
|
4388
|
+
// src/utils/media-customer-id.ts
|
|
4389
|
+
function stripMediaCustomerIdDecorators(raw) {
|
|
4390
|
+
return raw.trim().replace(/[\s-]+/g, "");
|
|
4391
|
+
}
|
|
4392
|
+
function looksLikeNumericMediaCustomerId(raw) {
|
|
4393
|
+
return /^\d+$/.test(stripMediaCustomerIdDecorators(raw));
|
|
4394
|
+
}
|
|
4395
|
+
function normalizeNumericMediaCustomerId(raw) {
|
|
4396
|
+
if (!looksLikeNumericMediaCustomerId(raw)) return null;
|
|
4397
|
+
return stripMediaCustomerIdDecorators(raw);
|
|
4398
|
+
}
|
|
4399
|
+
function parseNumericMediaCustomerIds(input) {
|
|
4400
|
+
if (!input || !input.trim()) return [];
|
|
4401
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4402
|
+
const out = [];
|
|
4403
|
+
for (const raw of input.split(",")) {
|
|
4404
|
+
const piece = raw.trim();
|
|
4405
|
+
if (!piece) continue;
|
|
4406
|
+
const id = normalizeNumericMediaCustomerId(piece);
|
|
4407
|
+
if (!id) {
|
|
4408
|
+
throw new Error(`mediaCustomerId \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF08\u53EF\u542B\u8FDE\u5B57\u7B26\uFF09\uFF1A${piece}`);
|
|
4409
|
+
}
|
|
4410
|
+
if (seen.has(id)) continue;
|
|
4411
|
+
seen.add(id);
|
|
4412
|
+
out.push(id);
|
|
4413
|
+
}
|
|
4414
|
+
return out;
|
|
4415
|
+
}
|
|
4416
|
+
var init_media_customer_id = __esm({
|
|
4417
|
+
"src/utils/media-customer-id.ts"() {
|
|
4418
|
+
"use strict";
|
|
4419
|
+
}
|
|
4420
|
+
});
|
|
4421
|
+
|
|
4388
4422
|
// src/utils/balance.ts
|
|
4389
4423
|
function fmt(d) {
|
|
4390
4424
|
return d.toISOString().slice(0, 10);
|
|
@@ -103126,20 +103160,7 @@ function parseSections(input) {
|
|
|
103126
103160
|
return list;
|
|
103127
103161
|
}
|
|
103128
103162
|
function parseAccountIds(input) {
|
|
103129
|
-
|
|
103130
|
-
const seen = /* @__PURE__ */ new Set();
|
|
103131
|
-
const out = [];
|
|
103132
|
-
for (const raw of input.split(",")) {
|
|
103133
|
-
const id = raw.trim();
|
|
103134
|
-
if (!id) continue;
|
|
103135
|
-
if (!/^\d+$/.test(id)) {
|
|
103136
|
-
throw new Error(`mediaCustomerId \u5FC5\u987B\u4E3A\u7EAF\u6570\u5B57\uFF1A${id}`);
|
|
103137
|
-
}
|
|
103138
|
-
if (seen.has(id)) continue;
|
|
103139
|
-
seen.add(id);
|
|
103140
|
-
out.push(id);
|
|
103141
|
-
}
|
|
103142
|
-
return out;
|
|
103163
|
+
return parseNumericMediaCustomerIds(input);
|
|
103143
103164
|
}
|
|
103144
103165
|
function parseDeadline(s) {
|
|
103145
103166
|
if (!s) return void 0;
|
|
@@ -103644,6 +103665,7 @@ var init_google_analysis_batch = __esm({
|
|
|
103644
103665
|
init_google_analysis3();
|
|
103645
103666
|
init_balance();
|
|
103646
103667
|
init_version();
|
|
103668
|
+
init_media_customer_id();
|
|
103647
103669
|
DEFAULT_SECTIONS = ["campaigns", "geographic", "keywords"];
|
|
103648
103670
|
DEFAULT_ACCOUNT_CONCURRENCY = 4;
|
|
103649
103671
|
DEFAULT_SECTION_CONCURRENCY = 6;
|
|
@@ -103795,23 +103817,15 @@ function finiteOpt(n) {
|
|
|
103795
103817
|
return typeof n === "number" && Number.isFinite(n) ? n : void 0;
|
|
103796
103818
|
}
|
|
103797
103819
|
function parseAccountIdsForAnalysis(input) {
|
|
103798
|
-
|
|
103799
|
-
|
|
103800
|
-
|
|
103801
|
-
const
|
|
103802
|
-
|
|
103803
|
-
|
|
103804
|
-
console.error(`
|
|
103805
|
-
\u274C --account \u987B\u4E3A\u6570\u5B57 mediaCustomerId\uFF08\u4E0D\u5408\u6CD5\uFF1A${id}\uFF09\u3002
|
|
103820
|
+
try {
|
|
103821
|
+
return parseNumericMediaCustomerIds(input);
|
|
103822
|
+
} catch (err) {
|
|
103823
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
103824
|
+
console.error(`
|
|
103825
|
+
\u274C --account \u987B\u4E3A\u6570\u5B57 mediaCustomerId\uFF1A${message}
|
|
103806
103826
|
`);
|
|
103807
|
-
|
|
103808
|
-
}
|
|
103809
|
-
if (!seen.has(id)) {
|
|
103810
|
-
seen.add(id);
|
|
103811
|
-
out.push(id);
|
|
103812
|
-
}
|
|
103827
|
+
process.exit(1);
|
|
103813
103828
|
}
|
|
103814
|
-
return out;
|
|
103815
103829
|
}
|
|
103816
103830
|
async function runMultiAccountViaBatch(accountIds, opts) {
|
|
103817
103831
|
const targets = resolveSectionList(opts.sections, opts.exclude);
|
|
@@ -103997,6 +104011,7 @@ var init_register_cli = __esm({
|
|
|
103997
104011
|
init_auth();
|
|
103998
104012
|
init_google_analysis_snapshot();
|
|
103999
104013
|
init_version();
|
|
104014
|
+
init_media_customer_id();
|
|
104000
104015
|
init_http_retry();
|
|
104001
104016
|
init_sections();
|
|
104002
104017
|
init_fetch();
|
|
@@ -105963,6 +105978,7 @@ function wrapListJson(params) {
|
|
|
105963
105978
|
}
|
|
105964
105979
|
|
|
105965
105980
|
// src/commands/list-accounts/main.ts
|
|
105981
|
+
init_media_customer_id();
|
|
105966
105982
|
async function runListAccounts(opts) {
|
|
105967
105983
|
let config = loadConfig(opts.token);
|
|
105968
105984
|
if (opts.refreshDp) {
|
|
@@ -105993,9 +106009,9 @@ async function runListAccounts(opts) {
|
|
|
105993
106009
|
params.set("status", opts.status);
|
|
105994
106010
|
}
|
|
105995
106011
|
if (opts.keyword) {
|
|
105996
|
-
const
|
|
105997
|
-
if (
|
|
105998
|
-
params.set(platformCfg.idSearchParam,
|
|
106012
|
+
const numericId = normalizeNumericMediaCustomerId(opts.keyword);
|
|
106013
|
+
if (numericId) {
|
|
106014
|
+
params.set(platformCfg.idSearchParam, numericId);
|
|
105999
106015
|
} else {
|
|
106000
106016
|
params.set("mediaCustomerName", opts.keyword.trim());
|
|
106001
106017
|
}
|
|
@@ -106033,7 +106049,9 @@ async function runListAccounts(opts) {
|
|
|
106033
106049
|
}
|
|
106034
106050
|
} else {
|
|
106035
106051
|
const params = new URLSearchParams();
|
|
106036
|
-
if (opts.keyword)
|
|
106052
|
+
if (opts.keyword) {
|
|
106053
|
+
params.set("keyword", normalizeNumericMediaCustomerId(opts.keyword) ?? opts.keyword.trim());
|
|
106054
|
+
}
|
|
106037
106055
|
if (opts.status && opts.status !== "all") params.set("status", opts.status);
|
|
106038
106056
|
params.set("pageNo", String(page));
|
|
106039
106057
|
params.set("pageSize", String(pageSize));
|
|
@@ -106280,6 +106298,7 @@ init_auth();
|
|
|
106280
106298
|
init_cli_json_snapshot();
|
|
106281
106299
|
init_cli_table();
|
|
106282
106300
|
init_balance();
|
|
106301
|
+
init_media_customer_id();
|
|
106283
106302
|
var VALID_MEDIA_TYPES2 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
|
|
106284
106303
|
async function runBalance(opts) {
|
|
106285
106304
|
const config = loadConfig(opts.token);
|
|
@@ -106316,7 +106335,7 @@ async function runBalance(opts) {
|
|
|
106316
106335
|
`);
|
|
106317
106336
|
process.exit(1);
|
|
106318
106337
|
}
|
|
106319
|
-
const accountIds = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean);
|
|
106338
|
+
const accountIds = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean).map((id) => normalizeNumericMediaCustomerId(id) ?? id);
|
|
106320
106339
|
if (accountIds.length === 0) {
|
|
106321
106340
|
console.error("\n\u274C \u8BF7\u901A\u8FC7 --accounts \u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u8D26\u6237 ID\uFF08\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF09\n");
|
|
106322
106341
|
process.exit(1);
|
|
@@ -106874,7 +106893,10 @@ init_cli_json_snapshot();
|
|
|
106874
106893
|
init_cli_table();
|
|
106875
106894
|
init_balance();
|
|
106876
106895
|
init_media_account_lookup();
|
|
106896
|
+
init_media_customer_id();
|
|
106877
106897
|
var VALID_MEDIA_TYPES3 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
|
|
106898
|
+
var MAX_BY_DAY_SPAN = 366;
|
|
106899
|
+
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
106878
106900
|
function defaultDateRange2() {
|
|
106879
106901
|
const end = /* @__PURE__ */ new Date();
|
|
106880
106902
|
end.setDate(end.getDate() - 1);
|
|
@@ -106883,6 +106905,77 @@ function defaultDateRange2() {
|
|
|
106883
106905
|
const fmt2 = (d) => d.toISOString().slice(0, 10);
|
|
106884
106906
|
return { startDate: fmt2(start), endDate: fmt2(end) };
|
|
106885
106907
|
}
|
|
106908
|
+
function eachDateInclusive(startDate, endDate) {
|
|
106909
|
+
if (!DATE_RE.test(startDate) || !DATE_RE.test(endDate)) {
|
|
106910
|
+
throw new Error(`\u65E5\u671F\u683C\u5F0F\u987B\u4E3A YYYY-MM-DD\uFF0C\u6536\u5230\uFF1A${startDate} ~ ${endDate}`);
|
|
106911
|
+
}
|
|
106912
|
+
const [ys, ms, ds] = startDate.split("-").map(Number);
|
|
106913
|
+
const [ye, me, de] = endDate.split("-").map(Number);
|
|
106914
|
+
const cur = new Date(Date.UTC(ys, ms - 1, ds));
|
|
106915
|
+
const end = new Date(Date.UTC(ye, me - 1, de));
|
|
106916
|
+
if (Number.isNaN(cur.getTime()) || Number.isNaN(end.getTime())) {
|
|
106917
|
+
throw new Error(`\u65E0\u6548\u65E5\u671F\uFF1A${startDate} ~ ${endDate}`);
|
|
106918
|
+
}
|
|
106919
|
+
if (cur > end) {
|
|
106920
|
+
throw new Error(`\u5F00\u59CB\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u7ED3\u675F\u65E5\u671F\uFF1A${startDate} > ${endDate}`);
|
|
106921
|
+
}
|
|
106922
|
+
const out = [];
|
|
106923
|
+
while (cur <= end) {
|
|
106924
|
+
out.push(cur.toISOString().slice(0, 10));
|
|
106925
|
+
cur.setUTCDate(cur.getUTCDate() + 1);
|
|
106926
|
+
}
|
|
106927
|
+
if (out.length > MAX_BY_DAY_SPAN) {
|
|
106928
|
+
throw new Error(
|
|
106929
|
+
`--by-day \u8DE8\u5EA6\u6700\u591A ${MAX_BY_DAY_SPAN} \u5929\uFF08\u542B\u8D77\u6B62\uFF09\uFF0C\u5F53\u524D ${out.length} \u5929\uFF1B\u8BF7\u7F29\u5C0F\u533A\u95F4\u6216\u5206\u6BB5\u62C9\u53D6`
|
|
106930
|
+
);
|
|
106931
|
+
}
|
|
106932
|
+
return out;
|
|
106933
|
+
}
|
|
106934
|
+
async function fetchStatsWindow(media, ids, config, startDate, endDate, verbose) {
|
|
106935
|
+
const isGoogle = media === "Google";
|
|
106936
|
+
const isMetaAd = media === "MetaAd";
|
|
106937
|
+
if (isGoogle) {
|
|
106938
|
+
const params = new URLSearchParams({ startDate, endDate, mediaCustomerIds: ids.join("|") });
|
|
106939
|
+
const url = `${config.apiBaseUrl}/report/media-account/google/account-spend-overview?${params.toString()}`;
|
|
106940
|
+
const raw = await apiFetch2(url, config, {}, verbose);
|
|
106941
|
+
return parseGoogleAccountSpendOverviewRows(raw).map((row) => ({
|
|
106942
|
+
mediaAccountId: row.mediaAccountId,
|
|
106943
|
+
mediaCustomerName: row.mediaCustomerName,
|
|
106944
|
+
spend: row.spend,
|
|
106945
|
+
impressions: row.impressions,
|
|
106946
|
+
clicks: row.clicks,
|
|
106947
|
+
conversions: row.conversions,
|
|
106948
|
+
costPerClick: row.costPerClick,
|
|
106949
|
+
currencyCode: row.currencyCode,
|
|
106950
|
+
remainingAccountBudget: row.remainingAccountBudget,
|
|
106951
|
+
status: row.status
|
|
106952
|
+
}));
|
|
106953
|
+
}
|
|
106954
|
+
if (isMetaAd) {
|
|
106955
|
+
const accountMediaTypes = await lookupMetaMediaAccountTypes(config, ids, verbose);
|
|
106956
|
+
const items2 = [];
|
|
106957
|
+
for (const [route, routeIds] of groupAccountIdsByOverviewRoute(
|
|
106958
|
+
"MetaAd",
|
|
106959
|
+
ids,
|
|
106960
|
+
accountMediaTypes
|
|
106961
|
+
)) {
|
|
106962
|
+
const map2 = await fetchOverviewMap(route, routeIds, config, startDate, endDate, verbose);
|
|
106963
|
+
for (const item of map2.values()) {
|
|
106964
|
+
items2.push(item);
|
|
106965
|
+
}
|
|
106966
|
+
}
|
|
106967
|
+
return items2;
|
|
106968
|
+
}
|
|
106969
|
+
const map = await fetchOverviewMap(
|
|
106970
|
+
media,
|
|
106971
|
+
ids,
|
|
106972
|
+
config,
|
|
106973
|
+
startDate,
|
|
106974
|
+
endDate,
|
|
106975
|
+
verbose
|
|
106976
|
+
);
|
|
106977
|
+
return [...map.values()];
|
|
106978
|
+
}
|
|
106886
106979
|
async function runStats(opts) {
|
|
106887
106980
|
const config = loadConfig(opts.token);
|
|
106888
106981
|
if (!VALID_MEDIA_TYPES3.includes(opts.media)) {
|
|
@@ -106909,57 +107002,35 @@ async function runStats(opts) {
|
|
|
106909
107002
|
);
|
|
106910
107003
|
process.exit(1);
|
|
106911
107004
|
}
|
|
106912
|
-
const ids = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean);
|
|
106913
|
-
const isGoogle = opts.media === "Google";
|
|
106914
|
-
const isMetaAd = opts.media === "MetaAd";
|
|
107005
|
+
const ids = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean).map((id) => normalizeNumericMediaCustomerId(id) ?? id);
|
|
106915
107006
|
let items2;
|
|
106916
107007
|
try {
|
|
106917
|
-
if (
|
|
106918
|
-
const
|
|
106919
|
-
const url = `${config.apiBaseUrl}/report/media-account/google/account-spend-overview?${params.toString()}`;
|
|
106920
|
-
const raw = await apiFetch2(url, config, {}, opts.verbose);
|
|
106921
|
-
items2 = parseGoogleAccountSpendOverviewRows(raw).map((row) => ({
|
|
106922
|
-
mediaAccountId: row.mediaAccountId,
|
|
106923
|
-
mediaCustomerName: row.mediaCustomerName,
|
|
106924
|
-
spend: row.spend,
|
|
106925
|
-
impressions: row.impressions,
|
|
106926
|
-
clicks: row.clicks,
|
|
106927
|
-
conversions: row.conversions,
|
|
106928
|
-
costPerClick: row.costPerClick,
|
|
106929
|
-
currencyCode: row.currencyCode,
|
|
106930
|
-
remainingAccountBudget: row.remainingAccountBudget,
|
|
106931
|
-
status: row.status
|
|
106932
|
-
}));
|
|
106933
|
-
} else if (isMetaAd) {
|
|
106934
|
-
const accountMediaTypes = await lookupMetaMediaAccountTypes(config, ids, opts.verbose);
|
|
107008
|
+
if (opts.byDay) {
|
|
107009
|
+
const days = eachDateInclusive(startDate, endDate);
|
|
106935
107010
|
items2 = [];
|
|
106936
|
-
|
|
106937
|
-
|
|
106938
|
-
|
|
106939
|
-
|
|
106940
|
-
|
|
106941
|
-
|
|
106942
|
-
|
|
106943
|
-
|
|
107011
|
+
console.error(
|
|
107012
|
+
`\u23F3 [stats --by-day] ${opts.media} ${ids.length} \u6237 \xD7 ${days.length} \u5929\uFF08${startDate} ~ ${endDate}\uFF09\u2026`
|
|
107013
|
+
);
|
|
107014
|
+
for (let i = 0; i < days.length; i++) {
|
|
107015
|
+
const day = days[i];
|
|
107016
|
+
if (opts.verbose || days.length > 7) {
|
|
107017
|
+
console.error(` \u2192 [${i + 1}/${days.length}] ${day}`);
|
|
107018
|
+
}
|
|
107019
|
+
const dayItems = await fetchStatsWindow(
|
|
107020
|
+
opts.media,
|
|
107021
|
+
ids,
|
|
106944
107022
|
config,
|
|
106945
|
-
|
|
106946
|
-
|
|
107023
|
+
day,
|
|
107024
|
+
day,
|
|
106947
107025
|
opts.verbose
|
|
106948
107026
|
);
|
|
106949
|
-
for (const
|
|
106950
|
-
items2.push(
|
|
107027
|
+
for (const row of dayItems) {
|
|
107028
|
+
items2.push({ ...row, date: day });
|
|
106951
107029
|
}
|
|
106952
107030
|
}
|
|
107031
|
+
console.error(` \u2713 \u5B8C\u6210\uFF1A${items2.length} \u6761\u6309\u65E5\u884C`);
|
|
106953
107032
|
} else {
|
|
106954
|
-
|
|
106955
|
-
opts.media,
|
|
106956
|
-
ids,
|
|
106957
|
-
config,
|
|
106958
|
-
startDate,
|
|
106959
|
-
endDate,
|
|
106960
|
-
opts.verbose
|
|
106961
|
-
);
|
|
106962
|
-
items2 = [...map.values()];
|
|
107033
|
+
items2 = await fetchStatsWindow(opts.media, ids, config, startDate, endDate, opts.verbose);
|
|
106963
107034
|
}
|
|
106964
107035
|
} catch (err) {
|
|
106965
107036
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -106978,17 +107049,18 @@ async function runStats(opts) {
|
|
|
106978
107049
|
process.exit(1);
|
|
106979
107050
|
}
|
|
106980
107051
|
const n = items2.length;
|
|
107052
|
+
const section = opts.byDay ? `stats-${opts.media}-by-day` : `stats-${opts.media}`;
|
|
106981
107053
|
const statsPayload = wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: items2 });
|
|
106982
107054
|
if (await emitCliJsonOrSnapshot(opts, {
|
|
106983
|
-
section
|
|
107055
|
+
section,
|
|
106984
107056
|
commandLabel: "stats",
|
|
106985
|
-
commandHint: opts.media,
|
|
107057
|
+
commandHint: opts.byDay ? `${opts.media}-by-day` : opts.media,
|
|
106986
107058
|
payload: statsPayload,
|
|
106987
|
-
idSuffix: opts.media
|
|
107059
|
+
idSuffix: opts.byDay ? `${opts.media}-by-day` : opts.media
|
|
106988
107060
|
})) {
|
|
106989
107061
|
return;
|
|
106990
107062
|
}
|
|
106991
|
-
const rangeLabel = `${startDate} ~ ${endDate}`;
|
|
107063
|
+
const rangeLabel = opts.byDay ? `${startDate} ~ ${endDate}\uFF08\u6309\u65E5\uFF09` : `${startDate} ~ ${endDate}`;
|
|
106992
107064
|
if (items2.length === 0) {
|
|
106993
107065
|
console.log(`
|
|
106994
107066
|
${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09
|
|
@@ -107001,7 +107073,16 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
|
|
|
107001
107073
|
${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items2.length} \u6761\uFF0C\u5171 ${items2.length} \u6761\uFF09
|
|
107002
107074
|
`
|
|
107003
107075
|
);
|
|
107004
|
-
const cols = [
|
|
107076
|
+
const cols = opts.byDay ? [
|
|
107077
|
+
{ key: "date", header: "\u65E5\u671F" },
|
|
107078
|
+
{ key: "id", header: "\u8D26\u6237ID" },
|
|
107079
|
+
{ key: "name", header: "\u8D26\u6237\u540D\u79F0" },
|
|
107080
|
+
{ key: "spend", header: "\u6D88\u8017" },
|
|
107081
|
+
{ key: "impressions", header: "\u5C55\u793A\u6B21\u6570" },
|
|
107082
|
+
{ key: "clicks", header: "\u70B9\u51FB\u6B21\u6570" },
|
|
107083
|
+
{ key: "conversions", header: "\u8F6C\u5316\u6B21\u6570" },
|
|
107084
|
+
{ key: "cpc", header: "\u70B9\u51FB\u5747\u4EF7" }
|
|
107085
|
+
] : [
|
|
107005
107086
|
{ key: "id", header: "\u8D26\u6237ID" },
|
|
107006
107087
|
{ key: "name", header: "\u8D26\u6237\u540D\u79F0" },
|
|
107007
107088
|
{ key: "spend", header: "\u6D88\u8017" },
|
|
@@ -107019,7 +107100,7 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
|
|
|
107019
107100
|
totalImpressions += item.impressions ?? 0;
|
|
107020
107101
|
totalClicks += item.clicks ?? 0;
|
|
107021
107102
|
totalConversions += item.conversions ?? 0;
|
|
107022
|
-
|
|
107103
|
+
const base = {
|
|
107023
107104
|
id: item.mediaAccountId ?? "",
|
|
107024
107105
|
name: item.mediaCustomerName ?? "",
|
|
107025
107106
|
spend: item.spend?.toFixed(2) ?? "0.00",
|
|
@@ -107028,27 +107109,45 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
|
|
|
107028
107109
|
conversions: String(item.conversions ?? 0),
|
|
107029
107110
|
cpc: item.costPerClick?.toFixed(4) ?? "0.0000"
|
|
107030
107111
|
};
|
|
107112
|
+
return opts.byDay ? { date: item.date ?? "", ...base } : base;
|
|
107031
107113
|
});
|
|
107032
107114
|
if (items2.length > 1) {
|
|
107033
107115
|
const avgCpc = totalClicks > 0 ? (totalSpend / totalClicks).toFixed(4) : "0.0000";
|
|
107034
|
-
rows.push(
|
|
107035
|
-
|
|
107036
|
-
|
|
107037
|
-
|
|
107038
|
-
|
|
107039
|
-
|
|
107040
|
-
|
|
107041
|
-
|
|
107042
|
-
|
|
107116
|
+
rows.push(
|
|
107117
|
+
opts.byDay ? {
|
|
107118
|
+
date: "\u5408\u8BA1",
|
|
107119
|
+
id: "",
|
|
107120
|
+
name: "",
|
|
107121
|
+
spend: totalSpend.toFixed(2),
|
|
107122
|
+
impressions: String(totalImpressions),
|
|
107123
|
+
clicks: String(totalClicks),
|
|
107124
|
+
conversions: String(totalConversions),
|
|
107125
|
+
cpc: avgCpc
|
|
107126
|
+
} : {
|
|
107127
|
+
id: "\u5408\u8BA1",
|
|
107128
|
+
name: "",
|
|
107129
|
+
spend: totalSpend.toFixed(2),
|
|
107130
|
+
impressions: String(totalImpressions),
|
|
107131
|
+
clicks: String(totalClicks),
|
|
107132
|
+
conversions: String(totalConversions),
|
|
107133
|
+
cpc: avgCpc
|
|
107134
|
+
}
|
|
107135
|
+
);
|
|
107043
107136
|
}
|
|
107044
107137
|
printCliTable(rows, cols);
|
|
107045
107138
|
console.log();
|
|
107046
107139
|
}
|
|
107047
107140
|
function register11(program2) {
|
|
107048
|
-
program2.command("stats").description(
|
|
107141
|
+
program2.command("stats").description(
|
|
107142
|
+
"\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\u533A\u95F4\u5408\u8BA1\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF1B\u8981\u6309\u65E5\u660E\u7EC6\u52A0 --by-day\uFF09"
|
|
107143
|
+
).requiredOption(
|
|
107049
107144
|
"-m, --media <type>",
|
|
107050
107145
|
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2 | Kwai"
|
|
107051
|
-
).option("-a, --accounts <ids>", "\u8D26\u6237
|
|
107146
|
+
).option("-a, --accounts <ids>", "\u8D26\u6237 mediaCustomerId\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4 7 \u5929\u524D\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4\u6628\u5929\uFF09").option("--start-date <date>", "\u540C --start\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option("--end-date <date>", "\u540C --end\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option(
|
|
107147
|
+
"--by-day",
|
|
107148
|
+
"\u6309\u65E5\u660E\u7EC6\uFF1A\u5BF9\u533A\u95F4\u5185\u6BCF\u4E00\u5929\u5206\u522B\u62C9\u6570\uFF0Citems[] \u6BCF\u884C\u5E26 date\uFF1B\u5BFC\u51FA Excel/\u6309\u65E5\u8D8B\u52BF\u5FC5\u52A0\u3002\u9ED8\u8BA4\u4E0D\u52A0\u5219\u53EA\u8FD4\u56DE\u533A\u95F4\u5408\u8BA1\u4E00\u884C",
|
|
107149
|
+
false
|
|
107150
|
+
).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option(
|
|
107052
107151
|
"--json-out <path>",
|
|
107053
107152
|
"\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",
|
|
107054
107153
|
void 0
|
|
@@ -107060,6 +107159,7 @@ function register11(program2) {
|
|
|
107060
107159
|
accounts: opts.accounts,
|
|
107061
107160
|
startDate: opts.start ?? opts.startDate,
|
|
107062
107161
|
endDate: opts.end ?? opts.endDate,
|
|
107162
|
+
byDay: opts.byDay,
|
|
107063
107163
|
jsonOut: opts.jsonOut,
|
|
107064
107164
|
verbose: opts.verbose
|
|
107065
107165
|
});
|
package/dist/skill/AGENTS.md
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
| 网站诊断 | `references/report-templates/website-diagnosis-report.md` |
|
|
39
39
|
| 战略市场分析 | `references/report-templates/market-analysis-report.md` |
|
|
40
40
|
| Google 周期 Excel | `references/report-templates/google-period-report-excel.md`(P4) |
|
|
41
|
+
| 账户按日 Excel | `references/report-templates/stats-daily-excel.md`(P4-DAILY) |
|
|
41
42
|
| OKKI 周报 | `references/report-templates/okki-weekly-google-client.md` |
|
|
42
43
|
| 询盘分析 | `references/report-templates/google-inquiry-analysis.md` |
|
|
43
44
|
|
package/dist/skill/SKILL.md
CHANGED
|
@@ -98,6 +98,7 @@ siluzan-tso -h # 查看帮助
|
|
|
98
98
|
| Google 账户 **周期** / **月度** / **季度** 报告 / 月报(**非** OKKI / **非** 询盘 / **非** 强调健康诊断) | **P4** | `references/report-templates/google-period-report.md` + `references/analytics/account-analytics.md`;要 **Excel** 加 `references/report-templates/google-period-report-excel.md` |
|
|
99
99
|
| Meta/Facebook 周期或诊断报告 | **P4-FB** | `references/report-templates/meta-period-report.md` + `assets/meta-period-report-rules.md` + `references/analytics/facebook-analysis-guide.md`;要 Excel 加 `references/report-templates/meta-period-report-excel.md` |
|
|
100
100
|
| TikTok / Bing 周期报告 | **P4** | `references/analytics/account-analytics.md`(tiktok-analysis/bing-analysis)+ 对应 `references/report-templates/*-period-report.md` |
|
|
101
|
+
| 账户级按日 Excel / 按天导出投放数据 | **P4-DAILY** | `references/report-templates/stats-daily-excel.md` |
|
|
101
102
|
| 多账户 × 多维度批处理 | **P5** | `references/analytics/google-analysis-batch.md` + `references/analytics/account-analytics.md` |
|
|
102
103
|
| OKKI 周报 | **P6** | `references/report-templates/okki-weekly-google-client.md`(全文) |
|
|
103
104
|
| Google 询盘分析 | **P7** | `references/report-templates/google-inquiry-analysis.md`(全文)+ `references/analytics/geo-continents.json` |
|
package/dist/skill/_meta.json
CHANGED
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
| ---------------------------------------------------------------- | ------------------------------ |
|
|
86
86
|
| `google-period-report.md` | Google 账户周期/月度报告(P4) |
|
|
87
87
|
| `google-period-report-excel.md` | P4 用户要 Excel |
|
|
88
|
+
| `stats-daily-excel.md` | P4-DAILY 按日 Excel |
|
|
88
89
|
| `meta-period-report.md` / `meta-period-report-excel.md` | Meta 周期(P4-FB) |
|
|
89
90
|
| `google-ads-diagnosis.md` / `google-account-diagnosis-report.md` | Google 诊断(P1) |
|
|
90
91
|
| `website-diagnosis-report.md` | 网站诊断(P8) |
|
|
@@ -118,11 +118,8 @@ siluzan-tso account-active-bills -m <媒体> --id <entityId> [--json-out ./snap]
|
|
|
118
118
|
# 从列表取 entityId
|
|
119
119
|
siluzan-tso list-accounts -m Google --json-out ./snap
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
siluzan-tso account-active-bills -m Google --id
|
|
123
|
-
|
|
124
|
-
# 原始 JSON,便于脚本解析
|
|
125
|
-
siluzan-tso account-active-bills -m Google --id 18176820-6204-43c2-9a1f-0d0f5e9eb957 --json-out ./snap
|
|
121
|
+
siluzan-tso account-active-bills -m Google --id <entityId>
|
|
122
|
+
siluzan-tso account-active-bills -m Google --id <entityId> --json-out ./snap
|
|
126
123
|
```
|
|
127
124
|
|
|
128
125
|
> \*\*勿在文档或聊天中粘贴真实 JWT。
|
|
@@ -233,24 +230,19 @@ siluzan-tso stats -m <媒体类型> [选项]
|
|
|
233
230
|
| `--start <YYYY-MM-DD>` | 开始日期 | 7 天前 |
|
|
234
231
|
| `--end <YYYY-MM-DD>` | 结束日期 | 昨天 |
|
|
235
232
|
| `--start-date` / `--end-date` | 与 `--start` / `--end` 同义(CLI 别名,与 SKILL Playbook 一致) | — |
|
|
233
|
+
| `--by-day` | 按日明细(`items[]` 带 `date`);按日 Excel 见 `stats-daily-excel.md` | 关 |
|
|
236
234
|
| `--json-out` | 输出原始 JSON;**失败时 stdout 仍为 JSON**(`{"ok":false,"error":"..."}`) | — |
|
|
237
235
|
|
|
238
|
-
|
|
236
|
+
**口径(易错)**:默认 **`spend` = 区间合计**(非日消耗)。按日加 `--by-day`;单日可用 `start=end`;日均用 `spend/天数` 或 `balance-scan` 的 `dailySpend`。
|
|
239
237
|
|
|
240
238
|
**示例:**
|
|
241
239
|
|
|
242
240
|
```bash
|
|
243
|
-
|
|
244
|
-
siluzan-tso stats -m Google -a
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
siluzan-tso stats -m Google -a
|
|
248
|
-
|
|
249
|
-
# 查询多个 Bing 账户消耗
|
|
250
|
-
siluzan-tso stats -m BingV2 -a 1234567890,9876543210 --start 2026-03-01
|
|
251
|
-
|
|
252
|
-
# JSON 输出
|
|
253
|
-
siluzan-tso stats -m Google -a 6326027735 --json-out ./snap
|
|
241
|
+
siluzan-tso stats -m Google -a <id>
|
|
242
|
+
siluzan-tso stats -m Google -a <id> --start 2026-03-01 --end 2026-03-31
|
|
243
|
+
siluzan-tso stats -m Yandex -a <id> --start <S> --end <E> --by-day --json-out ./snap/daily.json
|
|
244
|
+
siluzan-tso stats -m BingV2 -a <id1>,<id2> --start 2026-03-01
|
|
245
|
+
siluzan-tso stats -m Google -a <id> --json-out ./snap
|
|
254
246
|
```
|
|
255
247
|
|
|
256
248
|
---
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
- **数据时效性**:涉及「今天/当天/今日消耗」「实时消耗排行」前,必读 `references/analytics/account-analytics.md` 顶部「数据时效性」表。TikTok / Yandex / BingV2 / Kwai 是 `accountsoverview` 同步昨天数据,**不能查今天**。
|
|
111
111
|
- **先查账户再操作**:`list-accounts -m [mediaType] -k [mediaCustomerId]`;用户给出的 `mediaCustomerId` 必须 `-k` 核验,无结果则告知用户并停止,**禁止**翻页 grep 自行换 ID(会导致报告错户);拉数、脚本、报告文件名全链路用同一 ID(以 stdout `accountId` 为准)。**Google 额外建议**:`list-accounts` 命中后、拉数前可 `account check-access -a <mediaCustomerId>` 校验 Google 网关访问权限;`no_permission`(403)通常表示账户不在当前丝路赞账号下。
|
|
112
112
|
- **不猜测账户 ID**:`entityId` ≠ `mediaCustomerId`,两者均来自 `list-accounts`;**禁止**把 `entityId` 传给 `stats -a` / `balance -a`。
|
|
113
|
-
- **媒体类型区分大小写**:`Google`、`TikTok`、`MetaAd`、`BingV2`、`Kwai`。
|
|
113
|
+
- **媒体类型区分大小写**:`Google`、`TikTok`、`Yandex`、`MetaAd`、`BingV2`、`Kwai`。
|
|
114
114
|
- **CLI 输出忠实**:数值与 ID 须与本次落盘 JSON / stdout 一致,不编造示例 ID;`data` 为空时只说「当前返回无记录」并附 JSON 路径。
|
|
115
115
|
- **破坏性操作必须确认 + `--commit`**:账户解绑/关闭/取消分享、BC/MCC 解绑、删除预警/报告/广告/关键词、发票申请、广告发布等。
|
|
116
116
|
- **不确定时读文档**:先读对应 references 或用 `-h`,不要猜参数。
|
|
@@ -199,6 +199,7 @@
|
|
|
199
199
|
| --------------------------- | -------------------------------------------------------------------------------------- | -------------------------------- |
|
|
200
200
|
| 多账户余额 / 预算不足预警 | `balance-scan -m <媒体> --threshold-days 7`(用 **`dailySpend`** / `remainingDays`) | 逐账户 `balance --accounts ...`;把 `stats` 多日 **`spend` 当「日消耗」** |
|
|
201
201
|
| 多账户投放画像 | `accounts-digest -m <媒体> [-a ...] --start --end --json-out`(**`spend`=区间合计**) | 逐账户 `stats`;把合计 `spend` 说成「每天花了」 |
|
|
202
|
+
| 单户按日 Excel | `stats … --by-day --json-out`(P4-DAILY) | 默认 `stats` 当按日 |
|
|
202
203
|
| 多账户 × 多维度 Google 数据 | 全量:`google-analysis-batch run`(省略 `-a`);2~10:`google-analysis -a id1,id2,...` | 外层 for-loop;先 list 再拼 `-a` |
|
|
203
204
|
| 多系列诊断 | `ad campaigns --json-out` + node 读文件过滤 | 逐系列 `ad campaign-get` |
|
|
204
205
|
| 单日预算熔断 / 当日花费比日预算 | `ad campaigns --start <当日> --end <当日>`(**start=end**)后再比 `spend` 与 `budget` | 用默认近 7 天窗口的 `spend` 对比日预算 |
|
|
@@ -219,7 +220,7 @@
|
|
|
219
220
|
|
|
220
221
|
先用位数判断类型,不确定再 `list-accounts -m [mediaType] -k [id]`:
|
|
221
222
|
|
|
222
|
-
- Google: `454xxx5137` 或 `270-xxx-0720
|
|
223
|
+
- Google: `454xxx5137` 或 `270-xxx-0720`
|
|
223
224
|
- TikTok: `70083497xxx59820033`
|
|
224
225
|
- Meta(Facebook): `1716030xxx734076`
|
|
225
226
|
- Bing: `138xxx763`
|
|
@@ -164,6 +164,7 @@
|
|
|
164
164
|
| **P9** | **行业 / 市场 / 战略**(**无网址主诉求**) | 市场分析、**行业分析**、**行业分析报告**、市场调查报告、战略市场报告、KA 市场报告、竞品/GTM、「写一份 **XX 行业** 报告」(电商/制造/医疗…) | 客户名 / 行业 / 核心产品 **至少一项**(**不是** URL+诊断) | HTML(`market-analysis render`) |
|
|
165
165
|
| **P1** | **单个 Google 广告账户** 的投放健康 / 诊断 | Google **广告**诊断、**账户**诊断报告、投放诊断、**账户**健康检查、**账户**体检(**且含 Google 账户 ID**) | 账户 ID + 统计区间 | HTML(`google-ads-diagnosis render`) |
|
|
166
166
|
| **P4** | **单个媒体广告账户** 某区间的 **周期汇总** | 周期报告、月度报告、季度报告、月报、投放月报、Google 账户报告(**未强调「诊断/健康/网站/网址」**) | 媒体 + 账户 ID + 区间 | HTML(默认);用户要 Excel 见 P4 excel 纲要 |
|
|
167
|
+
| **P4-DAILY** | **账户级按日表**(无多维) | 按天导出、投放数据 Excel(非 Google/Meta 周期报告) | 媒体 + 账户 ID + 区间 | xlsx(`stats --by-day`) |
|
|
167
168
|
| **P4-FB** | **Meta/Facebook 账户** 周期或诊断 | Facebook 报告、Meta 月报、FB **账户**诊断报告 | Meta 账户 ID + 区间 | HTML(`facebook-analysis render`) |
|
|
168
169
|
| **P6** | **OKKI 周报**(固定客户模板) | 见 §三魔法短语 | 账户 ID + 区间 | 多 Sheet xlsx |
|
|
169
170
|
| **P7** | **Google 账户 + 询盘** 效果 | 见 §三魔法短语 | 账户 + 分析月 + 询盘资料 | 8 Sheet xlsx |
|
|
@@ -190,7 +191,7 @@
|
|
|
190
191
|
| 用户侧重点 | 正确工作流 |
|
|
191
192
|
| ---------------------------------------------- | -------------------------------- |
|
|
192
193
|
| 给了 **Google 账户 ID**,要健康/诊断/优化建议 | **P1**(`google-ads-diagnosis`) |
|
|
193
|
-
| 给了 **账户 ID**,要某月/某季 **投放数据汇总** | **P4**
|
|
194
|
+
| 给了 **账户 ID**,要某月/某季 **投放数据汇总** | **P4**(按日表无多维 → **P4-DAILY**) |
|
|
194
195
|
| 给了 **URL / 网址 / 域名** + 诊断类词(§零) | **P8** |
|
|
195
196
|
| 只给 **行业名**(无 URL),要行业分析 | **P9** |
|
|
196
197
|
|
|
@@ -73,6 +73,15 @@
|
|
|
73
73
|
- **交付/确认**:按 conventions §七 自检;`accountId` 须与用户给的 `mediaCustomerId` 一致。
|
|
74
74
|
|
|
75
75
|
> 用户用「OKKI 周报」固定话术 → 改走 **P6**,不按默认 8 维追问。
|
|
76
|
+
> 只要账户级按日 Excel(无多维章节)→ **P4-DAILY**。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## P4-DAILY · 按日投放 Excel
|
|
81
|
+
|
|
82
|
+
- **触发**:按天导出 / 投放数据做成 Excel(非 Google/Meta 多维报告)。
|
|
83
|
+
- **必读**:`references/report-templates/stats-daily-excel.md`。
|
|
84
|
+
- **步骤**:核验账户 → `stats … --by-day --json-out` → 脚本写 xlsx。
|
|
76
85
|
|
|
77
86
|
---
|
|
78
87
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
- **步骤**:
|
|
29
29
|
1. 列表/数量:`list-accounts -m <媒体> --page-size 999 --json-out ./snap`,脚本读 `list-accounts-*.json` 的 `total` / `items[]`(**禁止**默认 20 条再翻页)。
|
|
30
30
|
2. 单户余额:`balance -m <媒体> -a <mediaCustomerId>`。
|
|
31
|
-
3. 单户消耗:`stats -m <媒体> -a <mediaCustomerId> --start <S> --end <D
|
|
31
|
+
3. 单户消耗:`stats -m <媒体> -a <mediaCustomerId> --start <S> --end <D>`(按日 Excel → **P4-DAILY**;多账户对比 → **P3**)。
|
|
32
32
|
4. 激活账单:先取 `entityId` → `account-active-bills -m <媒体> --id <entityId> --json-out ./snap`。
|
|
33
33
|
- **交付/确认**:多账户余额预警走 **P2**、消耗汇总走 **P3**。
|
|
34
34
|
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
22
|
| `google-period-report.md` | **Google 周期分析报告(默认)**:终稿=HTML,四步流程 → `google-analysis render` 出 HTML |
|
|
23
23
|
| `google-period-report-excel.md` | **仅用户要 Excel 时**(P4 定制 Sheet):先 `*.outline.txt` 后脚本写 xlsx;账户须 `-k` 核验,无 CLI excel 子命令 |
|
|
24
|
+
| `stats-daily-excel.md` | **P4-DAILY**:账户级按日 Excel(`stats --by-day`) |
|
|
24
25
|
| `google-account-diagnosis-report.md` | Google 账户深度诊断(健康度/转化/结构等) |
|
|
25
26
|
| `google-ads-diagnosis.md` | Google **广告诊断**完整纲要(HTML 区块、**每日趋势 2 位小数**、**每模块必填分析/建议**) |
|
|
26
27
|
| `meta-period-report.md` / `.html` | **Meta(Facebook)周期报告(默认)**:四步流程 → `facebook-analysis render` 出 HTML,见 P4-FB |
|
|
@@ -129,7 +129,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
129
129
|
|
|
130
130
|
### 6. `landingPageAnalysis.desktop` / `mobile` 禁止被整体覆盖丢弃
|
|
131
131
|
|
|
132
|
-
- `collect` 产出的 `landingPageAnalysis` 结构固定为 `{ desktop: {score, firstContentfulPaint, firstMeaningfulPaint, speedIndex}, mobile: {...}, source?, simpleDiagnosis? }`;Agent 撰写终稿时**只能在这个对象上追加** `analysis`/`suggestions`,**禁止**把整个 `landingPageAnalysis` 替换成仅剩 `{analysis, suggestions}
|
|
132
|
+
- `collect` 产出的 `landingPageAnalysis` 结构固定为 `{ desktop: {score, firstContentfulPaint, firstMeaningfulPaint, speedIndex}, mobile: {...}, source?, simpleDiagnosis? }`;Agent 撰写终稿时**只能在这个对象上追加** `analysis`/`suggestions`,**禁止**把整个 `landingPageAnalysis` 替换成仅剩 `{analysis, suggestions}`(否则会丢掉全部 Lighthouse 测速数字)。
|
|
133
133
|
- `render` 会在同目录存在 `google-ads-diagnosis-collect.json` 时自动从 collect 恢复缺失/损坏的 `desktop`/`mobile`(保留 Agent 写的 `analysis`/`suggestions`),但**不能依赖这个兜底**——终稿应本就保留完整字段。
|
|
134
134
|
- 若 `source` 为 `simple`/`none`,或 `desktop`/`mobile` 全 0(未测到),`analysis` 须说明数据未获取/已降级,并引用 `simpleDiagnosis`(若有);**禁止**编造评分,**禁止**把「数据缺失」写进 `keyIssues`。
|
|
135
135
|
- **`analysis` / `suggestions` 只能谈着陆页**(测速、HTTPS、表单、追踪、加载体验)。**禁止**在 §07 写关键词花费/CPA/匹配类型等(那些属于 §08);render 会拦截「只谈关键词、不谈着陆页」的 analysis。
|
|
@@ -22,16 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
-
## 账户 ID
|
|
25
|
+
## 账户 ID
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **必须**:`list-accounts -m Google -k <该 ID>` 单户查询;404 / 空列表 → 告知用户 ID 不存在,**停止**,不得换号继续。
|
|
30
|
-
- **禁止**:`list-accounts` 翻页 + `grep` 猜账户;禁止把列表里「看起来像」的另一账户(如 `9322098303`)当作用户要的 ID。
|
|
31
|
-
- **禁止**:目录名用用户 ID、但 `google-analysis -a` 或脚本里读文件用另一个 ID。
|
|
32
|
-
- **禁止**:`entityId` 与 `mediaCustomerId` 混用(见 `agent-conventions.md`)。
|
|
33
|
-
|
|
34
|
-
核验通过后,在报告首行/封面写:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:XXX)`,且账户 ID 与 `list-accounts` 输出一致。
|
|
27
|
+
`list-accounts -m Google -k <id>` 核验;全流程用同一 `mediaCustomerId`(见 `agent-conventions.md`)。报告首行:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:XXX)`。
|
|
35
28
|
|
|
36
29
|
---
|
|
37
30
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
2. **统计区间**:`--start` / `--end`(用户未给齐时按 SKILL 反问;授权默认时可用「上一完整自然周」白名单并写明)。
|
|
17
17
|
3. **询盘口径**:默认使用区间内 `conversions`(转化次数,来自 `stats` 或 `overview`)。若运营定义为某类转化,须在首段脚注说明(必要时补拉 `google-analysis --sections conversion-actions` 仅作说明)。
|
|
18
18
|
4. **日期写法**:`2026.4.1`、`2026/4/1` 等先规范为 `YYYY-MM-DD`(如 `2026-04-01`)再传 `--start` / `--end`。
|
|
19
|
+
5. **交付**:用户要可复制话术 → 优先纯文本;否则默认话术 + Excel。
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# 账户按日投放数据 Excel(stats --by-day)
|
|
2
|
+
|
|
3
|
+
> 账户级**按日**消耗表 → Excel。≠ P4 / P4-FB / P1。无 CLI excel 子命令。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
siluzan-tso list-accounts -m <媒体> -k <id> --json-out ./snap
|
|
7
|
+
siluzan-tso stats -m <媒体> -a <id> --start <S> --end <E> --by-day --json-out ./snap/daily.json
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
脚本读 `items[]`(含 `date`、`spend`、`impressions`、`clicks`、`conversions` 等)写 xlsx。建议 Sheet:每日明细 + 汇总。ID 列文本;CTR/CPA 由脚本派生。
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
22
|
| `google-period-report.md` | **Google 周期分析报告(默认)**:终稿=HTML,四步流程 → `google-analysis render` 出 HTML |
|
|
23
23
|
| `google-period-report-excel.md` | **仅用户要 Excel 时**(P4 定制 Sheet):先 `*.outline.txt` 后脚本写 xlsx;账户须 `-k` 核验,无 CLI excel 子命令 |
|
|
24
|
+
| `stats-daily-excel.md` | **P4-DAILY**:账户级按日 Excel(`stats --by-day`) |
|
|
24
25
|
| `google-account-diagnosis-report.md` | Google 账户深度诊断(健康度/转化/结构等) |
|
|
25
26
|
| `google-ads-diagnosis.md` | Google **广告诊断**完整纲要(HTML 区块、**每日趋势 2 位小数**、**每模块必填分析/建议**) |
|
|
26
27
|
| `meta-period-report.md` / `.html` | **Meta(Facebook)周期报告(默认)**:四步流程 → `facebook-analysis render` 出 HTML,见 P4-FB |
|
|
@@ -129,7 +129,7 @@ siluzan-tso google-ads-diagnosis render \
|
|
|
129
129
|
|
|
130
130
|
### 6. `landingPageAnalysis.desktop` / `mobile` 禁止被整体覆盖丢弃
|
|
131
131
|
|
|
132
|
-
- `collect` 产出的 `landingPageAnalysis` 结构固定为 `{ desktop: {score, firstContentfulPaint, firstMeaningfulPaint, speedIndex}, mobile: {...}, source?, simpleDiagnosis? }`;Agent 撰写终稿时**只能在这个对象上追加** `analysis`/`suggestions`,**禁止**把整个 `landingPageAnalysis` 替换成仅剩 `{analysis, suggestions}
|
|
132
|
+
- `collect` 产出的 `landingPageAnalysis` 结构固定为 `{ desktop: {score, firstContentfulPaint, firstMeaningfulPaint, speedIndex}, mobile: {...}, source?, simpleDiagnosis? }`;Agent 撰写终稿时**只能在这个对象上追加** `analysis`/`suggestions`,**禁止**把整个 `landingPageAnalysis` 替换成仅剩 `{analysis, suggestions}`(否则会丢掉全部 Lighthouse 测速数字)。
|
|
133
133
|
- `render` 会在同目录存在 `google-ads-diagnosis-collect.json` 时自动从 collect 恢复缺失/损坏的 `desktop`/`mobile`(保留 Agent 写的 `analysis`/`suggestions`),但**不能依赖这个兜底**——终稿应本就保留完整字段。
|
|
134
134
|
- 若 `source` 为 `simple`/`none`,或 `desktop`/`mobile` 全 0(未测到),`analysis` 须说明数据未获取/已降级,并引用 `simpleDiagnosis`(若有);**禁止**编造评分,**禁止**把「数据缺失」写进 `keyIssues`。
|
|
135
135
|
- **`analysis` / `suggestions` 只能谈着陆页**(测速、HTTPS、表单、追踪、加载体验)。**禁止**在 §07 写关键词花费/CPA/匹配类型等(那些属于 §08);render 会拦截「只谈关键词、不谈着陆页」的 analysis。
|
|
@@ -22,16 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
-
## 账户 ID
|
|
25
|
+
## 账户 ID
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **必须**:`list-accounts -m Google -k <该 ID>` 单户查询;404 / 空列表 → 告知用户 ID 不存在,**停止**,不得换号继续。
|
|
30
|
-
- **禁止**:`list-accounts` 翻页 + `grep` 猜账户;禁止把列表里「看起来像」的另一账户(如 `9322098303`)当作用户要的 ID。
|
|
31
|
-
- **禁止**:目录名用用户 ID、但 `google-analysis -a` 或脚本里读文件用另一个 ID。
|
|
32
|
-
- **禁止**:`entityId` 与 `mediaCustomerId` 混用(见 `agent-conventions.md`)。
|
|
33
|
-
|
|
34
|
-
核验通过后,在报告首行/封面写:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:XXX)`,且账户 ID 与 `list-accounts` 输出一致。
|
|
27
|
+
`list-accounts -m Google -k <id>` 核验;全流程用同一 `mediaCustomerId`(见 `agent-conventions.md`)。报告首行:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:XXX)`。
|
|
35
28
|
|
|
36
29
|
---
|
|
37
30
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
2. **统计区间**:`--start` / `--end`(用户未给齐时按 SKILL 反问;授权默认时可用「上一完整自然周」白名单并写明)。
|
|
17
17
|
3. **询盘口径**:默认使用区间内 `conversions`(转化次数,来自 `stats` 或 `overview`)。若运营定义为某类转化,须在首段脚注说明(必要时补拉 `google-analysis --sections conversion-actions` 仅作说明)。
|
|
18
18
|
4. **日期写法**:`2026.4.1`、`2026/4/1` 等先规范为 `YYYY-MM-DD`(如 `2026-04-01`)再传 `--start` / `--end`。
|
|
19
|
+
5. **交付**:用户要可复制话术 → 优先纯文本;否则默认话术 + Excel。
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# 账户按日投放数据 Excel(stats --by-day)
|
|
2
|
+
|
|
3
|
+
> 账户级**按日**消耗表 → Excel。≠ P4 / P4-FB / P1。无 CLI excel 子命令。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
siluzan-tso list-accounts -m <媒体> -k <id> --json-out ./snap
|
|
7
|
+
siluzan-tso stats -m <媒体> -a <id> --start <S> --end <E> --by-day --json-out ./snap/daily.json
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
脚本读 `items[]`(含 `date`、`spend`、`impressions`、`clicks`、`conversions` 等)写 xlsx。建议 Sheet:每日明细 + 汇总。ID 列文本;CTR/CPA 由脚本派生。
|
|
@@ -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.37-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.37-beta.13'
|
|
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.37-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.37-beta.13"
|
|
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"
|