siluzan-tso-cli 1.1.15-beta.4 → 1.1.15-beta.5

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 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.15-beta.4),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.15-beta.5),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -3538,6 +3538,10 @@ async function writeGoogleAnalysisSnapshot(params) {
3538
3538
  const writtenAt = (/* @__PURE__ */ new Date()).toISOString();
3539
3539
  const body = JSON.stringify(params.payload, null, 2);
3540
3540
  await fs4.writeFile(path6.join(absDir, fileName), `${body}
3541
+ `, "utf8");
3542
+ const outlineFileName = snapshotOutlineFileName(fileName);
3543
+ const outlineBody = formatOutlineFileBody(fileName, params.payload);
3544
+ await fs4.writeFile(path6.join(absDir, outlineFileName), `${outlineBody}
3541
3545
  `, "utf8");
3542
3546
  const existing = await readManifestIfExists(absDir, accountSlug || void 0);
3543
3547
  const newArtifact = {
@@ -3564,8 +3568,10 @@ async function writeGoogleAnalysisSnapshot(params) {
3564
3568
  schemaVersion: SCHEMA_VERSION,
3565
3569
  absoluteSnapshotDir: absDir,
3566
3570
  manifestFile,
3567
- writtenFiles: [fileName],
3568
- section: params.section
3571
+ writtenFiles: [fileName, outlineFileName],
3572
+ section: params.section,
3573
+ outlineFile: outlineFileName,
3574
+ agentHint: OUTLINE_AGENT_HINT
3569
3575
  };
3570
3576
  }
3571
3577
 
@@ -3573,6 +3579,7 @@ async function writeGoogleAnalysisSnapshot(params) {
3573
3579
  var CLI_SNAPSHOT_MANIFEST_FILE = "cli-manifest.json";
3574
3580
  var CLI_PACKAGE2 = "siluzan-tso-cli";
3575
3581
  var SCHEMA_VERSION2 = 1;
3582
+ var OUTLINE_AGENT_HINT = "\u5904\u7406\u987A\u5E8F\uFF1A\u5148\u8BFB outlineFile\uFF08schema \u63CF\u8FF0\uFF0C\u975E\u6570\u636E\uFF09\u4E86\u89E3\u5B57\u6BB5\u7C7B\u578B\uFF0C\u518D\u7528\u811A\u672C\u8BFB writtenFiles[0]\uFF08\u771F\u5B9E JSON \u6570\u636E\uFF09\u505A\u7B5B\u9009/\u805A\u5408\uFF1B\u4E0D\u8981\u628A outline \u5F53\u6210\u6570\u636E\uFF0C\u4E5F\u4E0D\u8981\u628A JSON \u5F53\u6210 schema\u3002";
3576
3583
  var DEFAULT_FIELD_GUIDE2 = {
3577
3584
  markdownRefs: ["references/tips.md", "references/accounts.md"]
3578
3585
  };
@@ -3706,9 +3713,18 @@ function snapshotOutlineFileName(jsonBasename) {
3706
3713
  }
3707
3714
  return `${jsonBasename.slice(0, -".json".length)}.outline.txt`;
3708
3715
  }
3716
+ function formatOutlineFileBody(jsonBasename, payload) {
3717
+ const typeText = describePayloadTsLike(payload);
3718
+ const lines = [
3719
+ `// outline of \`${jsonBasename}\` \u2014 schema-only, NOT the data.`,
3720
+ `// \u7528\u6CD5\uFF1A\u5904\u7406\u540C\u76EE\u5F55 \`${jsonBasename}\` \u7684\u6570\u636E\u524D\uFF0C\u5148\u8BFB\u672C\u6587\u4EF6\u4E86\u89E3\u5B57\u6BB5\u7C7B\u578B\uFF0C\u518D\u7528\u811A\u672C\uFF08fs.readFileSync / require\uFF09\u8BFB\u53D6\u8BE5 JSON \u505A\u7B5B\u9009\u4E0E\u805A\u5408\u3002`,
3721
+ `// \u7C7B\u578B\u7531 JSON \u63A8\u65AD\uFF1A\u6570\u7EC4\u53D6\u524D 8 \u9879\u53BB\u91CD\u5E76\u96C6\uFF1B\u73AF\u6216\u91CD\u590D\u5BF9\u8C61\u5F15\u7528\u8BB0\u4E3A any\u3002`,
3722
+ typeText
3723
+ ];
3724
+ return lines.join("\n");
3725
+ }
3709
3726
  async function writeCliJsonSnapshot(params) {
3710
3727
  const trimmed = params.snapshotDir.trim();
3711
- const outlineText = describePayloadTsLike(params.payload);
3712
3728
  const idSlug = slugifyIdSuffix(params.idSuffix);
3713
3729
  const manifestFile = cliManifestFileName(idSlug || void 0);
3714
3730
  let absDir;
@@ -3744,7 +3760,8 @@ async function writeCliJsonSnapshot(params) {
3744
3760
  if (outlineFileName.toLowerCase() === manifestFile.toLowerCase()) {
3745
3761
  throw new Error(`\u975E\u6CD5\u8F93\u51FA\uFF1A${outlineFileName} \u4E0E\u6E05\u5355\u6587\u4EF6\u540D\u51B2\u7A81`);
3746
3762
  }
3747
- await fs5.writeFile(path7.join(absDir, outlineFileName), `${outlineText}
3763
+ const outlineBody = formatOutlineFileBody(fileName, params.payload);
3764
+ await fs5.writeFile(path7.join(absDir, outlineFileName), `${outlineBody}
3748
3765
  `, "utf8");
3749
3766
  const existing = await readCliManifestIfExists(absDir, idSlug || void 0);
3750
3767
  const newArtifact = {
@@ -3770,7 +3787,8 @@ async function writeCliJsonSnapshot(params) {
3770
3787
  manifestFile,
3771
3788
  writtenFiles: [fileName, outlineFileName],
3772
3789
  section,
3773
- outlineFile: outlineFileName
3790
+ outlineFile: outlineFileName,
3791
+ agentHint: OUTLINE_AGENT_HINT
3774
3792
  };
3775
3793
  }
3776
3794
  async function emitCliJsonOrSnapshot(opts, params) {
@@ -6429,7 +6447,7 @@ async function writeReportAnalysisSnapshot(params) {
6429
6447
  );
6430
6448
  await fs8.writeFile(
6431
6449
  path11.join(absDir, outlineFileName),
6432
- `${describePayloadTsLike(params.payload)}
6450
+ `${formatOutlineFileBody(fileName, params.payload)}
6433
6451
  `,
6434
6452
  "utf8"
6435
6453
  );
@@ -6459,7 +6477,8 @@ async function writeReportAnalysisSnapshot(params) {
6459
6477
  manifestFile,
6460
6478
  writtenFiles: [fileName, outlineFileName],
6461
6479
  section: params.section,
6462
- outlineFile: outlineFileName
6480
+ outlineFile: outlineFileName,
6481
+ agentHint: OUTLINE_AGENT_HINT
6463
6482
  };
6464
6483
  }
6465
6484
 
@@ -153,6 +153,11 @@ allowed-tools: Bash(siluzan-tso:*) Read Write
153
153
  - **不确定时读文档**:遇到不熟悉的命令,先读对应 references 文件或使用-h查看命令帮助,不要猜参数。
154
154
  - **先查账户再操作**:对具体账户做操作前,先通过 `list-accounts -m [mediaType] -k [mediaCustomerId]` 确认。特别是不确定是Google/Bing/TikTok这些媒体平台中的哪一个的时候
155
155
  - **使用 `--json-out` 处理数据**:需对返回数据做计算或筛选时,**加 `--json-out <目录>`**,再用 `node -e` **读目录内 `*.json`**(见 `references/tips.md`)。若用户**已有一份 JSON 文件**,只问如何筛选时:优先给「读本地文件 + `node -e`」的通用写法,不必默认再跑一遍业务命令。
156
+ - **`--json-out` 摘要的强制处理顺序**:拿到 stdout 摘要后**必须**按 `outlineFile` → `writtenFiles[0]` → 脚本聚合的顺序操作(详见 `references/tips.md`「处理顺序」小节):
157
+ 1. 先 `fs.readFileSync(outlineFile)` 读 `*.outline.txt`(**它是 schema 描述,不是数据**;首行注释会明示 `schema-only, NOT the data`,最后一行是单行 TS 类型字面量),用它确认字段路径;
158
+ 2. 再 `require(writtenFiles[0])` / `fs.readFileSync` 读真实 JSON 做筛选、聚合;
159
+ 3. **禁止**:把 outline 当数据贴给用户、跳过 outline 直接猜字段、把 outline 文件 `require` 当 JSON 解析(它是 `.txt`)。
160
+ 4. 摘要里固定带的 `agentHint` 字段就是这条规则的一句话浓缩,遇到就照做。
156
161
  - **CLI 输出忠实**:向用户引用数值与 ID 时,须与**本次落盘 JSON 或表格 stdout** 一致,不得换成别的示例 ID。禁止编造「stub/示例环境/登录异常」等**未在 CLI 输出或 stderr 中出现**的解释;`data` 为空时只说明「当前返回无记录」并附上原始 JSON 路径或片段。
157
162
  - **用户明确要求原始 JSON**:优先交付**快照文件路径**及 `cli-manifest.json` 条目;若用户坚持要对话内整包 JSON,可临时用 **`--json`**(stdout)满足,但**默认编排仍用 `--json-out`**。
158
163
  - **不要猜测账户 ID**:`entityId` ≠ `mediaCustomerId`,两者均来自 `list-accounts`。
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.15-beta.4",
4
- "publishedAt": 1778057745812
3
+ "version": "1.1.15-beta.5",
4
+ "publishedAt": 1778066658466
5
5
  }
@@ -13,6 +13,27 @@
13
13
 
14
14
  ---
15
15
 
16
+ ## 处理顺序(**Agent 必读**):先 outline → 再 JSON → 再脚本聚合
17
+
18
+ 每条 `--json-out` 命令成功后,**必须**按以下顺序处理,不要跳步、不要把 outline 当数据:
19
+
20
+ 1. **先读 stdout 一行摘要 JSON**:拿到 `outlineFile`、`writtenFiles[0]`、`manifestFile`,以及固定回显的 **`agentHint`** 一行说明(即"先读 outline 再读 JSON"的提示)。**不要硬编码 `<section>.json` 文件名**。
21
+ 2. **再 `fs.readFileSync(outlineFile, 'utf8')` 读 outline 文件**(即 `*.outline.txt`):
22
+ - 第 1 行(注释):`// outline of \`<xxx>.json\` — schema-only, NOT the data.` —— **明确告诉你它是"数据结构描述文件"**,不要把它当业务数据使用。
23
+ - 第 2 行(注释):中文用法说明。
24
+ - 第 3 行(注释):类型推断口径(数组取前 8 项去重并集;环或重复对象记为 any)。
25
+ - **最后一行**:单行 TypeScript 类型字面量(`{ a: number; b: string; items: { ... }[] }`)—— 你写筛选/聚合脚本时**只看这一行**就能拿到完整字段路径。
26
+ - 提取最后一行的写法:`outlineRaw.trimEnd().split('\n').filter(l => !l.startsWith('//')).pop()`,或简单地 `lines[lines.length - 1]`。
27
+ 3. **再 `require(writtenFiles[0])` / `fs.readFileSync` 读真实 JSON 数据**做筛选、聚合、计算。**禁止**:
28
+ - 把 outline 文件 `require` 进来当 JSON 解析(它是 `.txt` 不是 JSON);
29
+ - 跳过 outline 直接猜 JSON 字段名;
30
+ - 把 outline 当成"摘要数据"贴给用户当结论。
31
+ 4. **交付物**用代码(Node / Python + 数据处理库)写出对应格式(HTML / Excel / PDF / PPT / Markdown 等),不要在对话里手填数。
32
+
33
+ > 这个顺序对所有三类快照统一生效:通用业务命令(`cli-manifest[-<id>].json`)、`google-analysis`(`manifest-<accountId>.json`)、`report …` 分析(`report-manifest[-<accountId>].json`)。三种 summary 都带 `outlineFile`、`agentHint` 字段。
34
+
35
+ ---
36
+
16
37
  ## 已有 JSON 时(不必先重跑 CLI)
17
38
 
18
39
  用户已保存输出或只问「怎么从一大坨 JSON 里筛字段」时:直接用 **本地文件** 喂给 `node -e` 即可,不必为示例再执行 `list-accounts` 等业务命令(字段路径以实际响应为准;列表类命令多为 `items[]` 外层分页结构)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.15-beta.4",
3
+ "version": "1.1.15-beta.5",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",