siluzan-tso-cli 1.1.42 → 1.1.43-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/index.js +151 -54
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/google-period-report.schema.json +2 -2
- package/dist/skill/references/accounts/accounts-list.md +1 -1
- package/dist/skill/references/accounts/accounts-permissions.md +2 -2
- package/dist/skill/references/accounts/finance.md +1 -1
- package/dist/skill/references/accounts/open-account-by-media.md +1 -1
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/agent-conventions.md +17 -3
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/workflows.md +8 -6
- package/dist/skill/references/google-ads/google-ads-campaign-plan.md +3 -2
- package/dist/skill/references/google-ads/google-ads-write.md +1 -0
- package/dist/skill/references/google-ads/rules/google-ads-plan-source-fidelity.md +10 -9
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/references/report-templates/google-period-report.md +3 -3
- package/dist/skill/report-templates/google-period-report.md +3 -3
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板外部资源:**ECharts** 统一使用 `https://staticpn.siluz
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli@beta
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,6 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
> **注意**:当前为测试版(1.1.43-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
54
55
|
|
|
55
56
|
| 助手 | 建议 `--ai` |
|
|
56
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -4026,7 +4026,7 @@ var DEFAULT_API_BASE;
|
|
|
4026
4026
|
var init_defaults = __esm({
|
|
4027
4027
|
"src/config/defaults.ts"() {
|
|
4028
4028
|
"use strict";
|
|
4029
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
4029
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
4030
4030
|
}
|
|
4031
4031
|
});
|
|
4032
4032
|
|
|
@@ -5544,6 +5544,32 @@ var init_daily_metrics_range = __esm({
|
|
|
5544
5544
|
}
|
|
5545
5545
|
});
|
|
5546
5546
|
|
|
5547
|
+
// src/utils/snapshot/async-lock.ts
|
|
5548
|
+
async function withAsyncLock(key, fn) {
|
|
5549
|
+
const prev = chains.get(key) ?? Promise.resolve();
|
|
5550
|
+
let release;
|
|
5551
|
+
const gate = new Promise((resolve21) => {
|
|
5552
|
+
release = resolve21;
|
|
5553
|
+
});
|
|
5554
|
+
chains.set(
|
|
5555
|
+
key,
|
|
5556
|
+
prev.catch(() => void 0).then(() => gate)
|
|
5557
|
+
);
|
|
5558
|
+
await prev.catch(() => void 0);
|
|
5559
|
+
try {
|
|
5560
|
+
return await fn();
|
|
5561
|
+
} finally {
|
|
5562
|
+
release();
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
var chains;
|
|
5566
|
+
var init_async_lock = __esm({
|
|
5567
|
+
"src/utils/snapshot/async-lock.ts"() {
|
|
5568
|
+
"use strict";
|
|
5569
|
+
chains = /* @__PURE__ */ new Map();
|
|
5570
|
+
}
|
|
5571
|
+
});
|
|
5572
|
+
|
|
5547
5573
|
// src/commands/google-analysis/wrap-snapshot-envelope.ts
|
|
5548
5574
|
function coerceToRowArray(value) {
|
|
5549
5575
|
if (Array.isArray(value)) return value;
|
|
@@ -5766,26 +5792,29 @@ async function writeGoogleAnalysisSnapshot(params) {
|
|
|
5766
5792
|
const outlineBody = formatOutlineFileBody(fileName, normalizedWrapped, outlineExtra);
|
|
5767
5793
|
await fs7.writeFile(path11.join(absDir, outlineFileName), `${outlineBody}
|
|
5768
5794
|
`, "utf8");
|
|
5769
|
-
const existing = await readManifestIfExists(absDir, accountSlug || void 0);
|
|
5770
5795
|
const newArtifact = {
|
|
5771
5796
|
section: params.section,
|
|
5772
5797
|
file: relativeFile,
|
|
5773
5798
|
writtenAt,
|
|
5774
5799
|
...params.endpointHint !== void 0 ? { endpointHint: params.endpointHint } : {}
|
|
5775
5800
|
};
|
|
5776
|
-
const merged = mergeGoogleAnalysisManifest(existing, {
|
|
5777
|
-
accountId: params.accountId,
|
|
5778
|
-
dateRange: params.dateRange,
|
|
5779
|
-
cliVersion: params.cliVersion,
|
|
5780
|
-
newArtifact
|
|
5781
|
-
});
|
|
5782
5801
|
const manifestFile = googleAnalysisManifestFile(accountSlug || void 0);
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5802
|
+
const manifestPath = path11.join(absDir, manifestFile);
|
|
5803
|
+
await withAsyncLock(manifestPath, async () => {
|
|
5804
|
+
const existing = await readManifestIfExists(absDir, accountSlug || void 0);
|
|
5805
|
+
const merged = mergeGoogleAnalysisManifest(existing, {
|
|
5806
|
+
accountId: params.accountId,
|
|
5807
|
+
dateRange: params.dateRange,
|
|
5808
|
+
cliVersion: params.cliVersion,
|
|
5809
|
+
newArtifact
|
|
5810
|
+
});
|
|
5811
|
+
await fs7.writeFile(
|
|
5812
|
+
manifestPath,
|
|
5813
|
+
`${JSON.stringify(stringifyIdsDeep(merged), null, 2)}
|
|
5786
5814
|
`,
|
|
5787
|
-
|
|
5788
|
-
|
|
5815
|
+
"utf8"
|
|
5816
|
+
);
|
|
5817
|
+
});
|
|
5789
5818
|
return {
|
|
5790
5819
|
kind: "siluzan-tso-google-analysis-snapshot",
|
|
5791
5820
|
schemaVersion: SCHEMA_VERSION2,
|
|
@@ -5803,6 +5832,7 @@ var init_google_analysis = __esm({
|
|
|
5803
5832
|
"use strict";
|
|
5804
5833
|
init_cli_json();
|
|
5805
5834
|
init_wrap_snapshot_envelope();
|
|
5835
|
+
init_async_lock();
|
|
5806
5836
|
init_dir();
|
|
5807
5837
|
LEGACY_MANIFEST_FILE = "manifest.json";
|
|
5808
5838
|
CLI_PACKAGE = "siluzan-tso-cli";
|
|
@@ -102288,6 +102318,56 @@ async function loadSectionFile(snapshotDir, file) {
|
|
|
102288
102318
|
return null;
|
|
102289
102319
|
}
|
|
102290
102320
|
}
|
|
102321
|
+
function dateTagFromRange(dateRange) {
|
|
102322
|
+
if (!dateRange || dateRange.mode !== "range") return void 0;
|
|
102323
|
+
return `${dateRange.start.replace(/-/g, "")}-${dateRange.end.replace(/-/g, "")}`;
|
|
102324
|
+
}
|
|
102325
|
+
function dateTagFromMeta(meta) {
|
|
102326
|
+
const start = typeof meta?.startDate === "string" ? meta.startDate : "";
|
|
102327
|
+
const end = typeof meta?.endDate === "string" ? meta.endDate : "";
|
|
102328
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(start) || !/^\d{4}-\d{2}-\d{2}$/.test(end)) return void 0;
|
|
102329
|
+
return `${start.replace(/-/g, "")}-${end.replace(/-/g, "")}`;
|
|
102330
|
+
}
|
|
102331
|
+
function pickSectionSnapshotFile(files, section, accountId, preferredDateTag) {
|
|
102332
|
+
const escapedSection = section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
102333
|
+
const escapedId = accountId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
102334
|
+
const re = new RegExp(`^${escapedSection}-${escapedId}(?:_(\\d{8}-\\d{8}))?\\.json$`);
|
|
102335
|
+
const matches = files.filter((f) => re.test(f));
|
|
102336
|
+
if (matches.length === 0) return null;
|
|
102337
|
+
if (preferredDateTag) {
|
|
102338
|
+
const preferred = matches.find((f) => f.endsWith(`_${preferredDateTag}.json`));
|
|
102339
|
+
if (preferred) return preferred;
|
|
102340
|
+
}
|
|
102341
|
+
return [...matches].sort().at(-1) ?? null;
|
|
102342
|
+
}
|
|
102343
|
+
async function recoverMissingReportSections(sectionMap, absDir, accountId, preferredDateTag) {
|
|
102344
|
+
if (!accountId) return;
|
|
102345
|
+
let entries;
|
|
102346
|
+
try {
|
|
102347
|
+
entries = await fs20.readdir(absDir);
|
|
102348
|
+
} catch {
|
|
102349
|
+
return;
|
|
102350
|
+
}
|
|
102351
|
+
for (const section of REPORT_MERGE_SECTIONS) {
|
|
102352
|
+
if (sectionMap.has(section)) continue;
|
|
102353
|
+
const file = pickSectionSnapshotFile(entries, section, accountId, preferredDateTag);
|
|
102354
|
+
if (!file) continue;
|
|
102355
|
+
const data = await loadSectionFile(absDir, file);
|
|
102356
|
+
if (data) sectionMap.set(section, data);
|
|
102357
|
+
}
|
|
102358
|
+
}
|
|
102359
|
+
function periodMetricsFromRow(row) {
|
|
102360
|
+
if (!row) return null;
|
|
102361
|
+
return {
|
|
102362
|
+
cost: num2(row.spend),
|
|
102363
|
+
impressions: num2(row.impressions),
|
|
102364
|
+
clicks: num2(row.clicks),
|
|
102365
|
+
conversions: num2(row.conversions),
|
|
102366
|
+
ctr: num2(row.ctr),
|
|
102367
|
+
averageCpc: num2(row.averageCpc),
|
|
102368
|
+
costPerConversion: num2(row.costPerConversion)
|
|
102369
|
+
};
|
|
102370
|
+
}
|
|
102291
102371
|
function items(envelope) {
|
|
102292
102372
|
if (!envelope || !Array.isArray(envelope.items)) return [];
|
|
102293
102373
|
return envelope.items.filter((row) => asRecord11(row) !== null);
|
|
@@ -102342,16 +102422,18 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102342
102422
|
if (!manifest) {
|
|
102343
102423
|
throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
|
|
102344
102424
|
}
|
|
102425
|
+
const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
|
|
102426
|
+
const dateRange = manifest.googleAnalysis?.dateRange;
|
|
102427
|
+
const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord11(payload.meta) ?? void 0);
|
|
102345
102428
|
const sectionMap = /* @__PURE__ */ new Map();
|
|
102346
102429
|
for (const art of manifest.artifacts ?? []) {
|
|
102347
102430
|
const data = await loadSectionFile(absDir, art.file);
|
|
102348
102431
|
if (data) sectionMap.set(art.section, data);
|
|
102349
102432
|
}
|
|
102433
|
+
await recoverMissingReportSections(sectionMap, absDir, accountId, preferredDateTag);
|
|
102350
102434
|
const overviewRecord = record(sectionMap.get("overview"));
|
|
102351
102435
|
const currentPeriod = asRecord11(overviewRecord?.currentPeriod);
|
|
102352
102436
|
const previousPeriod = asRecord11(overviewRecord?.previousPeriod);
|
|
102353
|
-
const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
|
|
102354
|
-
const dateRange = manifest.googleAnalysis?.dateRange;
|
|
102355
102437
|
const meta = { ...payload.meta ?? {} };
|
|
102356
102438
|
if (!meta.accountId && accountId) meta.accountId = accountId;
|
|
102357
102439
|
if (!meta.currency) {
|
|
@@ -102363,16 +102445,9 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102363
102445
|
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
102364
102446
|
const campaignRows2 = items(sectionMap.get("campaigns"));
|
|
102365
102447
|
const campaignKpis = sumCampaignRowsToPeriodKpis(campaignRows2);
|
|
102448
|
+
const dimensionSummaryRecord = record(sectionMap.get("dimension-summary"));
|
|
102366
102449
|
const kpis = { ...payload.kpis ?? {} };
|
|
102367
|
-
const currentKpiSource = campaignKpis ?? (currentPeriod
|
|
102368
|
-
cost: num2(currentPeriod.spend),
|
|
102369
|
-
impressions: num2(currentPeriod.impressions),
|
|
102370
|
-
clicks: num2(currentPeriod.clicks),
|
|
102371
|
-
conversions: num2(currentPeriod.conversions),
|
|
102372
|
-
ctr: num2(currentPeriod.ctr),
|
|
102373
|
-
averageCpc: num2(currentPeriod.averageCpc),
|
|
102374
|
-
costPerConversion: num2(currentPeriod.costPerConversion)
|
|
102375
|
-
} : null);
|
|
102450
|
+
const currentKpiSource = campaignKpis ?? periodMetricsFromRow(currentPeriod) ?? periodMetricsFromRow(dimensionSummaryRecord);
|
|
102376
102451
|
if (currentKpiSource) {
|
|
102377
102452
|
if (currentKpiSource.cost != null) kpis.cost = currentKpiSource.cost;
|
|
102378
102453
|
if (currentKpiSource.impressions != null) kpis.impressions = currentKpiSource.impressions;
|
|
@@ -102411,22 +102486,21 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102411
102486
|
}
|
|
102412
102487
|
}
|
|
102413
102488
|
const tables = { ...payload.tables ?? {} };
|
|
102414
|
-
{
|
|
102415
|
-
|
|
102416
|
-
|
|
102417
|
-
|
|
102418
|
-
|
|
102419
|
-
|
|
102420
|
-
|
|
102421
|
-
|
|
102422
|
-
|
|
102423
|
-
|
|
102424
|
-
|
|
102425
|
-
|
|
102426
|
-
|
|
102427
|
-
|
|
102428
|
-
|
|
102429
|
-
}
|
|
102489
|
+
if (dimensionSummaryRecord) {
|
|
102490
|
+
tables.dimensionSummary = {
|
|
102491
|
+
cost: num2(dimensionSummaryRecord.spend),
|
|
102492
|
+
impressions: num2(dimensionSummaryRecord.impressions),
|
|
102493
|
+
clicks: num2(dimensionSummaryRecord.clicks),
|
|
102494
|
+
conversions: num2(dimensionSummaryRecord.conversions),
|
|
102495
|
+
ctr: num2(dimensionSummaryRecord.ctr),
|
|
102496
|
+
averageCpc: num2(dimensionSummaryRecord.averageCpc),
|
|
102497
|
+
costPerConversion: num2(dimensionSummaryRecord.costPerConversion),
|
|
102498
|
+
searchImpressionShare: num2(dimensionSummaryRecord.searchImpressionShare),
|
|
102499
|
+
searchBudgetLostImpressionShare: num2(
|
|
102500
|
+
dimensionSummaryRecord.searchBudgetLostImpressionShare
|
|
102501
|
+
),
|
|
102502
|
+
searchRankLostImpressionShare: num2(dimensionSummaryRecord.searchRankLostImpressionShare)
|
|
102503
|
+
};
|
|
102430
102504
|
}
|
|
102431
102505
|
if (campaignRows2.length > 0) {
|
|
102432
102506
|
tables.campaigns = campaignRows2.map((r) => ({
|
|
@@ -102464,10 +102538,20 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102464
102538
|
tables
|
|
102465
102539
|
};
|
|
102466
102540
|
}
|
|
102541
|
+
var REPORT_MERGE_SECTIONS;
|
|
102467
102542
|
var init_merge_snapshot = __esm({
|
|
102468
102543
|
"src/commands/google-analysis/merge-snapshot.ts"() {
|
|
102469
102544
|
"use strict";
|
|
102470
102545
|
init_google_analysis();
|
|
102546
|
+
REPORT_MERGE_SECTIONS = [
|
|
102547
|
+
"overview",
|
|
102548
|
+
"daily-metrics",
|
|
102549
|
+
"dimension-summary",
|
|
102550
|
+
"campaigns",
|
|
102551
|
+
"devices",
|
|
102552
|
+
"geographic",
|
|
102553
|
+
"keywords"
|
|
102554
|
+
];
|
|
102471
102555
|
}
|
|
102472
102556
|
});
|
|
102473
102557
|
|
|
@@ -102511,6 +102595,19 @@ function validateGooglePeriodReportContent(data) {
|
|
|
102511
102595
|
"\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u8F6C\u5316/CTR/CPA \u8D70\u52BF"
|
|
102512
102596
|
);
|
|
102513
102597
|
}
|
|
102598
|
+
const kpis = asRecord12(data.kpis);
|
|
102599
|
+
const hasCoreKpi = ["cost", "impressions", "clicks"].some(
|
|
102600
|
+
(key) => Number.isFinite(Number(kpis?.[key]))
|
|
102601
|
+
);
|
|
102602
|
+
if (!hasCoreKpi) {
|
|
102603
|
+
pushMissing(
|
|
102604
|
+
missing,
|
|
102605
|
+
"kpis-core-metrics",
|
|
102606
|
+
"\u6267\u884C\u6458\u8981 KPI",
|
|
102607
|
+
"kpis.cost / kpis.impressions / kpis.clicks",
|
|
102608
|
+
"\u81F3\u5C11\u4E00\u9879\u987B\u4E3A\u6709\u6548\u6570\u5B57\uFF1B\u8BF7\u52A0 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u5408\u5E76\uFF08\u52FF\u624B\u586B HTML\uFF09"
|
|
102609
|
+
);
|
|
102610
|
+
}
|
|
102514
102611
|
const sectionAnalysisCounts = {};
|
|
102515
102612
|
const sectionSuggestionCounts = {};
|
|
102516
102613
|
for (const key of SECTION_KEYS) {
|
|
@@ -102571,7 +102668,7 @@ function formatGooglePeriodReportErrors(result) {
|
|
|
102571
102668
|
...lines,
|
|
102572
102669
|
"",
|
|
102573
102670
|
"\u8BF7\u8865\u5168 narrative.sections.<dimension>.{analysis,suggestions} \u4E0E narrative.recommendations \u540E\u91CD\u65B0\u6267\u884C render\u3002",
|
|
102574
|
-
"
|
|
102671
|
+
"kpis/charts/tables \u987B\u7531 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u81EA\u52A8\u5408\u5E76\uFF08Agent \u53EA\u5199 narrative\uFF09\uFF1B\u5408\u5E76\u540E kpis \u4ECD\u4E3A\u7A7A\u65F6\u68C0\u67E5\u5FEB\u7167\u76EE\u5F55 manifest \u662F\u5426\u542B overview/campaigns/dimension-summary\u3002\u7981\u6B62\u624B\u5199 HTML\u3002"
|
|
102575
102672
|
].join("\n");
|
|
102576
102673
|
}
|
|
102577
102674
|
var SECTION_KEYS, SECTION_LABELS;
|
|
@@ -108342,6 +108439,7 @@ init_cli_table();
|
|
|
108342
108439
|
init_cli_json_snapshot();
|
|
108343
108440
|
|
|
108344
108441
|
// src/utils/snapshot/report-analysis.ts
|
|
108442
|
+
init_async_lock();
|
|
108345
108443
|
init_google_analysis();
|
|
108346
108444
|
init_cli_json();
|
|
108347
108445
|
import * as fs8 from "fs/promises";
|
|
@@ -108415,25 +108513,24 @@ async function writeReportAnalysisSnapshot(params) {
|
|
|
108415
108513
|
`,
|
|
108416
108514
|
"utf8"
|
|
108417
108515
|
);
|
|
108418
|
-
const existing = await readReportManifestIfExists(absDir, accountSlug || void 0);
|
|
108419
108516
|
const newArtifact = {
|
|
108420
108517
|
section: params.section,
|
|
108421
108518
|
file: fileName,
|
|
108422
108519
|
writtenAt
|
|
108423
108520
|
};
|
|
108424
|
-
const merged = mergeReportAnalysisManifest(existing, {
|
|
108425
|
-
accountId: params.accountId,
|
|
108426
|
-
dateRange: params.dateRange,
|
|
108427
|
-
cliVersion: params.cliVersion,
|
|
108428
|
-
newArtifact
|
|
108429
|
-
});
|
|
108430
108521
|
const manifestFile = reportManifestFile(accountSlug || void 0);
|
|
108431
|
-
|
|
108432
|
-
|
|
108433
|
-
|
|
108434
|
-
|
|
108435
|
-
|
|
108436
|
-
|
|
108522
|
+
const manifestPath = path12.join(absDir, manifestFile);
|
|
108523
|
+
await withAsyncLock(manifestPath, async () => {
|
|
108524
|
+
const existing = await readReportManifestIfExists(absDir, accountSlug || void 0);
|
|
108525
|
+
const merged = mergeReportAnalysisManifest(existing, {
|
|
108526
|
+
accountId: params.accountId,
|
|
108527
|
+
dateRange: params.dateRange,
|
|
108528
|
+
cliVersion: params.cliVersion,
|
|
108529
|
+
newArtifact
|
|
108530
|
+
});
|
|
108531
|
+
await fs8.writeFile(manifestPath, `${JSON.stringify(merged, null, 2)}
|
|
108532
|
+
`, "utf8");
|
|
108533
|
+
});
|
|
108437
108534
|
return {
|
|
108438
108535
|
kind: "siluzan-tso-report-analysis-snapshot",
|
|
108439
108536
|
schemaVersion: SCHEMA_VERSION3,
|
package/dist/skill/_meta.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "siluzan-tso/google-period-report.schema.json",
|
|
4
4
|
"title": "GooglePeriodReport",
|
|
5
|
-
"description": "Google Ads 周期分析报告 JSON(对齐 google-period-report.md 8 默认维度;供 google-analysis render 注入 HTML)。Agent 只需撰写 narrative
|
|
5
|
+
"description": "Google Ads 周期分析报告 JSON(对齐 google-period-report.md 8 默认维度;供 google-analysis render 注入 HTML)。Agent 只需撰写 narrative;kpis/charts/tables 由 --snapshot-dir 从 google-analysis 快照合并。render 校验要求合并后 kpis.cost/impressions/clicks 至少一项为有效数字,否则拒绝出 HTML(避免执行摘要卡片全「—」)。",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["meta", "narrative"],
|
|
8
8
|
"properties": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"kpis": {
|
|
23
23
|
"type": "object",
|
|
24
|
-
"description": "账户级 KPI(执行摘要 KPI
|
|
24
|
+
"description": "账户级 KPI(执行摘要 KPI 网格);Agent 可省略,但 render 时须经 --snapshot-dir 合并出 cost/impressions/clicks",
|
|
25
25
|
"properties": {
|
|
26
26
|
"cost": { "type": "number" },
|
|
27
27
|
"impressions": { "type": "number" },
|
|
@@ -167,7 +167,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
|
|
|
167
167
|
| 状态 | 含义 | 下一步操作 |
|
|
168
168
|
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
169
169
|
| `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
|
|
170
|
-
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
|
|
170
|
+
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
|
|
171
171
|
| `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
|
|
172
172
|
|
|
173
173
|
---
|
|
@@ -486,7 +486,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
486
486
|
|
|
487
487
|
| 功能 | 媒体 | 网页路径 |
|
|
488
488
|
| --------------------------------------- | ------ | ------------------------------------------------- |
|
|
489
|
-
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
489
|
+
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
490
490
|
|
|
491
491
|
**Agent 建议话术**:
|
|
492
492
|
|
|
@@ -495,5 +495,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
495
495
|
siluzan-tso config show # 查看 webUrl 字段
|
|
496
496
|
|
|
497
497
|
# 账户激活(Google)→ 引导至账户管理页
|
|
498
|
-
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
498
|
+
# https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
499
499
|
```
|
|
@@ -127,7 +127,7 @@ siluzan-tso config show
|
|
|
127
127
|
|
|
128
128
|
### 充值页链接(按媒体 × 类型)
|
|
129
129
|
|
|
130
|
-
链接模式:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
|
|
130
|
+
链接模式:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
|
|
131
131
|
|
|
132
132
|
| 充值类型 | `<page>` | 支持媒体(`mediaType` 参数) |
|
|
133
133
|
| ------------------------- | --------------------- | ------------------------------------------- |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 各媒体开户
|
|
2
2
|
|
|
3
|
-
> 网页链接:`https://www.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
|
|
3
|
+
> 网页链接:`https://www-ci.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
|
|
4
4
|
> 多命令串联见 `references/core/workflows.md` § 流程一。
|
|
5
5
|
|
|
6
6
|
|
|
@@ -65,7 +65,7 @@ siluzan-tso open-account google-wizard
|
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
67
|
siluzan-tso account-history -m Google
|
|
68
|
-
# 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
68
|
+
# 审核通过后:config show → https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
---
|
|
@@ -190,9 +190,9 @@ siluzan-tso report push receive-emails -m Google [--json-out ./snap]
|
|
|
190
190
|
|
|
191
191
|
| 媒体 | 报告类型 | URL 模板 |
|
|
192
192
|
| ------ | ---------------- | ----------------------------------------------------------- |
|
|
193
|
-
| Google | 日报(Daily) | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
194
|
-
| Google | 小时报(Hourly) | `https://www.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
|
|
195
|
-
| TikTok | 日报 | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
193
|
+
| Google | 日报(Daily) | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
194
|
+
| Google | 小时报(Hourly) | `https://www-ci.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
|
|
195
|
+
| TikTok | 日报 | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
|
|
196
196
|
|
|
197
197
|
`entityId` 来自 `siluzan-tso report list --json-out ./snap` 中每条记录的 `entityId` 字段。
|
|
198
198
|
|
|
@@ -205,8 +205,8 @@ siluzan-tso report list -m Google --json-out ./snap
|
|
|
205
205
|
|
|
206
206
|
# 第二步:查看 webUrl
|
|
207
207
|
siluzan-tso config show
|
|
208
|
-
# webUrl: https://www.siluzan.com
|
|
208
|
+
# webUrl: https://www-ci.siluzan.com
|
|
209
209
|
|
|
210
210
|
# 第三步:拼接链接(Google 日报)
|
|
211
|
-
# https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
211
|
+
# https://www-ci.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
212
212
|
```
|
|
@@ -142,6 +142,17 @@
|
|
|
142
142
|
- **破坏性操作必须确认 + `--commit`**:账户解绑/关闭/取消分享、BC/MCC 解绑、删除预警/报告/广告/关键词、发票申请、广告发布等。
|
|
143
143
|
- **CLI 硬门控**:`account delink` / `unshare` / `reauth` / `mcc-unbind` / `bc-unbind` **缺少 `--i-confirm` 会直接失败**(不会发网关)。`--commit` 只是审计说明,**不能替代**用户确认。
|
|
144
144
|
- **Agent**:先说明风险与将执行的命令 → **等待用户明确同意** → 才附加 `--i-confirm --commit "…"` 执行。用户说「别问我 / 直接做」也**不得**跳过确认;**禁止**未获同意就自行加 `--i-confirm`。
|
|
145
|
+
- **写操作结束后必须向用户交付成败报告**(修改 / 创建 / 删除 / 绑定 / 分享 / 开户提交 / 预警变更等凡改变远端状态的命令):
|
|
146
|
+
- 用**业务语言**说明:结论(全成功 / 部分失败 / 全失败)→ **成功了哪些**(对象名或 ID)→ **失败了哪些**(对象 + 原因,来自当次 CLI stderr / `reason` / `errors` / 读命令复核)→ 如需用户动作再给 1 句下一步。
|
|
147
|
+
- 批量或可部分失败时(多账户 MCC/BC、关户、批量关键词等):**逐项**列清,禁止只说「已处理」。
|
|
148
|
+
- 单资源写:至少交代「改了什么 + 当前状态」(可用成对读命令复核后写进报告)。
|
|
149
|
+
- **禁止**只贴一行 CLI `✅`/`❌` 或整段 stdout 当交付;**禁止**写命令成功后静默结束。
|
|
150
|
+
- **广告创建(W3)另有加强**:见下条与 `workflows.md` W3——创建完成后必须输出**每个系列**的详情,不能只报「任务已提交 / 创建完成」。
|
|
151
|
+
- **Google 广告创建完成后必出系列详情报告**(用户确认计划并执行 `campaign-create` / `pmax-create` 之后):
|
|
152
|
+
- 流水线跑完:`batch get` 至终态 →(搜索)`batch diff` + 必要自动补建 → 再读 `ad campaigns`(及组/词/扩展等按需)核对。
|
|
153
|
+
- 对用户按**每个广告系列**交代:账户、系列名与 `campaignId`、batch 状态、广告组/关键词/RSA/否词/投放国家/附加信息的**计划 vs 实况**(可用 `batch diff` 的 `counts` + `missing` + 读命令结果组织);已自动补建的条数;仍失败项与原因。
|
|
154
|
+
- 多系列:每个系列各跑完核对后,在同一回复里**按系列分节**汇报。
|
|
155
|
+
- **禁止**只说「已创建成功 / 未发现缺失」而不列成功明细;代改过用户方案时另加修改表(见 `google-ads-plan-source-fidelity.md`)。
|
|
145
156
|
- **不确定时读文档**:先读对应 references 或用 `-h`,不要猜参数。
|
|
146
157
|
- **跨账号 / 企业管家手机号**:用户消息中出现**中国大陆 11 位手机号**(常见语境:「企业管家」「管家账户」「账号 xxx」)且意图是查**该手机号名下**的账户数据时,**必须先**执行 `siluzan-tso account me --check-phone <手机号> --json-out ./snap-me`。**禁止**在未校验通过前用当前凭据拉他户数据。
|
|
147
158
|
- `matched: true`(或 CLI exit 0)→ 按原工作流继续(如 P3 `accounts-digest` 查 TOP 消耗)。
|
|
@@ -153,7 +164,7 @@
|
|
|
153
164
|
- 当前凭据未返回手机号且用户指定了手机号 → 视同未校验通过,引导重新用手机号登录。
|
|
154
165
|
- **Google 新建搜索系列**:流程在 `references/google-ads/google-ads-campaign-plan.md`;填 JSON 前**必须先 Read** `assets/campaign-create-template.json`,再 Read `assets/campaign-create-template.md`。**禁止**只读 `.md` 手写 JSON。
|
|
155
166
|
- **「根据官网生成 Google 搜索广告 / 表格格式」**:仍属新建搜索系列 → **W3 + 本文件上条**;用户要的「表格」是对已落盘 JSON 的投影(Agent 写代码生成),**不是**可跳过 JSON 的独立交付物。**仅出方案**时可先 JSON + 审查稿(跳过 validate);**创建前**必须 `campaign-validate` 且用户已审完整审查稿。**禁止**与 P8 网站诊断、P9 市场分析、W5 仅拓词混用;**禁止**因缺账户 ID 拒出方案。
|
|
156
|
-
- **Excel/表格投放方案 → 创建广告**:必读 `references/google-ads/rules/google-ads-plan-source-fidelity.md`。Agent **写代码**直接转成 campaign-create JSON;地域用 **`ad geo resolve`**;**禁止**对话手填完整 JSON、**禁止**编造 geo id;有方案匹配类型时勿压成一律 BROAD。**方案不合规时必须询问**:「您自己改还是我帮您改?」——**禁止**未问就静默改用户方案内容后 create
|
|
167
|
+
- **Excel/表格投放方案 → 创建广告**:必读 `references/google-ads/rules/google-ads-plan-source-fidelity.md`。Agent **写代码**直接转成 campaign-create JSON;地域用 **`ad geo resolve`**;**禁止**对话手填完整 JSON、**禁止**编造 geo id;有方案匹配类型时勿压成一律 BROAD。**方案不合规时必须询问**:「您自己改还是我帮您改?」——**禁止**未问就静默改用户方案内容后 create。用户选「我帮您改」时:代改同步落盘变更账本。**创建完成后必出系列详情报告**;代改过则**另附**修改表(从 xxx→xxx + 原因)。
|
|
157
168
|
- **「行业分析 / 行业分析报告 / 生成 XX 行业报告」**(例:「帮我生成一份电商行业的行业分析报告」)→ **P9 战略市场分析**。**必须**先 `siluzan-tso market-analysis collect … --json-out`,再 WebSearch 补数据、写 `market-report.json`,最后 `market-analysis render` 出 HTML。**禁止**不调用 CLI、仅在对话里用 WebSearch 写 Markdown 充当终稿。**不是** `google-analysis`、**不是** P8 网站诊断。
|
|
158
169
|
- **开户首次响应**:对话内首次进入开户话题时,**必须先**按 `references/accounts/open-account-by-media.md` §「首次响应硬规范」输出**完整必填业务清单**(未指明媒体则列全平台六媒体业务项),再收集资料;**禁止**未列清单就执行 `open-account` 或零散追问。清单**只写业务项与说明**;**禁止**向用户展示 `--flag` / CLI 选项名 / 命令行参数列(参数仅 Agent 内部组命令用)。
|
|
159
170
|
- **Google 开户**:`open-account google-wizard` 仅限真实 TTY;Agent/自动化用非交互 `open-account google ...`,审核进度用 `account-history`;对用户话术仍只用业务语言。
|
|
@@ -322,8 +333,10 @@
|
|
|
322
333
|
| 模糊意图 | 选最可能工作流先执行;结论后附「您是不是还想…」 |
|
|
323
334
|
| campaign-create 后 Sitelink/国家 batch 漏建 | **自动** `batch get` → `batch diff` → `ad geo add` / `ad extension *`;**勿**反问是否补建 |
|
|
324
335
|
| 用户方案(Excel 等)不合规 | 列出问题 → 二选一「您自己改还是我帮您改?」→ 停等;禁止未问静默改后 create |
|
|
325
|
-
|
|
|
326
|
-
|
|
|
336
|
+
| **任意写操作刚结束** | **必出成败报告**(§四):成功对象 + 失败对象/原因;禁止只贴 emoji 行或静默结束 |
|
|
337
|
+
| **广告创建流水线刚结束**(含未代改方案) | **必出每个系列的创建详情**(§四):计划 vs 实况计数、补建条数、仍失败项;代改时另加修改表(`google-ads-plan-source-fidelity.md`) |
|
|
338
|
+
| 用户选「我帮您改」且已创建 | 在系列详情之上 **另出修改表**:从 xxx→xxx + 原因 |
|
|
339
|
+
| 写入/删除/充值/开户提交 | **必须先确认**(§四);业务语言说明将要做什么;执行后再按上表汇报结果 |
|
|
327
340
|
| 对象不清且无法推断 | **只问一次**,给 2~3 个选项 |
|
|
328
341
|
|
|
329
342
|
### 14.4 自然语言 ↔ 内部路由(对用户隐藏编号)
|
|
@@ -347,5 +360,6 @@
|
|
|
347
360
|
- 禁止冷冰冰系统提示语气而不给下一步。
|
|
348
361
|
- 禁止用户未要求时输出冗长「执行计划」清单;尽快进入执行。
|
|
349
362
|
- 交付 HTML/Excel 时附 **3~5 行摘要**(区间、币种、核心 KPI、最大问题、建议动作),不要只丢文件路径。
|
|
363
|
+
- 写操作 / 广告创建结束后:**禁止**用「搞定了 / 已提交」代替成败明细;须按 §四交付成功项与失败项(创建另须按系列列详情)。
|
|
350
364
|
|
|
351
365
|
数值纪律不变:金额、状态、ID 只来自当次 CLI/`--json-out`;本节只约束表述方式。
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
## 安装 CLI
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g siluzan-tso-cli
|
|
13
|
+
npm install -g siluzan-tso-cli@beta
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -63,7 +63,7 @@ siluzan-tso config set --api-key <Key> # 或 config 直接写入
|
|
|
63
63
|
siluzan-tso config set --token <Token> # 备用:设置 JWT Token
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
API Key 获取入口:`https://www.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
|
|
66
|
+
API Key 获取入口:`https://www-ci.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
69
|
# 第 1 步:让用户报出手机号后,立刻发码(命令立即返回,不会等待输入)
|
|
@@ -126,9 +126,9 @@ siluzan-tso config show
|
|
|
126
126
|
|
|
127
127
|
```
|
|
128
128
|
构建环境 : production
|
|
129
|
-
apiBaseUrl : https://tso-api.siluzan.com
|
|
130
|
-
googleApiUrl : https://googleapi.mysiluzan.com
|
|
131
|
-
webUrl : https://www.siluzan.com
|
|
129
|
+
apiBaseUrl : https://tso-api-ci.siluzan.com
|
|
130
|
+
googleApiUrl : https://googleapi-ci.mysiluzan.com
|
|
131
|
+
webUrl : https://www-ci.siluzan.com
|
|
132
132
|
apiKey : abcd****1234
|
|
133
133
|
```
|
|
134
134
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 工作流目录 · 操作 / 管理类(W1–W12)
|
|
2
2
|
|
|
3
3
|
> **范围**:调接口 / 写操作类业务(账户读取、开户、广告 CRUD、智投、拓词、优化、报告推送、财务、权限、预警、线索、巡检)。分析/报告类(拉数 → 撰稿 → 交付)见 `references/core/playbooks.md`(P1–P9)。
|
|
4
|
-
> **通用纪律见 `references/core/agent-conventions.md`**(写操作确认 + `--commit
|
|
4
|
+
> **通用纪律见 `references/core/agent-conventions.md`**(写操作确认 + `--commit`、写后成败报告、ID 口径);各卡片只写线性步骤。卡片字段:`触发 / 必读 / 步骤 / 产物`。完整参数表见「必读」指向的命令文档。
|
|
5
5
|
|
|
6
6
|
| 编号 | 业务 | 必读 |
|
|
7
7
|
| ---- | ------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
@@ -76,10 +76,11 @@
|
|
|
76
76
|
4. 创建阶段门禁:`ad pmax-validate --config-file ./pmax.json --json-out ./snap-pmax`。
|
|
77
77
|
5. **写代码**按 `google-ads-pmax-launch-plan-template.md` 从 JSON 投影完整审查稿 → 用户审查确认 → `ad pmax-create --commit "…"`。
|
|
78
78
|
6. 复核:`ad campaigns` / `ad pmax-get`;缺表单时 `ad extension lead-form` 补挂。
|
|
79
|
+
7. **向用户交付创建详情**(系列名/`campaignId`、资产组/扩展是否齐全、失败原因);禁止只说「已创建」。
|
|
79
80
|
- **步骤(Search · 方案文件 → 创建)**:
|
|
80
81
|
1. Read `campaign-create-template.json`;Agent 写转换脚本读 Excel → 写出 `campaign.json`(匹配类型按方案分块)。
|
|
81
82
|
2. `ad geo resolve -a <id> --from-file ./locations.json --json-out ./snap-geo`,把 id 写回 JSON。
|
|
82
|
-
3. `ad campaign-validate`;**有不合规 → 询问「您自己改还是我帮您改?」**(见 `google-ads-plan-source-fidelity.md`)→ **写代码投影完整审查稿** → 用户确认 → `campaign-create` → `batch get` / `batch diff` /
|
|
83
|
+
3. `ad campaign-validate`;**有不合规 → 询问「您自己改还是我帮您改?」**(见 `google-ads-plan-source-fidelity.md`)→ **写代码投影完整审查稿** → 用户确认 → `campaign-create` → `batch get` / `batch diff` / 自动补扩展 → **必出系列创建详情报告**;若 Agent 代改过 → 详情中**另附**修改表(创建清单 + 从 xxx→xxx + 原因)。
|
|
83
84
|
- **步骤(Search 一体化创建,无现成方案文件)**:
|
|
84
85
|
1. 地域:多国 `ad geo resolve`;单国 `ad geo search -a <id> -q "United States"`(仍禁止编造)。
|
|
85
86
|
2. 门禁:`ad campaign-validate --config-file ./campaign.json`(必跑)。
|
|
@@ -88,8 +89,9 @@
|
|
|
88
89
|
5. 轮询:`ad batch get --id <taskId> --config-file … --json-out …` 直至非 Creating;**读落盘 `agentWorkflow.nextCommand`**(`--json-out` 时人读提示不会出现)。
|
|
89
90
|
6. **必做** `ad batch diff`(含投放国家);`ok===false` / exit 2 时按 `missing[].remediateCommand` **自动** `ad geo add` / `ad extension *` 补建,勿反问用户(见 `google-ads-campaign-plan.md` § batch diff 后自动补建)。
|
|
90
91
|
7. 复核:`ad campaigns` / `ad extension list` 确认系列与扩展齐全。
|
|
91
|
-
|
|
92
|
-
-
|
|
92
|
+
8. **向用户交付创建详情报告**(每个系列一节):系列名/`campaignId`、batch 状态、组/词/RSA/否词/国家/附加信息的计划 vs 实况(依据 `batch diff` 的 `counts`/`missing` + 读命令)、已补建条数、仍失败项与原因;**禁止**只说「创建完成」。代改过方案时另附修改表(`google-ads-plan-source-fidelity.md`)。见 `agent-conventions.md` §四。
|
|
93
|
+
- **精细管理与日常运营**:`ad adgroup-create` / `ad keyword-create` / `ad keyword-negative-create` / `ad ad-create`(拓词辅助见 **W5**);调整用 `ad adgroup-status` / `ad campaign-status` / `ad ad-delete` / `ad keyword-negative-delete`。完整参数见 `references/google-ads/google-ads-write.md`;列表复核见 `google-ads-read.md`。写后按 `agent-conventions.md` §四向用户汇报成败(改了什么、是否生效)。
|
|
94
|
+
- **产物**:系列(`ad campaigns` 可见)+ batch(`ad batch get` / `batch diff` 补齐扩展与地域)+ **面向用户的系列创建详情报告**;关键词匹配格式 `running shoes`=广泛 / `"..."`=词组 / `[...]`=精确;结构性写操作须用户确认;写后用成对读命令复核并汇报成败。
|
|
93
95
|
|
|
94
96
|
---
|
|
95
97
|
|
|
@@ -102,8 +104,8 @@
|
|
|
102
104
|
2. 详情:`ad batch get --id <recordId>`。
|
|
103
105
|
3. (可选)改字段(仅 `draftStatus=Draft` 可改):`ad batch update --id <recordId> --budget … --campaign-name … --url …`。
|
|
104
106
|
4. 发布:`ad batch publish --id <recordId>`。
|
|
105
|
-
5. 跟踪:`ad batch list` 看 `Creating → Successfully / Failed`;成功后 `ad campaigns -a <id>`
|
|
106
|
-
- **产物**:草稿的**从零创建**须在网页向导完成,CLI 不支持;要纯 CLI 创建走 **W3
|
|
107
|
+
5. 跟踪:`ad batch list` 看 `Creating → Successfully / Failed`;成功后 `ad campaigns -a <id>` 验证;终态后按 **W3** / `agent-conventions.md` §四向用户交付系列创建详情(成功/失败项)。
|
|
108
|
+
- **产物**:草稿的**从零创建**须在网页向导完成,CLI 不支持;要纯 CLI 创建走 **W3**。发布前与用户确认;发布后须汇报成败明细。
|
|
107
109
|
|
|
108
110
|
---
|
|
109
111
|
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
| 5 | 得到与模板同构的 `campaign-create` JSON(仅出方案时 `account`=`[PENDING_ACCOUNT]`) | **`assets/campaign-create-template.json`** |
|
|
62
62
|
| 6 | **创建阶段**:`ad campaign-validate --config-file <json>`;**仅出方案 → 跳过**,交付时说明「有账户后再 validate」 | 下文「校验」 |
|
|
63
63
|
| 6b | **方案来自用户且不合规**(创建前):列出问题 → **询问**「您自己改还是我帮您改?」→ 按选择处理后再 validate(**禁止**未问就静默改方案) | **`rules/google-ads-plan-source-fidelity.md`** § 用户方案不合规 |
|
|
64
|
-
| 6c | 用户选「我帮您改」:改 JSON 时**同步落盘变更账本**(from → to + reason) | 同上 §
|
|
64
|
+
| 6c | 用户选「我帮您改」:改 JSON 时**同步落盘变更账本**(from → to + reason) | 同上 § 创建完成报告 |
|
|
65
65
|
| 7 | **审查稿(必做)**:Agent **写代码**读 JSON,按 `google-ads-launch-plan-template.md` 投影完整文件(默认 MD;用户要 Excel 等则改格式);须含全部关键词与 RSA 正文;**禁止**概览表代替;**勿**贴整份 JSON 当主交付 | `google-ads-launch-plan-template.md` |
|
|
66
66
|
| 8 | 用户确认后 **`ad campaign-create`** | `references/google-ads/google-ads-write.md` |
|
|
67
67
|
| 9 | 每隔5s 获取创建结果 | `ad batch get --id <taskId> --config-file ./campaign.json` |
|
|
68
68
|
| 10 | 成功或部分成功后 **`ad batch diff`** 对照 JSON 与账户实况 | |
|
|
69
69
|
| 11 | **自动补建缺失项**(见下文「batch diff 后自动补建」):附加信息(Sitelink/Callout 等)**直接**执行 `ad extension *`;组/词/RSA 用对应 create 命令。**勿**仅汇报失败并反问用户是否补建 | `references/google-ads/google-ads-batch.md` § batch diff 后自动补建 |
|
|
70
|
-
| 12 |
|
|
70
|
+
| 12 | **向用户交付系列创建详情**(每个系列:计划 vs 实况、补建、失败项);代改过方案时**另附**修改表(从 xxx → xxx + 原因) | `agent-conventions.md` §四;**`rules/google-ads-plan-source-fidelity.md`** § 创建完成报告 |
|
|
71
71
|
|
|
72
72
|
多系列:每系列一个 JSON;可选 `campaign-manifest.json`(`role: brand|competitor|generic`)仅作文件组织参考。
|
|
73
73
|
|
|
@@ -147,6 +147,7 @@ validate 与 create **共用** `runCampaignCreateValidation`:词面规范化 +
|
|
|
147
147
|
| 5 | 有缺失时 CLI **exit 2**;补建后再 `ad batch diff`,直到 `ok===true`(含 `counts.liveLocations === plannedLocations`) |
|
|
148
148
|
| 6 | 汇总告诉用户「已自动补上 N 个投放国家 / M 条 Sitelink」 |
|
|
149
149
|
| 7 | 仅当补建命令也失败时,才向用户说明原因并给改写方案 |
|
|
150
|
+
| 8 | **向用户交付系列创建详情报告**(必做,即使 `ok===true`):按系列列出名/`campaignId`、batch 状态、各组层计划 vs 实况(`counts` + 无 `missing` 的项视为已生效)、补建条数、仍失败项;**禁止**只说「创建完成 / 未发现缺失」。多系列按系列分节。细则见 `agent-conventions.md` §四;代改方案另附修改表见 `google-ads-plan-source-fidelity.md` |
|
|
150
151
|
|
|
151
152
|
**Agent 易漏点**:`--json-out` 时人读「下一步」不会打印——**必须以落盘 `agentWorkflow` 为准**;`campaign-create` 落盘同样带 `agentWorkflow.nextCommand`(首轮 `batch get`)。
|
|
152
153
|
|
|
@@ -177,6 +177,7 @@ BatchJob 常漏 **附加信息**(Sitelink)与 **投放地域**;系列/组/
|
|
|
177
177
|
3. 扩展字段映射:`Properties.Text` + `DestinationUrl` → `ad extension sitelink`;`CALLOUT` → `callout`;`CALL` → `call`;`STRUCTURED_SNIPPET` → `snippet`。
|
|
178
178
|
4. 有缺失时 CLI **exit 2**;补建后再跑一次 `ad batch diff`,直到 `ok===true`。
|
|
179
179
|
5. 向用户汇报已补挂条数(地域 + Sitelink 等)。
|
|
180
|
+
6. **无论全成功或部分失败**,收尾必须向用户交付**每个系列的创建详情**(业务语言):系列名/`campaignId`、batch 状态、组/词/RSA/否词/国家/附加信息计划 vs 实况(用 `counts` + `missing` + 读命令)、补建与仍失败项。**禁止**只说「已创建成功」或只复述「未发现缺失」。见 `agent-conventions.md` §四。
|
|
180
181
|
|
|
181
182
|
完整流水线见 `references/google-ads/google-ads-campaign-plan.md` § batch diff 后自动补建。
|
|
182
183
|
|
|
@@ -62,10 +62,11 @@
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## 创建完成报告(必出)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
**何时必出系列创建详情**:凡最终完成了 `campaign-create`(含 `batch get` / `batch diff` / 必要补建)之后——**无论是否代改方案**。结构见下节「创建了哪些」;多系列按系列分节。总纪律见 `agent-conventions.md` §四。
|
|
68
|
+
|
|
69
|
+
**何时另出完整修改表**:仅当用户选择「我帮您改」且 Agent 改过业务内容。用户全程自己改方案、Agent 未改业务内容 → **不必**出修改表,但仍须出系列创建详情。
|
|
69
70
|
|
|
70
71
|
### 变更账本(代改过程中维护)
|
|
71
72
|
|
|
@@ -82,20 +83,20 @@
|
|
|
82
83
|
|
|
83
84
|
### 面向用户的报告结构(业务语言)
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
创建与核对结束后,用一份短报告回复用户:
|
|
86
87
|
|
|
87
|
-
1.
|
|
88
|
-
账户 ID/名称、系列名与 `campaignId`、广告组数、关键词数(可附 Exact/Phrase/Broad)、否词数、投放国家数、RSA
|
|
88
|
+
1. **创建了哪些(每个系列必有)**
|
|
89
|
+
账户 ID/名称、系列名与 `campaignId`、广告组数、关键词数(可附 Exact/Phrase/Broad)、否词数、投放国家数、RSA/附加信息条数(计划 vs 实况,依据 `batch diff` 的 `counts` / `missing`);batch 状态;若有自动补建(Sitelink/地域等)写明补了几条;仍失败项与原因。
|
|
89
90
|
|
|
90
|
-
2.
|
|
91
|
+
2. **修改了哪些(相对您的原方案)**——**仅代改时必出**
|
|
91
92
|
表格逐条:**位置 | 从(原值) | 改成(新值) | 原因**。
|
|
92
93
|
- `from` / `to` 写清原文,勿只写「已优化」。
|
|
93
|
-
-
|
|
94
|
+
- 无业务修改则写「相对您的原方案无业务内容修改」(仅 geo id 解析等不写进此表)。
|
|
94
95
|
|
|
95
96
|
3. **未改动的说明(可选一句)**
|
|
96
97
|
如:匹配类型/国家列表按您的方案保留。
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
**禁止**:只说「已创建成功 / 未发现缺失」而不列系列详情;代改时**禁止**省略修改表;**禁止**把创建结果与修改混成一团让用户自己猜改了啥。
|
|
99
100
|
|
|
100
101
|
可选脚手架(非必须):`assets/plan-extract.example.json` + `assets/scripts/assemble-campaign-from-plan.mjs`——若 Agent 更习惯先抽中间件再组装,可以用;**不强制**。
|
|
101
102
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
siluzan-tso config show # 取 webUrl
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
首页地址:`https://www.siluzan.com/v3/foreign_trade/tso/home`
|
|
9
|
+
首页地址:`https://www-ci.siluzan.com/v3/foreign_trade/tso/home`
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -25,7 +25,7 @@ siluzan-tso config show # 取 webUrl
|
|
|
25
25
|
|
|
26
26
|
## 推荐话术
|
|
27
27
|
|
|
28
|
-
1. **「和首页一样的总览」** → 打开 `https://www.siluzan.com/v3/foreign_trade/tso/home`。
|
|
28
|
+
1. **「和首页一样的总览」** → 打开 `https://www-ci.siluzan.com/v3/foreign_trade/tso/home`。
|
|
29
29
|
2. **「某个 Google 账户昨天花了多少」** → `list-accounts -m Google` + `stats -m Google -a <id>`。
|
|
30
30
|
3. **「有待充值账户」** → 说明聚合数据在首页;CLI 可 `list-accounts` + `balance` 逐户排查,或引导充值页。
|
|
31
31
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| ---------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
16
|
| **1. 拉数** | Agent 调 CLI | `google-analysis -a <id> --start <s> --end <e> --json-out ./snap-google --sections <见下方默认维度对应 CLI>` |
|
|
17
17
|
| **2. 分析** | Agent | 用 **node/python 脚本**读落盘 JSON(勿用 Read 打开业务 `*.json`),完成筛选、聚合、排序与洞察 |
|
|
18
|
-
| **3. 写 JSON** | Agent | 按 `assets/google-period-report.schema.json` 撰写 `google-period-report.json
|
|
18
|
+
| **3. 写 JSON** | Agent | 按 `assets/google-period-report.schema.json` 撰写 `google-period-report.json`:只写 `meta` + `narrative`(8 维度叙事);`kpis`/`charts`/`tables` 留给步骤 4 的 `--snapshot-dir` 合并(合并后缺 KPI 会拒绝出 HTML) |
|
|
19
19
|
| **4. 渲染 HTML** | CLI | `google-analysis render` — **校验 narrative 8 维度必含字段**,缺项报错不生成 HTML;**禁止** Agent 手写/拼接 HTML |
|
|
20
20
|
|
|
21
21
|
```bash
|
|
@@ -33,7 +33,7 @@ siluzan-tso google-analysis render \
|
|
|
33
33
|
`google-period-report.json` 顶层结构:
|
|
34
34
|
|
|
35
35
|
- `meta`:`accountId`(必填)/ `accountName` / `currency` / `startDate` / `endDate`;可省略由 `--snapshot-dir` 从 `overview` + manifest 自动合并。
|
|
36
|
-
- `kpis`:账户级 KPI(消耗/展示/点击/转化/CTR/CPC/CPA,含可选 `previousPeriod`
|
|
36
|
+
- `kpis`:账户级 KPI(消耗/展示/点击/转化/CTR/CPC/CPA,含可选 `previousPeriod` 环比);Agent 可省略,但 **render 合并后** `cost`/`impressions`/`clicks` 至少一项须为有效数字,否则拒绝出 HTML(避免执行摘要卡片全「—」)。本期 KPI 由 CLI 优先对 `campaigns` 全系列累加并重算比率;无 campaigns 时回退 `overview.currentPeriod`,再回退 `dimension-summary`。环比仍来自 `overview.previousPeriod`。
|
|
37
37
|
- `charts.dailyTrend`:每日趋势(`dates`/`cost`/`conversions`/`cpa`);可省略由 `daily-metrics` 自动合并。
|
|
38
38
|
- `tables.{dimensionSummary,campaigns,devices,geographic,keywords}`:对应 §3~§7 表格数据;可省略由同名 `google-analysis` section 自动合并。
|
|
39
39
|
- `narrative`(**Agent 必填,唯一由 Agent 撰写的内容**):
|
|
@@ -53,7 +53,7 @@ siluzan-tso google-analysis render \
|
|
|
53
53
|
模板源码:`report-templates/google-period-report.html`(结构与样式,ECharts 渲染逻辑已内联)。
|
|
54
54
|
|
|
55
55
|
`render` 会向输出目录写入 HTML,并注入 `window.__GOOGLE_PERIOD_REPORT__`。
|
|
56
|
-
传 `--snapshot-dir` 时 CLI 自动从快照合并 KPI、每日趋势图表、周期汇总/系列/设备/地域/关键词表格:**数值一律以 CLI 快照覆盖**(`meta` 仅补空)。本期 KPI 优先 `campaigns`
|
|
56
|
+
传 `--snapshot-dir` 时 CLI 自动从快照合并 KPI、每日趋势图表、周期汇总/系列/设备/地域/关键词表格:**数值一律以 CLI 快照覆盖**(`meta` 仅补空)。本期 KPI 优先 `campaigns` 累加。若 manifest 缺条目但磁盘上仍有对应 `*.json`,CLI 会按文件名自愈补齐。Agent 只写 `narrative`,勿自填 `kpis`/`tables`。
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| ---------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
16
|
| **1. 拉数** | Agent 调 CLI | `google-analysis -a <id> --start <s> --end <e> --json-out ./snap-google --sections <见下方默认维度对应 CLI>` |
|
|
17
17
|
| **2. 分析** | Agent | 用 **node/python 脚本**读落盘 JSON(勿用 Read 打开业务 `*.json`),完成筛选、聚合、排序与洞察 |
|
|
18
|
-
| **3. 写 JSON** | Agent | 按 `assets/google-period-report.schema.json` 撰写 `google-period-report.json
|
|
18
|
+
| **3. 写 JSON** | Agent | 按 `assets/google-period-report.schema.json` 撰写 `google-period-report.json`:只写 `meta` + `narrative`(8 维度叙事);`kpis`/`charts`/`tables` 留给步骤 4 的 `--snapshot-dir` 合并(合并后缺 KPI 会拒绝出 HTML) |
|
|
19
19
|
| **4. 渲染 HTML** | CLI | `google-analysis render` — **校验 narrative 8 维度必含字段**,缺项报错不生成 HTML;**禁止** Agent 手写/拼接 HTML |
|
|
20
20
|
|
|
21
21
|
```bash
|
|
@@ -33,7 +33,7 @@ siluzan-tso google-analysis render \
|
|
|
33
33
|
`google-period-report.json` 顶层结构:
|
|
34
34
|
|
|
35
35
|
- `meta`:`accountId`(必填)/ `accountName` / `currency` / `startDate` / `endDate`;可省略由 `--snapshot-dir` 从 `overview` + manifest 自动合并。
|
|
36
|
-
- `kpis`:账户级 KPI(消耗/展示/点击/转化/CTR/CPC/CPA,含可选 `previousPeriod`
|
|
36
|
+
- `kpis`:账户级 KPI(消耗/展示/点击/转化/CTR/CPC/CPA,含可选 `previousPeriod` 环比);Agent 可省略,但 **render 合并后** `cost`/`impressions`/`clicks` 至少一项须为有效数字,否则拒绝出 HTML(避免执行摘要卡片全「—」)。本期 KPI 由 CLI 优先对 `campaigns` 全系列累加并重算比率;无 campaigns 时回退 `overview.currentPeriod`,再回退 `dimension-summary`。环比仍来自 `overview.previousPeriod`。
|
|
37
37
|
- `charts.dailyTrend`:每日趋势(`dates`/`cost`/`conversions`/`cpa`);可省略由 `daily-metrics` 自动合并。
|
|
38
38
|
- `tables.{dimensionSummary,campaigns,devices,geographic,keywords}`:对应 §3~§7 表格数据;可省略由同名 `google-analysis` section 自动合并。
|
|
39
39
|
- `narrative`(**Agent 必填,唯一由 Agent 撰写的内容**):
|
|
@@ -53,7 +53,7 @@ siluzan-tso google-analysis render \
|
|
|
53
53
|
模板源码:`report-templates/google-period-report.html`(结构与样式,ECharts 渲染逻辑已内联)。
|
|
54
54
|
|
|
55
55
|
`render` 会向输出目录写入 HTML,并注入 `window.__GOOGLE_PERIOD_REPORT__`。
|
|
56
|
-
传 `--snapshot-dir` 时 CLI 自动从快照合并 KPI、每日趋势图表、周期汇总/系列/设备/地域/关键词表格:**数值一律以 CLI 快照覆盖**(`meta` 仅补空)。本期 KPI 优先 `campaigns`
|
|
56
|
+
传 `--snapshot-dir` 时 CLI 自动从快照合并 KPI、每日趋势图表、周期汇总/系列/设备/地域/关键词表格:**数值一律以 CLI 快照覆盖**(`meta` 仅补空)。本期 KPI 优先 `campaigns` 累加。若 manifest 缺条目但磁盘上仍有对应 `*.json`,CLI 会按文件名自愈补齐。Agent 只写 `narrative`,勿自填 `kpis`/`tables`。
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
@@ -9,11 +9,11 @@ $ErrorActionPreference = 'Stop'
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
$PKG_NAME = 'siluzan-tso-cli'
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
$PKG_VERSION = '1.1.
|
|
12
|
+
$PKG_VERSION = '1.1.43-beta.2'
|
|
13
13
|
$CLI_BIN = 'siluzan-tso'
|
|
14
14
|
$SKILL_LABEL = 'Siluzan TSO'
|
|
15
|
-
$INSTALL_CMD = 'npm install -g siluzan-tso-cli'
|
|
16
|
-
$WEB_BASE = 'https://www.siluzan.com'
|
|
15
|
+
$INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
|
|
16
|
+
$WEB_BASE = 'https://www-ci.siluzan.com'
|
|
17
17
|
|
|
18
18
|
# -- Constants ----------------------------------------------------------------
|
|
19
19
|
$NODE_MAJOR_MIN = 18
|
|
@@ -9,11 +9,11 @@ set -euo pipefail
|
|
|
9
9
|
# -- Package info (injected at build time) ------------------------------------
|
|
10
10
|
readonly PKG_NAME="siluzan-tso-cli"
|
|
11
11
|
# PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
|
|
12
|
-
readonly PKG_VERSION="1.1.
|
|
12
|
+
readonly PKG_VERSION="1.1.43-beta.2"
|
|
13
13
|
readonly CLI_BIN="siluzan-tso"
|
|
14
14
|
readonly SKILL_LABEL="Siluzan TSO"
|
|
15
|
-
readonly INSTALL_CMD="npm install -g siluzan-tso-cli"
|
|
16
|
-
readonly WEB_BASE="https://www.siluzan.com"
|
|
15
|
+
readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
|
|
16
|
+
readonly WEB_BASE="https://www-ci.siluzan.com"
|
|
17
17
|
|
|
18
18
|
# -- Constants ----------------------------------------------------------------
|
|
19
19
|
readonly NODE_MAJOR_MIN=18
|