siluzan-tso-cli 1.1.37-beta.12 → 1.1.37-beta.14

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +197 -94
  3. package/dist/skill/AGENTS.md +18 -51
  4. package/dist/skill/SKILL.md +58 -69
  5. package/dist/skill/_meta.json +2 -2
  6. package/dist/skill/assets/campaign-create-template.md +1 -1
  7. package/dist/skill/references/README.md +14 -6
  8. package/dist/skill/references/accounts/accounts-balance-stats.md +167 -0
  9. package/dist/skill/references/accounts/accounts-list.md +170 -0
  10. package/dist/skill/references/accounts/accounts-permissions.md +481 -0
  11. package/dist/skill/references/accounts/accounts.md +18 -939
  12. package/dist/skill/references/accounts/currency.md +2 -2
  13. package/dist/skill/references/accounts/finance.md +11 -0
  14. package/dist/skill/references/accounts/open-account-by-media.md +16 -0
  15. package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
  16. package/dist/skill/references/analytics/account-analytics.md +14 -0
  17. package/dist/skill/references/analytics/google-analysis-batch.md +16 -0
  18. package/dist/skill/references/analytics/keyword-planner-workflows.md +18 -4
  19. package/dist/skill/references/analytics/rag.md +1 -1
  20. package/dist/skill/references/analytics/reporting.md +1 -1
  21. package/dist/skill/references/analytics/website-diagnosis-guide.md +1 -1
  22. package/dist/skill/references/core/agent-conventions.md +46 -30
  23. package/dist/skill/references/core/intent-routing.md +18 -1
  24. package/dist/skill/references/core/playbooks.md +19 -10
  25. package/dist/skill/references/core/skill-authoring.md +35 -0
  26. package/dist/skill/references/core/tips.md +18 -4
  27. package/dist/skill/references/core/workflows.md +14 -14
  28. package/dist/skill/references/google-ads/google-ads-batch.md +66 -0
  29. package/dist/skill/references/google-ads/google-ads-campaign-plan.md +4 -4
  30. package/dist/skill/references/google-ads/google-ads-read.md +272 -0
  31. package/dist/skill/references/google-ads/google-ads-write.md +400 -0
  32. package/dist/skill/references/google-ads/google-ads.md +14 -659
  33. package/dist/skill/references/google-ads/rules/README.md +20 -18
  34. package/dist/skill/references/google-ads/rules/google-ads-account-audit-assets.md +284 -0
  35. package/dist/skill/references/google-ads/rules/google-ads-account-audit-quick.md +223 -0
  36. package/dist/skill/references/google-ads/rules/google-ads-account-audit-report.md +79 -0
  37. package/dist/skill/references/google-ads/rules/google-ads-account-audit-structure.md +123 -0
  38. package/dist/skill/references/google-ads/rules/google-ads-account-audit.md +31 -652
  39. package/dist/skill/references/google-ads/rules/google-ads-compliance-copy.md +201 -0
  40. package/dist/skill/references/google-ads/rules/google-ads-compliance-forbid.md +280 -0
  41. package/dist/skill/references/google-ads/rules/google-ads-compliance-ops.md +151 -0
  42. package/dist/skill/references/google-ads/rules/google-ads-compliance.md +24 -587
  43. package/dist/skill/references/google-ads/rules/google-ads-launch-plan-template.md +1 -1
  44. package/dist/skill/references/operations/hosted-automation-monitoring-json.md +1 -1
  45. package/dist/skill/references/operations/hosted-automation-optimize-index.md +1 -1
  46. package/dist/skill/references/operations/hosted-automation-optimize-scale.md +2 -2
  47. package/dist/skill/references/operations/hosted-automation-optimize-weak-downbid.md +1 -1
  48. package/dist/skill/references/operations/hosted-automation-scenarios.md +2 -2
  49. package/dist/skill/references/operations/hosted-automation-self-control.md +14 -2
  50. package/dist/skill/references/operations/hosted-automation-user-catalog.md +35 -27
  51. package/dist/skill/references/report-templates/README.md +1 -0
  52. package/dist/skill/references/report-templates/REPORT-WORKFLOW.md +3 -1
  53. package/dist/skill/references/report-templates/google-ads-diagnosis.md +23 -2
  54. package/dist/skill/references/report-templates/google-inquiry-analysis.md +18 -0
  55. package/dist/skill/references/report-templates/google-period-report-excel.md +2 -9
  56. package/dist/skill/references/report-templates/okki-weekly-google-client.md +14 -0
  57. package/dist/skill/references/report-templates/stats-daily-excel.md +10 -0
  58. package/dist/skill/report-templates/README.md +1 -0
  59. package/dist/skill/report-templates/REPORT-WORKFLOW.md +3 -1
  60. package/dist/skill/report-templates/google-ads-diagnosis.md +23 -2
  61. package/dist/skill/report-templates/google-inquiry-analysis.md +18 -0
  62. package/dist/skill/report-templates/google-period-report-excel.md +2 -9
  63. package/dist/skill/report-templates/okki-weekly-google-client.md +14 -0
  64. package/dist/skill/report-templates/stats-daily-excel.md +10 -0
  65. package/dist/skill/scripts/install.ps1 +1 -1
  66. package/dist/skill/scripts/install.sh +1 -1
  67. 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.12),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.37-beta.14),供内部测试使用。正式发布后安装命令将改为 `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
- if (!input || !input.trim()) return [];
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
- const out = [];
103799
- const seen = /* @__PURE__ */ new Set();
103800
- for (const raw of input.split(",")) {
103801
- const id = raw.trim();
103802
- if (!id) continue;
103803
- if (!/^\d+$/.test(id)) {
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
- process.exit(1);
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 isNumeric = /^\d+$/.test(opts.keyword.trim());
105997
- if (isNumeric) {
105998
- params.set(platformCfg.idSearchParam, opts.keyword.trim());
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) params.set("keyword", 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 (isGoogle) {
106918
- const params = new URLSearchParams({ startDate, endDate, mediaCustomerIds: ids.join("|") });
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
- for (const [route, routeIds] of groupAccountIdsByOverviewRoute(
106937
- "MetaAd",
106938
- ids,
106939
- accountMediaTypes
106940
- )) {
106941
- const map = await fetchOverviewMap(
106942
- route,
106943
- routeIds,
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
- startDate,
106946
- endDate,
107023
+ day,
107024
+ day,
106947
107025
  opts.verbose
106948
107026
  );
106949
- for (const item of map.values()) {
106950
- items2.push(item);
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
- const map = await fetchOverviewMap(
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: `stats-${opts.media}`,
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
- return {
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
- id: "\u5408\u8BA1",
107036
- name: "",
107037
- spend: totalSpend.toFixed(2),
107038
- impressions: String(totalImpressions),
107039
- clicks: String(totalClicks),
107040
- conversions: String(totalConversions),
107041
- cpc: avgCpc
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("\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF09").requiredOption(
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 ID\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u7559\u7A7A\u5219\u67E5\u5168\u90E8\u8D26\u6237\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("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option(
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
  });
@@ -131871,7 +131971,10 @@ configureCliJsonSnapshot({
131871
131971
  fieldGuideRefs: [
131872
131972
  "references/accounts/currency.md",
131873
131973
  "references/core/tips.md",
131874
- "references/accounts/accounts.md"
131974
+ "references/accounts/accounts.md",
131975
+ "references/accounts/accounts-list.md",
131976
+ "references/accounts/accounts-balance-stats.md",
131977
+ "references/accounts/accounts-permissions.md"
131875
131978
  ]
131876
131979
  });
131877
131980
  var program = new Command5();
@@ -1,61 +1,28 @@
1
1
  # siluzan-tso — Agent 文档目录
2
2
 
3
- > 单一 Skill 包(`name: siluzan-tso`)。运行时入口:`SKILL.md` → 按域 lazy-load `references/`。
3
+ > 运行时入口:`SKILL.md` → 按路由表 Read **leaf** 文档。维护时对齐 `references/core/skill-authoring.md`。
4
4
 
5
5
  ## 启动顺序
6
6
 
7
- 1. Read `SKILL.md`(单一路由表:意图 → 工作流 → 必读文档)
8
- 2. **每个新任务** Read `references/core/agent-conventions.md`
9
- 3. 按路由表 Read「必读文档」与对应工作流卡片,再执行 `siluzan-tso …`:
10
- - 分析/报告类线性步骤 → `references/core/playbooks.md`(P1–P9)
11
- - 操作/管理类线性步骤 → `references/core/workflows.md`(W1–W12)
12
- - 命令参数/字段口径 → 各域 `references/*.md`
13
- 4. **P5 / P6 / P7** 或长 CLI 输出:可选 Read `references/core/subagent-orchestration.md`(主 Agent 自行决定是否委派 subagent)
7
+ 1. Read `SKILL.md` 路由表,锁定唯一工作流
8
+ 2. 报告类模糊 → Read `references/core/intent-routing.md`
9
+ 3. Read 路由行「必读文档」+ 对应 `playbooks.md` / `workflows.md` 卡片(**直接读 leaf**,不必先经 `accounts.md` 索引)
10
+ 4. 写操作 / 报告交付 / 批量拉数 → Read `references/core/agent-conventions.md` 相关节
11
+ 5. P5/P6/P7 或长 CLI:可选 `references/core/subagent-orchestration.md`
14
12
 
15
- ## 文档域(gstack-style domains)
13
+ ## 文档域
16
14
 
17
- | 域 | 路径 | 何时 Read |
18
- | -------------- | -------------------------------------------------------------------- | -------------------------------------------------------------- |
19
- | **Core** | `references/core/` | 纪律、安装、tips、playbooks、workflows、subagent-orchestration |
20
- | **Handoff** | `snippets/` | P5/P6/P7 Task 派发模板(与 SKILL 同级) |
21
- | **Accounts** | `references/accounts/` | 列表、余额、开户、财务、审计 |
22
- | **Google Ads** | `references/google-ads/` | CRUD、PMax、搜索系列流水线;`rules/` 为优化 SOP |
23
- | **Analytics** | `references/analytics/` | 拉数、批处理、拓词、RAG、TSO 报告 |
24
- | **Operations** | `references/operations/` | 预警、线索、优化记录、宿主编排自动化 |
25
- | **Templates** | `assets/`、`references/report-templates/`、`report-templates/*.html` | JSON 契约、报告纲要、HTML 样式 |
26
-
27
- ## 工作流目录
28
-
29
- | 类别 | 文档 | 编号 |
30
- | ------------- | ------------------------------ | ------ |
31
- | 分析 / 报告类 | `references/core/playbooks.md` | P1–P9 |
32
- | 操作 / 管理类 | `references/core/workflows.md` | W1–W12 |
33
-
34
- 专用报告模板(被工作流卡片引用):
35
-
36
- | ID | 文档 |
37
- | ----------------- | ----------------------------------------------------------------- |
38
- | 网站诊断 | `references/report-templates/website-diagnosis-report.md` |
39
- | 战略市场分析 | `references/report-templates/market-analysis-report.md` |
40
- | Google 周期 Excel | `references/report-templates/google-period-report-excel.md`(P4) |
41
- | OKKI 周报 | `references/report-templates/okki-weekly-google-client.md` |
42
- | 询盘分析 | `references/report-templates/google-inquiry-analysis.md` |
15
+ | 域 | 路径 | 何时 Read |
16
+ | -- | ---- | --------- |
17
+ | Core | `references/core/` | 纪律、intent-routing、playbooks、workflows |
18
+ | Accounts | `references/accounts/` | `accounts-list` / `accounts-balance-stats` / `accounts-permissions`(`accounts.md` 仅索引) |
19
+ | Google Ads | `references/google-ads/` | `google-ads-read` / `write` / `batch`(索引:`google-ads.md`);`rules/` 先 README 再单文件 |
20
+ | Analytics | `references/analytics/` | 拉数、批处理、拓词、RAG |
21
+ | Operations | `references/operations/` | 预警、线索;自动化仅用户问起时 |
22
+ | Templates | `report-templates/*.md`、`assets/` | 报告纲要 / JSON 契约;**禁止** Read `*.html` |
43
23
 
44
24
  ## 维护
45
25
 
46
- - 源码唯一真相:`tso-cli/assets/siluzan-ads/`(勿编辑 `skills/siluzan-tso/` 副本)
47
- - 通用纪律唯一真相源:`references/core/agent-conventions.md`(其他文档只单行指向,不复制规则)
48
-
49
- ## CLI 代码域(与文档对齐)
50
-
51
- | CLI 模块 | 文档域 |
52
- | ----------------------------------------------------------------------- | ------------------------------------- |
53
- | `src/commands/list-accounts/`、`accounts-digest/`、`balance-scan/` | accounts |
54
- | `src/commands/open-account/`、`account-manage-register.ts` | accounts |
55
- | `src/commands/ad/` | google-ads |
56
- | `src/commands/google-analysis/`、`google-analysis-batch.ts` | analytics |
57
- | `src/commands/facebook-analysis/`、`bing-analysis/`、`tiktok-analysis/` | analytics(架构对齐 google-analysis) |
58
- | `src/commands/website-diagnosis/` | analytics(网站诊断) |
59
- | `src/commands/market-analysis/` | analytics(战略市场分析) |
60
- | `src/commands/report/` | analytics + report-templates |
61
- | `src/commands/forewarning/`、`optimize/`、`clue.ts` | operations |
26
+ - 源码:`tso-cli/assets/siluzan-ads/`
27
+ - 纪律真相源:`references/core/agent-conventions.md`
28
+ - 规范:`references/core/skill-authoring.md`