diff --git a/shortcuts/sheets/data/flag-defs.json b/shortcuts/sheets/data/flag-defs.json index ab97963bc..d8687e227 100644 --- a/shortcuts/sheets/data/flag-defs.json +++ b/shortcuts/sheets/data/flag-defs.json @@ -495,7 +495,7 @@ "kind": "own", "type": "string", "required": "optional", - "desc": "Required only in csv mode: the sheet reference_id to export" + "desc": "Required only in csv mode: which sheet to export as CSV. This is a `+workbook-export`-specific flag, unrelated to the common four-tuple sheet locator (this shortcut does not accept the common sheet locator)" }, { "name": "output-path", @@ -3745,7 +3745,7 @@ "kind": "own", "type": "string", "required": "optional", - "desc": "Filter rule JSON: `rules` (required, per-column rule array), `filtered_columns?` (active column index hint). `range` is a separate flag (do not duplicate inside this JSON)", + "desc": "Filter rule JSON: `rules` (per-column rule array), `filtered_columns?` (active column index hint). The flag is optional overall — if provided, `rules` must be non-empty; if omitted, an empty filter is created on `--range` (no column conditions). `range` is a separate flag (do not duplicate inside this JSON)", "input": [ "file", "stdin" @@ -4410,7 +4410,7 @@ "kind": "own", "type": "string", "required": "xor", - "desc": "Image reference_id (XOR with `--image-token`); a prefixed string like `<|image|>:abcdef`" + "desc": "Image reference_id (XOR with `--image-token`); the reference_id returned by the image upload flow" }, { "name": "position-row", @@ -4527,7 +4527,7 @@ "kind": "own", "type": "string", "required": "xor", - "desc": "Image reference_id (XOR with `--image-token`); a prefixed string like `<|image|>:abcdef`" + "desc": "Image reference_id (XOR with `--image-token`); the reference_id returned by the image upload flow" }, { "name": "position-row", diff --git a/skills/lark-sheets/SKILL.md b/skills/lark-sheets/SKILL.md index 91cddfd53..55ffe244f 100644 --- a/skills/lark-sheets/SKILL.md +++ b/skills/lark-sheets/SKILL.md @@ -13,6 +13,16 @@ metadata: **CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),其中包含认证、权限处理。** +## 术语约定 + +下列词在本 skill 各文档中可能交替出现,但**指同一对象**;解析用户口语时按此映射,不要当成不同概念: + +| 标准用语 | 同义 / 口语(均指同一对象) | 说明 | +| --- | --- | --- | +| 工作表(sheet) | 子表、tab、标签页 | spreadsheet 内的单张表;`sheet_id` 是其稳定标识 | +| 电子表格(spreadsheet) | 工作簿、表格 | 顶层容器;由 `--url` 或 `--spreadsheet-token` 定位 | +| reference_id | id | 各 `*-id` flag(`--sheet-id` / `--chart-id` / `--pivot-table-id` / `--group-id` / `--view-id` 等)接受的对象标识符,统称 reference_id | + ## References 本 skill 按能力子域组织,每个子域有独立 reference。先按下表索引定位到目标子域,再进入对应 reference 查 shortcut / 调用细节。 @@ -41,21 +51,35 @@ metadata: 各 reference 的每个 shortcut 标题下用一行徽章标注该 shortcut 支持的公共 / 系统 flag,例如: -- `_公共四件套 · 系统:--dry-run_` — URL/token + sheet 定位全 4 个公共 flag,加 `--dry-run` +- `_公共四件套 · 系统:--dry-run_` — URL/token + sheet 定位(两组各**必给一个**,详见下方「公共 flag」),加 `--dry-run` - `_公共:URL/token(无 sheet 定位) · 系统:--yes、--dry-run_` — 只接 URL/token,常见于 `+batch-update` 等不强制 sheet 定位的 shortcut 徽章里只列名字。type / 必填 / 描述都在本段统一声明: ### 公共 flag(定位资源) -**公共四件套** = `--url` / `--spreadsheet-token` / `--sheet-id` / `--sheet-name`。前两者 XOR 互斥(spreadsheet 定位),后两者 XOR 互斥(sheet 定位)。 +**公共四件套** = `--url` / `--spreadsheet-token` / `--sheet-id` / `--sheet-name`,分成两组 XOR,**每组都必须给且只能给一个**(XOR = 二选一必填,不是"可选"): + +1. **spreadsheet 定位(必填)**:`--url` 与 `--spreadsheet-token` 二选一,**必须给其中之一**。两个都不给 → 校验报错 `specify at least one of --url or --spreadsheet-token`;两个都给 → 互斥冲突。 +2. **sheet 定位(公共四件套 shortcut 必填)**:`--sheet-id` 与 `--sheet-name` 二选一,**必须给其中之一**。两个都不给 → 校验报错 `specify at least one of --sheet-id or --sheet-name`。 + - ⚠️ **`--range` 里的 `Sheet1!` 前缀不能替代 sheet 定位**:即使写了 `--range "Sheet1!A1:B2"`,仍**必须**额外传 `--sheet-id` 或 `--sheet-name`,否则照样报上面的错。 + - **例外**:徽章标为 `_公共:URL/token(无 sheet 定位)…_` 的 shortcut(如 `+workbook-info` / `+workbook-export` / `+batch-update` / `+dropdown-get|update|delete` / `+cells-batch-set-style` / `+cells-batch-clear` / `+sheet-create`)**不接受也不需要** sheet 定位,只给一组 spreadsheet 定位即可。 | Flag | Type | 必填 | 说明 | | --- | --- | --- | --- | -| `--url` | string | XOR | spreadsheet URL;与 `--spreadsheet-token` 二选一 | -| `--spreadsheet-token` | string | XOR | spreadsheet token;与 `--url` 二选一 | -| `--sheet-id` | string | XOR | 工作表 reference_id;与 `--sheet-name` 二选一 | -| `--sheet-name` | string | XOR | 工作表名称;与 `--sheet-id` 二选一 | +| `--url` | string | 二选一必填(与 `--spreadsheet-token`) | spreadsheet URL | +| `--spreadsheet-token` | string | 二选一必填(与 `--url`) | spreadsheet token | +| `--sheet-id` | string | 二选一必填(与 `--sheet-name`;仅公共四件套 shortcut) | 工作表 reference_id | +| `--sheet-name` | string | 二选一必填(与 `--sheet-id`;仅公共四件套 shortcut) | 工作表名称 | + +**统一调用范式**(公共四件套 shortcut 的所有示例都遵循此形状,两组定位缺一不可): + +```bash +lark-cli sheets <其它 flag> +# workbook 定位:--url "..." 或 --spreadsheet-token "..." (二选一,必给) +# sheet 定位: --sheet-id "$SID" 或 --sheet-name "Sheet1" (二选一,必给) +# 例:lark-cli sheets +csv-get --url "https://.../sheets/shtXXX" --sheet-name "Sheet1" --range "A1:F30" +``` ### 系统 flag @@ -66,7 +90,7 @@ metadata: | `--print-schema` | bool | 否 | 本地打印复合 JSON flag 的 JSON Schema 并退出,不发起任何调用、不需要其它 required flag。与 `--flag-name ` 搭配指定要查哪个 flag;省略 `--flag-name` 时列出该 shortcut 所有可查询的 flag。**仅在 shortcut 含复合 JSON flag 时有效**——判断方法:该 shortcut 的 Flags 表里出现类型标注为「复合 JSON」的 flag(如 `--cells` / `--properties` / `--operations` / `--border-styles` / `--sort-keys` / `--options`)即支持;纯标量 flag 的 shortcut 不支持。 | | `--flag-name` | string | 否 | 配合 `--print-schema` 使用,指定要打印 JSON Schema 的 flag 名(不带 `--` 前缀,如 `cells` / `properties` / `operations`)。 | -**Agent 使用提示**:写复合 JSON flag(`--cells` / `--properties` / `--operations` / `--border-styles` / `--sort-keys` 等)时,如果对结构不确定,先跑 `lark-cli sheets --print-schema --flag-name ` 把完整 JSON Schema 读出来再构造 payload,比靠 reference 的速查表更精确,也避免因为字段拼写或缺失被服务端拒绝。reference 的 `## Schemas` 段只给一层结构,深层只能靠 `--print-schema` 或 `## Examples` 的真实示例。 +**Agent 使用提示**:写复合 JSON flag(`--cells` / `--properties` / `--operations` / `--border-styles` / `--sort-keys` / `--options` 等)时,如果对结构不确定,先跑 `lark-cli sheets --print-schema --flag-name ` 把完整 JSON Schema 读出来再构造 payload,比靠 reference 的速查表更精确,也避免因为字段拼写或缺失被服务端拒绝。reference 的 `## Schemas` 段只给一层结构,深层只能靠 `--print-schema` 或 `## Examples` 的真实示例。 ## 复合 JSON / 大入参:优先 stdin @@ -75,7 +99,7 @@ flag 帮助里标注支持 **Stdin** 的入参,当 payload 较大、含换行 推荐写法:payload 写到 cwd 之外的临时文件(如 `/tmp/cells.json`,不污染用户项目目录),再用 stdin 喂进去: ```bash -lark-cli sheets +cells-set --url "..." --range "A1:B2" --cells - < /tmp/cells.json +lark-cli sheets +cells-set --url "..." --sheet-name "Sheet1" --range "A1:B2" --cells - < /tmp/cells.json ``` **`@file` 接绝对路径会被拒,且被拒后不要照报错提示做。** `@file` 出于安全只接受 cwd 下的相对路径,传 `@/tmp/cells.json` 这类绝对路径或 cwd 之外的路径会被拒。此时报错会建议"先 cd 到目标目录,或改用相对路径"——**两条都不要照做**:cd 过去、或把临时文件写进用户项目目录,都会污染工作目录。正解是改用 stdin(`-- - < 文件`)。 diff --git a/skills/lark-sheets/references/lark-sheets-batch-update.md b/skills/lark-sheets/references/lark-sheets-batch-update.md index 1bb8a009d..ba3160e0b 100644 --- a/skills/lark-sheets/references/lark-sheets-batch-update.md +++ b/skills/lark-sheets/references/lark-sheets-batch-update.md @@ -5,20 +5,22 @@ `+batch-update` 把多次写入打包成单次请求,但每个子操作仍受编辑类任务硬性默认规则约束: 1. **目标 range 必须落在用户授权范围内**:除用户明示要修改的区域外,子操作禁止扩张到无关单元格 / 列 / Sheet。规划 range 时先确认每个子操作的边界。 -2. **批次完成后必须回读校验**:整个 `+batch-update` 执行成功后,用 `+csv-get` 或 `+cells-get` 抽样回读受影响区域,至少校验 3-5 个代表性单元格(首 / 中 / 末),与 本地脚本 预先计算的预期值对照。 +2. **批次完成后必须回读校验**:整个 `+batch-update` 执行成功后,用 `+csv-get` 或 `+cells-get` 抽样回读受影响区域,至少校验 3-5 个代表性单元格(首 / 中 / 末),与本地脚本预先计算的预期值对照。 3. **预期条数前置断言**:涉及"批量填充 N 行"或"对 M 个区域分别写入"时,先把 N、M 硬编码进代码,回读后断言实际等于预期;不一致就再发一轮 `+batch-update` 补齐,禁止交付半成品。 ## 使用场景 写入。批量执行多个写入工具操作。将多个工具调用合并为一次请求,按顺序依次执行。适合需要连续执行多个写入操作的场景(如先修改结构再写入数据)。注意:不支持嵌套 `+batch-update`。 +**不可放进 `--operations` 的写 shortcut**(`shortcut` 枚举不含它们,强行写入会被校验拒):`+cells-set-image`(需本地上传图片)、`+dropdown-update` / `+dropdown-delete` / `+cells-batch-set-style` / `+cells-batch-clear`(自身已是批量入口,不可再嵌套)、`+dim-move`。这些操作需在 `+batch-update` 之外单独调用。 + **⚠️ 何时必须使用 `+batch-update`(硬性要求)**: - 需要对**多个**不同区域执行 `+cells-{merge|unmerge}` 时(如按分组合并多列相同内容) - 需要对**多个**不同区域执行 `+rows-resize / +cols-resize` 时(如统一调整多列列宽或多行行高) - 需要先插入行列再写入数据时(`+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` + `+cells-set`) - 需要对多个区域执行不同写入操作时(多次 `+cells-set` + `+cells-clear` 等组合) -当同一工具需要对多个区域重复调用时,**必须**改用 `+batch-update` 合并为单次请求。逐个调用会快速耗尽工具调用轮次上限(60R),导致任务无法完成。 +当同一工具需要对多个区域重复调用时,**必须**改用 `+batch-update` 合并为单次请求——`+batch-update` 是原子提交(要么全成功要么整批回滚);逐个调用非原子,中途失败会留下半成品。 ## Shortcuts diff --git a/skills/lark-sheets/references/lark-sheets-chart.md b/skills/lark-sheets/references/lark-sheets-chart.md index 9ca096071..b477e7742 100644 --- a/skills/lark-sheets/references/lark-sheets-chart.md +++ b/skills/lark-sheets/references/lark-sheets-chart.md @@ -2,7 +2,7 @@ ## 真对象硬约束 -当用户要求"画个图 / 数据可视化 / 趋势图 / 对比图 / 占比图"时,**必须**通过 `+chart-{create|update|delete}` 创建真实的图表对象。**禁止**用 本地脚本 调 matplotlib / seaborn 生成图片再插入到表格代替——静态图片无法随源数据更新,且失去交互能力。判断标准:交付后 `+chart-list` 必须能返回该对象。 +当用户要求"画个图 / 数据可视化 / 趋势图 / 对比图 / 占比图"时,**必须**通过 `+chart-{create|update|delete}` 创建真实的图表对象。**禁止**用本地脚本调 matplotlib / seaborn 生成图片再插入到表格代替——静态图片无法随源数据更新,且失去交互能力。判断标准:交付后 `+chart-list` 必须能返回该对象。 ## 使用场景 @@ -80,9 +80,9 @@ ## 图表位置选择(创建前必做) -凭感觉挑列号/行号会被 API 拒(`position is out of sheet range`),浪费一轮调用。按以下四步走: +凭感觉挑列号/行号会被 API 拒(`position is out of sheet range`)。按以下四步走: -1. **查尺寸**:`+sheet-info` 拿 `rowCount` / `columnCount`。 +1. **查尺寸**:`+workbook-info` 拿该 sheet 的 `row_count` / `column_count`(下文记为 rowCount / columnCount;`+sheet-info` 只返回布局,不含行列总数)。 2. **估跨度**:默认单元格 **105 px 宽 × 27 px 高**,`needCols = ceil(width/105)`,`needRows = ceil(height/27)`。 3. **校验**:`position.row + needRows ≤ rowCount` 且 `col_idx + needCols ≤ columnCount`(col 按 A=0、B=1、…、Z=25、AA=26… 换算)。 4. **不够就先扩表**,二选一,禁止硬塞越界位置: @@ -165,9 +165,10 @@ _创建/更新的图表属性_ 示例: ```bash -# 内联 JSON +# 内联 JSON —— 最小列图骨架(inline 模式:refs 含表头行,首列/首行即类别/系列名) +# 完整字段(堆叠/数据标签/detached/坐标轴等)跑 --print-schema --flag-name properties lark-cli sheets +chart-create --url "https://example.feishu.cn/sheets/shtXXX" \ - --sheet-name "Sheet1" --properties '{"position":{"row":42,"col":"A"},"size":{"width":600,"height":400},"snapshot":{...}}' + --sheet-name "Sheet1" --properties '{"position":{"row":42,"col":"A"},"size":{"width":600,"height":400},"snapshot":{"data":{"refs":[{"value":"Sheet1!A1:B10"}]},"plotArea":{"plot":{"type":"column"}}}}' # 走文件(推荐配置较多时) lark-cli sheets +chart-create --url "https://example.feishu.cn/sheets/shtXXX" \ @@ -188,12 +189,12 @@ lark-cli sheets +chart-create --url "https://example.feishu.cn/sheets/shtXXX" \ 示例: ```bash -# dry-run 先看会删什么 -lark-cli sheets +chart-delete --url "https://example.feishu.cn/sheets/shtXXX" \ +# dry-run 先看会删什么(sheet 定位必填) +lark-cli sheets +chart-delete --url "https://example.feishu.cn/sheets/shtXXX" --sheet-id "$SID" \ --chart-id "chrXXX" --dry-run # 真正执行 -lark-cli sheets +chart-delete --url "https://example.feishu.cn/sheets/shtXXX" \ +lark-cli sheets +chart-delete --url "https://example.feishu.cn/sheets/shtXXX" --sheet-id "$SID" \ --chart-id "chrXXX" --yes ``` diff --git a/skills/lark-sheets/references/lark-sheets-conditional-format.md b/skills/lark-sheets/references/lark-sheets-conditional-format.md index 3af0eda7b..5e497033c 100644 --- a/skills/lark-sheets/references/lark-sheets-conditional-format.md +++ b/skills/lark-sheets/references/lark-sheets-conditional-format.md @@ -14,7 +14,7 @@ **判断标准**:交付后 `+cond-format-list` 必须能返回该规则;否则视为违规。 -**大数据量加分项**:当数据量 > 1000 行时,条件格式是首选——它由飞书自身渲染,不会触发 本地脚本 50 秒超时(同 R8)。 +**大数据量首选**:当数据量 > 1000 行时,条件格式是首选——它由飞书自身渲染,比"本地脚本逐行计算 + `+cells-set` 写静态背景色"更高效、更稳(颜色还能随源数据自动联动)。 ## 使用场景 @@ -61,7 +61,7 @@ Step 2: 基于辅助列值做条件格式(用 cellIs 或引用辅助列的 exp `+cond-format-{create|update|delete}` create rule_type: "expression" ranges: ["2:145"] - attrs: [{formula: ["=$O2>$H2"]}] ← 虽然逻辑等价,但产物里缺辅助列 → 扣配置需求分 + attrs: [{formula: ["=$O2>$H2"]}] ← 虽然逻辑等价,但产物里缺辅助列 → 不满足用户明确要求的"辅助列"诉求 ``` 为什么禁止一步走:用户明确要求辅助列是有**业务意图**的——让人肉眼能在表里看到"是/否"列;条件格式只是视觉辅助。一步 expression 虽然效果对了,但用户打开表格看不到辅助列,被视为"操作不完整/未采用公式"。 @@ -167,7 +167,7 @@ lark-cli sheets +cond-format-create --url "..." --sheet-id "$SID" \ ### `+cond-format-delete` ```bash -lark-cli sheets +cond-format-delete --url "..." --rule-id "$RULE_ID" --yes +lark-cli sheets +cond-format-delete --url "..." --sheet-id "$SID" --rule-id "$RULE_ID" --yes ``` ### Validate / DryRun / Execute 约束 diff --git a/skills/lark-sheets/references/lark-sheets-core-operations.md b/skills/lark-sheets/references/lark-sheets-core-operations.md index 62e6138ca..68902e234 100644 --- a/skills/lark-sheets/references/lark-sheets-core-operations.md +++ b/skills/lark-sheets/references/lark-sheets-core-operations.md @@ -4,13 +4,13 @@ 这是面向"已有飞书表格"的核心工作流。核心原则是:先了解,再分析或写入,最后验证。 -## 编辑前必读:8 条默认规则 +## 编辑前必读:7 条默认规则 -> 所有编辑类任务(修改 / 排序 / 筛选 / 删除 / 透视 / 批量填充)**必须**先满足以下 8 条,再进入下方「硬性规则」和具体子 skill。任何子 skill 不得放宽这 8 条。 +> 所有编辑类任务(修改 / 排序 / 筛选 / 删除 / 透视 / 批量填充)**必须**先满足以下 7 条,再进入下方「硬性规则」和具体子 skill。任何子 skill 不得放宽这 7 条。 1. **R1 最小改动**:除用户明示要修改的单元格 / 列外,原表其它单元格、行列结构、Sheet 名称、合并区域、格式必须 1:1 保持。中间结果 / 标注列优先放在原数据列**右侧**;当中间结果会与原数据混淆,或需要承载结构化对象(透视表 / 图表)时可**新建空白 Sheet**。**禁止**擅自删除 / 重命名 / 隐藏 / 移动**已存在**的原 Sheet(新建是允许的,节制使用即可)。 -2. **R2 真实写回**:编辑任务的最终交付必须是对在线表格的真实写入并回读校验。**严禁**只在文本里描述"已完成 X" 没有任何写入;**严禁**用普通公式 / 文本汇总假装"透视表 / 筛选 / 图表 / 条件格式 / 迷你图"等结构化对象;**严禁**只输出 `{"type": "LarkExcelCard", "refs": [...]}` 形式的引用作为交付——LarkExcelCard 引用 ≠ 真实写入,必须有对应的 `+cells-set` / `+<对象>-{create|update|delete}`(图表 / 透视表 / 条件格式 / 筛选 / 迷你图 / 浮动图片)工具调用,并能用 `+<对象>-list`(或 `+csv-get` / `+cells-get`)回读到改动结果。 -3. **R3 计算复现**:涉及计算、排序、筛选、聚合、批量数据提取的任务,必须用 本地脚本 独立复现一份预期值,与回读结果对照通过后再交付。设计公式 / 筛选条件前先 sample 至少 50 行识别该列所有值类型变体(纯数值 / 公式文本 / 多种日期格式 / 空值),不能只看前 10 行。 +2. **R2 真实写回**:编辑任务的最终交付必须是对在线表格的真实写入并回读校验。**严禁**只在文本里描述"已完成 X" 没有任何写入;**严禁**用普通公式 / 文本汇总假装"透视表 / 筛选 / 图表 / 条件格式 / 迷你图"等结构化对象;**严禁**只给出引用 / 占位而无真实写入。必须有对应的 `+cells-set` / `+<对象>-{create|update|delete}`(图表 / 透视表 / 条件格式 / 筛选 / 迷你图 / 浮动图片)工具调用,并能用 `+<对象>-list`(或 `+csv-get` / `+cells-get`)回读到改动结果。 +3. **R3 计算复现**:涉及计算、排序、筛选、聚合、批量数据提取的任务,必须用本地脚本独立复现一份预期值,与回读结果对照通过后再交付。设计公式 / 筛选条件前先 sample 至少 50 行识别该列所有值类型变体(纯数值 / 公式文本 / 多种日期格式 / 空值),不能只看前 10 行。 4. **R4 处理完整性**:全量逐条处理类任务(翻译 / 打标 / 删除指定行 / 批量公式落地 / 按条件保留),落地前先把"预期处理条数"硬编码进代码,处理完后 `assert actual == expected`。**严禁**输出"已完成前 N 条,剩余将继续"这类半成品文案。 5. **R5 指令语义还原**:"按 X 排序" / "筛选 X" / "把 X 删除" 落地前先回答:① X 在哪一列?该列实际值类型是什么?② 期望结果集大小是多少?答完再动手;禁止直接对混合文本列做字符串排序 / 筛选。 6. **R6 任务拆解为可验证 checklist**:用户的指令落地前,**必须**先拆成所有"独立可验证子要点",每点对应一个 `assert`,全部通过才交付: @@ -18,20 +18,9 @@ - **多目标操作**("删除 N 条 / N 行")→ 每目标一个 assert - **多格式兼容**(日期 YYYYMM / YYYY-MM-DD / 时间戳)→ 每种格式至少一个样本通过 - **范围类操作**("加边框 A1:H11"、"覆盖第 2~218 行")→ 起始 / 末行 / 末列三个边界都要核 - - **单一指令隐含多个失败模式**(如"用公式算面积"隐含"提取数值 / 乘以数量 / 单位转换 / 公式而非硬编码 / 不超时"等多个验收点)→ 每点独立 assert + - **单一指令隐含多个失败模式**(如"用公式算面积"隐含"提取数值 / 乘以数量 / 单位转换 / 公式而非硬编码"等多个验收点)→ 每点独立 assert 只完成第一个要点就交付(典型如:按部门只排一级、删 3 行只删 1 行、兼容日期只兼容 YYYYMM)属于违规。 7. **R7 公式模式延续**:扩展 / 续写 / 新增行列时,**必须**先用 `+cells-get` 读原数据区域的 `formula` 字段,识别公式模式,新行新列必须延续相同模式。**禁止**把原表 `=C3/B3` / `=SUM(B3:B9)` 模式在新行替换为硬编码常数(如 `0.85` / `50`)这种破坏数据驱动性的写法。**用户口头操作("分列 / 排序 / 提取 / 求和")也必须落地为公式或原生工具**(SORT 公式 / 分列 / `TEXTBEFORE` / `MID` / `+filter-{create|update|delete}` / `+pivot-{create|update|delete}` 等),不能只写静态结果——否则用户改源数据时结果不再联动,等同破坏了表格的数据驱动性。 -8. **R8 大数据量超时降级走原生工具**:当任务涉及 **> 1000 行**数据 / 预估 本地脚本 超 50 秒时,**禁止**继续用代码逐行处理,**必须**改走原生工具: - - | 任务类型 | 必须使用 | 禁止 | - |---|---|---| - | 重复检测 / 条件高亮 / 颜色标记 | `+cond-format-{create|update|delete}` | 本地脚本 逐行 + `+cells-set` 静态背景色 | - | 大批量行公式填充 | 模板公式 + `--copy-to-range "X:X"` | 本地脚本 计算每行 + 静态写入 | - | 大数据筛选 | `+filter-{create|update|delete}` 或 `+pivot-{create|update|delete}` | 复制到新 sheet 后覆盖 | - | 大批量数据 set | 分批 `+cells-set`,每批 ≤ 100 行 | 一次写 1000+ 行 | - | 大批量翻译 / NLP | 分 30 行/批,每批后立即写回 | 一次性处理全表后才写回 | - - **严禁**遇到超时仅输出"由于数据量过大,无法自动完成"的文本说明 + 手动操作步骤——这等同于零分交付。**严禁**输出 LarkExcelCard 引用作为"已完成"的证据(同 R2)。 ## 硬性规则 @@ -45,7 +34,7 @@ - 数据分析/清洗/可视化/大数据集 → 同上路径 A - 快速查看少量数据或简单问答(只读、不回写) → `+csv-get` 读取到对话上下文 - 需要公式/样式/批注 → `+cells-get` - - **续写/扩展已有内容** → 必须用 `+cells-get` 读取源区块样式 + `+sheet-info` 读取行高和合并信息(见硬性规则 12) + - **续写/扩展已有内容** → 必须用 `+cells-get` 读取源区块样式 + `+sheet-info --include row_heights,merges` 读取行高和合并信息(见硬性规则 12) **读取前 10 行后按表格形态分流(路径 B/C 批量写入前强制)**:表格形态决定第二步读不读、读什么。先用 `range: "A1:Z10"` 探查,然后根据返回的 `annotated_csv` 分类: @@ -69,15 +58,15 @@ 5. **区分公式语法和工具参数语法**:公式字符串中的范围引用(如 `H:H`、`$A$2:$B$5`)遵循飞书公式语法;而 CLI 工具的 `range` / `ranges` / `--copy-to-range` 参数使用 A1 表示法(如 `A1:D3`、`1:1`)。两者写法不同,混淆会导致调用失败。 -6. **合并单元格需特殊处理**:合并区域只有左上角单元格存储数据,其余位置读取为空——这不代表”无内容”,而是合并的正常行为。写入时只能写左上角,写其他位置会报错或被忽略。如需修改合并区域中间的某格,先取消合并再操作。**在合并区域中间行插入数据之前,必须先调用 `+cells-get` 或 `+sheet-info` 确认目标行是否落在某个合并区域内**——直接用 `+cells-set` 写入合并区域的非左上角单元格,后端会返回 `cell at row N, col M is inside a merged region` 错误;即使 LLM 响应错误后改调 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` 插入行,行号也可能因合并扩展而错位。同理,**新增列后若原表存在合并的标题行(如 A1:F1),需要手动用 `+cells-{merge|unmerge}` 扩展合并范围到新列(如 A1:I1)**,否则标题行不会跟着变宽。 +6. **合并单元格需特殊处理**:合并区域只有左上角单元格存储数据,其余位置读取为空——这不代表”无内容”,而是合并的正常行为。写入时只能写左上角,写其他位置会报错或被忽略。如需修改合并区域中间的某格,先取消合并再操作。**在合并区域中间行插入数据之前,必须先调用 `+cells-get` 或 `+sheet-info --include merges` 确认目标行是否落在某个合并区域内**——直接用 `+cells-set` 写入合并区域的非左上角单元格,后端会返回 `cell at row N, col M is inside a merged region` 错误;即使 LLM 响应错误后改调 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` 插入行,行号也可能因合并扩展而错位。同理,**新增列后若原表存在合并的标题行(如 A1:F1),需要手动用 `+cells-{merge|unmerge}` 扩展合并范围到新列(如 A1:I1)**,否则标题行不会跟着变宽。 -7. **多步写入优先用 `+batch-update`**:当任务涉及多个连续写入操作时,优先使用 `lark-sheets-batch-update` 中的 `+batch-update` 将它们合并为单次请求,减少调用轮次。**特别是以下场景必须用 `+batch-update`**: +7. **多步写入优先用 `+batch-update`**:当任务涉及多个连续写入操作时,优先使用 `lark-sheets-batch-update` 中的 `+batch-update` 将它们合并为单次原子请求(一次提交,要么全成功要么整批回滚,也更快、更不易出错)。**特别是以下场景必须用 `+batch-update`**: - 需要对多个不同区域执行 `+cells-{merge|unmerge}`(如按合同编号合并多列相同内容)→ 将所有 merge 操作放进一个 `+batch-update` - 需要对多个不同区域执行 `+rows-resize / +cols-resize`(如统一调整多列列宽或多行行高)→ 将所有 resize 操作放进一个 `+batch-update` - 需要先插入行列再写入数据 → 将 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` + `+cells-set` 放进一个 `+batch-update` - 当同一工具需要对多个区域重复调用时,**必须**改用 `+batch-update` 合并为单次请求 -8. **结构操作用专用工具**:插入/删除行列用 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}`(一次操作可处理数千行),不要用 `+cells-set` 逐行搬数据——后者既慢又容易出错。用户给多步骤请求时,每个步骤都要执行,执行后重新验证。**`+dim-insert`(`--inherit-style before`/`after`)只继承相邻行的值/公式/边框,不继承 `row_height`**:插入后新行行高会回落到默认值(约 22px),若原行是高行高(容纳多行自动换行文本),新行长文本会被裁切(显示不全,末尾字符被截断)。**在中间插入行并填入文本前,必须先用 `+sheet-info` 读取相邻原行的 `row_height`,再用 `+batch-update` 合并 `+rows-resize / +cols-resize` 把同一高度应用到新行**——"在中间插入行填数据"本质等价于"续写已有内容",必须走硬性规则 12 的同一套样式继承流程(行高、边框、合并、对齐)。 +8. **结构操作用专用工具**:插入/删除行列用 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}`(一次操作可处理数千行),不要用 `+cells-set` 逐行搬数据——后者既慢又容易出错。用户给多步骤请求时,每个步骤都要执行,执行后重新验证。**`+dim-insert`(`--inherit-style before`/`after`)只继承相邻行的值/公式/边框,不继承 `row_height`**:插入后新行行高会回落到默认值(约 22px),若原行是高行高(容纳多行自动换行文本),新行长文本会被裁切(显示不全,末尾字符被截断)。**在中间插入行并填入文本前,必须先用 `+sheet-info --include row_heights` 读取相邻原行的 `row_height`,再用 `+batch-update` 合并 `+rows-resize / +cols-resize` 把同一高度应用到新行**——"在中间插入行填数据"本质等价于"续写已有内容",必须走硬性规则 12 的同一套样式继承流程(行高、边框、合并、对齐)。 9. **写入前精确定位表头和数据区域**:在执行任何写操作之前,必须先通过读取数据确认: - 表头在哪一行(不要假设表头一定在第 1 行,可能存在标题行、空行等) @@ -87,19 +76,19 @@ - **区分"表尺寸"与"数据占用范围"(新增列场景关键)**:`+workbook-info` 返回的 `column_count`(如 20 列)和 `row_count` 是**整个 sheet 的物理尺寸**,默认值可能远大于真实数据范围(比如一张只有 6 列数据的表可能 `column_count=20` 甚至 `column_count=100`)。**新增列 / 插入列之前,必须先调用一次 `+csv-get`(请求 `range: "A1:Z1"` 或表头附近一小块即可),读取返回值里的 `current_region` 作为真实数据矩形**,再基于 `current_region` 的右边界决定插入位置。例如 `current_region: "A1:F72"` → 数据末列是 F → 新增 3 列应插到 G/H/I,禁止插到 T(表尺寸末列)。否则新列和原数据之间会有一大片空列,用户看到的是"数据没动,三个空列在表尾"。 如果表头定位错误,后续所有公式和写入都会偏移,导致整体失败。 -10. **公式填充必须用 `--copy-to-range`,禁止逐行写入**:当同一公式需要向下填充到多行时,必须先用 `+cells-set` 在第一行写入模板公式,再用 `--copy-to-range` 填充整列(如 `--copy-to-range "H2:H100"` 或 `--copy-to-range "H:H"`)。**禁止**对每一行单独调用 `+cells-set` 写入相同结构的公式——这会浪费大量调用轮次。 +10. **公式填充必须用 `--copy-to-range`,禁止逐行写入**:当同一公式需要向下填充到多行时,必须先用 `+cells-set` 在第一行写入模板公式,再用 `--copy-to-range` 填充整列(如 `--copy-to-range "H2:H100"` 或 `--copy-to-range "H:H"`)。**禁止**对每一行单独调用 `+cells-set` 写入相同结构的公式——逐行写既慢又易错,而 `--copy-to-range` 会自动平移公式引用(C2=B2 → C3=B3)。 -11. **分组汇总必须用透视表**:当用户说"按XX统计YY"、"分组汇总"、"各部门/地区的数量/金额"、"汇总每个XX的YY"时,必须使用 `+pivot-{create|update|delete}` 创建透视表(推荐省略 sheet_id 自动新建子表)。禁止用 SUMIF/COUNTIF 公式或 本地脚本 代码替代——后者会导致统计结果覆盖原表数据。 +11. **分组汇总必须用透视表**:当用户说"按XX统计YY"、"分组汇总"、"各部门/地区的数量/金额"、"汇总每个XX的YY"时,必须使用 `+pivot-{create|update|delete}` 创建透视表(推荐省略 sheet_id 自动新建子表)。禁止用 SUMIF/COUNTIF 公式或本地脚本替代——后者会导致统计结果覆盖原表数据。 12. **续写/扩展已有内容时必须继承样式(高频致命错误)**:当用户要求"按已有格式续写"、"继续填充"、"复制区块"、"增加到第N周/月"等扩展任务时,**禁止只用 `+csv-get` 读值后只写值**。必须按以下顺序执行: - 用 `+cells-get` 读取源区块的 `cell_styles` 和 `border_styles` - - 用 `+sheet-info` 读取源区块的行高、合并单元格信息 + - 用 `+sheet-info --include row_heights,merges` 读取源区块的行高、合并单元格信息 - 写入时 cells 中同时携带 `value` + `cell_styles` + `border_styles` - 用 `+batch-update` 批量执行 `+cells-{merge|unmerge}`(复制合并)和 `+rows-resize / +cols-resize`(复制行高) - 只写值不写样式会导致新区块与源区块视觉完全不一致,这是最常见的致命错误 13. **"新增列"任务必须跑完整 checklist(高频致命错误)**:当用户要求"在表格中增加列/新增列/加几列"时,心智模型不是"只写表头 + 填公式"。**执行前必须完成以下 4 步 checklist,禁止跳步**: - - **Step 1 — 读原表 row1 的合并区域**:用 `+cells-get` 或 `+sheet-info` 读取 row1 的合并信息。**如果 row1 存在跨数据区的合并标题行(如 A1:F1 合并为一个大标题),新增 N 列后必须用 `+cells-{merge|unmerge}` 扩展合并范围到新列末**(如新增 3 列 → 合并改为 A1:I1)。否则新列在 row1 裸露在原标题区之外,视觉割裂。这一步被跳过会被 PM 判定"操作不完整"。 + - **Step 1 — 读原表 row1 的合并区域**:用 `+cells-get` 或 `+sheet-info --include merges` 读取 row1 的合并信息。**如果 row1 存在跨数据区的合并标题行(如 A1:F1 合并为一个大标题),新增 N 列后必须用 `+cells-{merge|unmerge}` 扩展合并范围到新列末**(如新增 3 列 → 合并改为 A1:I1)。否则新列在 row1 裸露在原标题区之外,视觉割裂——这一步被跳过会被判为"操作不完整"。 - **Step 2 — 读表头和原数据行的完整样式**:用 `+cells-get` 读原表头行(如 row2/row3)和数据行(row4)的 `cell_styles` **和 `border_styles`**,记录字体/加粗/对齐/**边框**/数字格式等。 - **Step 3 — 新列 cells 必须同时带 `cell_styles` + `border_styles`**:写新列时 cells 里的每个对象都要完整复制原表样式(包括边框),不能只传 font_size / alignment 就算"样式一致"。 - **Step 4 — 列宽对齐**:用 `+batch-update` 合并 `+rows-resize / +cols-resize` 把新列列宽与原数据列保持一致。 @@ -131,7 +120,7 @@ **路径 A:数据分析/清洗/可视化/大数据集/"完善 / 补齐 / 填空 / 修正所有 XX"** → 分批 `+csv-get` 把数据导出到本地文件,再用本地脚本(如 pandas)处理: ```bash # 分批导出(按 --range 行窗口翻页拼接到本地 data.csv,直到读完;单次返回量由 --max-chars 自动兜底,看 has_more / actual_range 续读) -lark-cli sheets +csv-get --url "$URL" --range "A1:Z500" > data.csv # 首窗口;后续 A501:Z1000 … 用 >> 追加 +lark-cli sheets +csv-get --url "$URL" --sheet-name "Sheet1" --range "A1:Z500" > data.csv # 首窗口;后续 A501:Z1000 … 用 >> 追加(sheet 定位必填) ``` ```python import pandas as pd @@ -164,7 +153,7 @@ print(df.head(10)) # 必做:横向——确认表头行 + **路径 C:需要公式/样式/批注** → 用 `+cells-get` -**路径 D:续写/扩展/完善已有内容(必须走此路径)** → 当用户要求"按已有格式续写"、"继续填充"、"复制区块"、"增加到第N周/月"、"帮我完善 XX"、"补齐 XX"、"填空"时,**必须**同时读取值和样式:先用 `+csv-get` 快速了解数据结构和范围,再用 `+cells-get` 读取源区块的 `cell_styles` + `border_styles`,并用 `+sheet-info` 读取行高和合并信息。**禁止跳过样式读取直接写入。** 这类任务默认要覆盖所有待补齐的行,**禁止只处理 `head(10)` 可见的行**——必须按 `df.info()` 的 non-null 数或 `current_region` 的实际行数确定写入范围。 +**路径 D:续写/扩展/完善已有内容(必须走此路径)** → 当用户要求"按已有格式续写"、"继续填充"、"复制区块"、"增加到第N周/月"、"帮我完善 XX"、"补齐 XX"、"填空"时,**必须**同时读取值和样式:先用 `+csv-get` 快速了解数据结构和范围,再用 `+cells-get` 读取源区块的 `cell_styles` + `border_styles`,并用 `+sheet-info --include row_heights,merges` 读取行高和合并信息。**禁止跳过样式读取直接写入。** 这类任务默认要覆盖所有待补齐的行,**禁止只处理 `head(10)` 可见的行**——必须按 `df.info()` 的 non-null 数或 `current_region` 的实际行数确定写入范围。 需要按关键字定位区域时使用 `lark-sheets-search-replace` 中的 `+cells-search`。 @@ -226,7 +215,7 @@ print(df.head(10)) # 必做:横向——确认表头行 + 7. 写入与修改 - 范围写入使用 `lark-sheets-write-cells`。`+cells-set` 的 `range` 必须落在当前已有行列范围内,`cells` 二维数组必须与 `range` 严格同维度;若是大块 CSV 纯值回写,优先用 `+csv-put`(直接传 CSV 文本,必要时自动扩容)。 - 如需在表尾追加数据,先插入行或列,再执行写入。 -- **多步写入优先用 `+batch-update`**(见硬性规则 7):将多个写入操作合并为一次 `+batch-update` 调用,减少调用轮次。尤其是多次 `+cells-{merge|unmerge}`、多次 `+rows-resize / +cols-resize`、多次 `+cells-set` 场景,必须合并。 +- **多步写入优先用 `+batch-update`**(见硬性规则 7):将多个写入操作合并为一次 `+batch-update` 原子调用。尤其是多次 `+cells-{merge|unmerge}`、多次 `+rows-resize / +cols-resize`、多次 `+cells-set` 场景,必须合并。 - **公式填充必须用 `--copy-to-range`(见硬性规则 10)**:先写一行模板公式,再用 `--copy-to-range` 一次填充整列或整区域。示例:在 H2 写 `=SUM(B2:G2)` 后,设 `--copy-to-range "H2:H100"` 即可填充 99 行。**禁止逐行调用 `+cells-set` 写入相同结构的公式。** - 对整行/整列统一设置值、公式、格式或批注时,优先写一个模板单元格,再用 `--copy-to-range` 扩展到 `1:1`、`J:J`、`A:A` 等目标范围。 - 当用户请求“宽一点 / 高一点 / 和其他行一样高 / 和其他列一样宽”时,先读取相邻可见行列的当前尺寸,再决定使用精确尺寸、`standard` 或 `auto`,不要随意猜测数值。 @@ -239,19 +228,8 @@ print(df.head(10)) # 必做:横向——确认表头行 + ## 公式策略 -### 优先使用公式,而非硬编码值 - -当可以用飞书表格公式表达计算逻辑时,必须写公式,而不是在 Python 中计算后写入静态结果。这样当源数据变化时,表格仍能自动重算。 -这适用于总计、平均值、增长率、占比、差值等常见计算。 - -### 飞书公式差异与限制 - -飞书表格公式与 Excel 公式基本相同,但需要特别注意以下差异: - -- 公式来自 Excel 或包含数组场景时,先读取 `lark-sheets-formula-translation` 完成改写,再生成公式。 -- 数组公式必须写成 `=ARRAYFORMULA(数组公式)` 语法。 -- 在公式字符串中,数据范围应使用飞书支持的语法,例如 `H:H`、`A2:B5`。禁止使用不符合飞书公式语法的写法,如 `H2:H`、`2:2` 等。 -- 飞书表格不支持部分 Excel / Google 专有函数(如 CUBE 系列、`GOOGLETRANSLATE`、`STOCKHISTORY`、`WEBSERVICE` 等),禁止主动使用;当用户明确要求使用这些函数时,应拒绝并说明飞书不支持。**完整的"飞书不支持函数"清单(含替代方案)见 `lark-sheets-formula-translation` 的「飞书不支持的函数」段——以那里为唯一权威清单。** +- **公式优先于硬编码**(同硬性规则 4):能用飞书公式表达的计算(总计 / 平均 / 增长率 / 占比 / 差值等)必须写公式,而非 Python 算出的静态值——源数据变化时才能自动重算。 +- **Excel 迁移 / 数组语义(ARRAYFORMULA)/ 飞书函数差异 / 不支持函数清单**:一律以 `lark-sheets-formula-translation` 为唯一权威。公式来自 Excel 或含数组(FILTER / MAP / XLOOKUP 等)场景,先读它完成改写再写入;公式字符串里的范围用飞书语法(`H:H`、`A2:B5`,禁止 `H2:H` / `2:2`)。 ### 向下填充与绝对引用 @@ -281,36 +259,26 @@ print(df.head(10)) # 必做:横向——确认表头行 + - 引用错误:验证所有单元格引用是否仍然有效 - 跨工作表引用:使用 `Sheet!A1` 风格引用 - 整行整列语义丢失:用户说“这行 / 这列 / 首行 / 整列”时,不要把操作范围截断为当前读取到的 `A1:U1`、`J1:J41` 等局部范围 -- **重复写入未使用 `--copy-to-range`(高频致命错误)**:整列公式、整列格式、首行样式、向下复制等场景,**必须**用模板单元格 + `--copy-to-range`,**禁止**逐行 `+cells-set`。这是最常见的导致轮次耗尽的错误 -- **重复调用 `+cells-{merge|unmerge}` / `+rows-resize / +cols-resize` 未合并为 `+batch-update`(高频致命错误)**:当需要合并/调整多个区域时,**必须**使用 `+batch-update` 将多个操作合并为单次调用。逐个调用会快速耗尽轮次上限(60R) +- **重复写入未使用 `--copy-to-range`(高频致命错误)**:整列公式、整列格式、首行样式、向下复制等场景,**必须**用模板单元格 + `--copy-to-range`,**禁止**逐行 `+cells-set`。逐行写既慢又易错,且不会自动平移公式引用 +- **重复调用 `+cells-{merge|unmerge}` / `+rows-resize / +cols-resize` 未合并为 `+batch-update`(高频致命错误)**:当需要合并/调整多个区域时,**必须**使用 `+batch-update` 将多个操作合并为单次原子调用。逐个调用慢且非原子(中途失败会留下半成品) - 多步骤请求漏做:若用户要求”先重命名,再新建”,两个动作都必须执行 - **表头定位不精确导致写入全偏(高频致命错误)**:不要假设表头在第 1 行。很多表格有标题行、说明行或空行,实际表头可能在第 2、3 行甚至更后。写入公式或数据前,必须先读取前几行确认表头行号和各列实际含义,再基于确认后的行列号构造写入 range - **参数冗余**:只需修改 10 个单元格时,不要把全表重写一遍;`+cells-set` 的 range 和 cells 应精确覆盖变更区域 - **表头理解路径不对**:要了解表格结构和字段含义时,先用 `+csv-get` 读取前 5-10 行查看表头与字段格式;大表需要全量统计才考虑分批导出后用本地脚本(如 `df.info()` + `df.head()`)分析。不要一行行用 `+cells-get` 逐行读取,也不要依赖 `+cells-search` 去”猜”字段名 - **隐藏行列导致定位偏移**:`+csv-get` 默认 `--skip-hidden=false`(返回完整数据含隐藏行列)。如需只看可见数据,显式设 `--skip-hidden=true`,但注意跳过隐藏行后返回数据的行序号与实际行号不对应 -- **写入前读取范围不充分**:涉及批量写入或修改时,必须先读取足够的数据范围。如果表格有 100 行而只读了 20 行,后续操作会漏掉剩余数据。使用 `+workbook-info` 获取行数后,根据实际行数决定读取范围。注意:了解表头和数据结构只需前几行,但批量操作前需要掌握完整数据 +- **写入前读取范围不充分**:批量写入 / 修改前必须读全数据范围(详见上方工作流第 4 步「写入前重新确认数据边界」),只读前 N 行就写会漏掉表尾 - **`+cells-search` 不是万能的**:用户说”汇总金额”是一个操作动作(求和),不是要搜索”汇总金额”这个文本。只有当确实需要定位某个文本值的位置时才用 `+cells-search` - **跨 sheet 对象**:图表、条件格式、透视表、浮动图片可能分布在多个子表中。操作前先用 `+workbook-info` 掌握全局,不要只看当前子表 - **--copy-to-range 不含行列尺寸**:`--copy-to-range` 复制的是值、公式和样式,不包含行高列宽设置。需要统一行列尺寸时,应另行调用 `lark-sheets-range-operations` 中的 `+rows-resize / +cols-resize` - **写入前先确保行列存在**:`+cells-set` 不会自动扩展表格。如果要写入的 range 超出当前行列范围,必须先用 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` 插入行列 -- **写入后保持原表样式(高频致命错误)**:原表已有边框线、背景色、行高、合并单元格等样式时,写入新数据后**必须**延续相同样式,不要只写值不管格式。具体做法:先用 `+cells-get` 读取源区域的样式(`cell_styles`、`border_styles`),写入时在 cells 中携带相同的样式字段;若源区域有合并单元格,用 `+cells-{merge|unmerge}` 对新区域做相同合并;若源区域有特殊行高,用 `+rows-resize / +cols-resize` 对新区域设置相同行高。详见下方"特殊场景 → 续写/复制已有区块格式" -- **CSV 行号按物理换行计数导致行号全错(高频致命错误)**:`+csv-get` 返回的 CSV 中,被双引号包裹的字段内换行符是**单元格内换行**,不是新行。例如 `"2026年3月2日\n星期一"` 是**一个单元格**,不是两行。计算行号时必须按逻辑记录计数。详见 `lark-sheets-read-data` 中的"CSV 行号计算规则" +- **写入后保持原表样式(高频致命错误)**:原表已有边框 / 背景色 / 行高 / 合并等样式时,写入新数据后**必须**延续,不要只写值不管格式(同硬性规则 12)。完整写法见 `lark-sheets-write-cells` 的「新增列 / 新增行的样式继承」 +- **CSV 行号按物理换行计数导致行号全错(高频致命错误)**:`+csv-get` 的 CSV 里被双引号包裹的字段内换行是**单元格内换行**、不是新行;行号一律按 `[row=N]` 前缀取,不要数 `\n`。详见 `lark-sheets-read-data` 的「CSV 行号计算规则」 ## 特殊场景 ### 续写/复制已有区块格式 -当用户要求"按照已有内容格式继续填充"(如"按前两周格式续写到第 20 周"、"把第一个模块复制 N 遍并改日期")时,必须按以下步骤执行: - -1. **用 `+cells-get` 读取源区块的样式**:`+csv-get` 只返回值,无法获取样式。必须用 `+cells-get` 读取源区块,获取每个单元格的 `cell_styles`(字体、背景色、对齐等)和 `border_styles`(边框) -2. **用 `+sheet-info` 读取布局信息**:获取源区块的行高、列宽、合并单元格信息 -3. **规划写入范围并扩行**:计算目标行数,若超出当前 sheet 边界,先用 `+dim-{insert|delete|hide|unhide|freeze|group|ungroup}` 插入行 -4. **带样式写入数据**:`+cells-set` 的 cells 中同时携带 `value` + `cell_styles` + `border_styles`。推荐使用"内容与样式分离写入"策略(见 `lark-sheets-write-cells`):先写值,再用模板单元格 + `--copy-to-range` 刷样式 -5. **合并单元格**:对标题行等需要合并的区域,用 `+batch-update` 批量调用 `+cells-{merge|unmerge}` -6. **设置行高**:用 `+batch-update` 批量调用 `+rows-resize / +cols-resize`,统一设置新区域的行高与源区块一致 -7. **回读校验**:用 `+csv-get` 校验值,用 `+cells-get` 抽查样式 - -> **反面案例**:只用 `+csv-get` 读值 → 只传 `{"value": ...}` 写入 → 新区块没有边框、没有合并、没有行高,与源区块视觉不一致。这是本场景最常见的错误。 +续写 / 复制已有区块("按前两周格式续写到第 20 周"、"把第一个模块复制 N 遍并改日期")的**完整写法见 `lark-sheets-write-cells` 的「新增列 / 新增行的样式继承」与「内容与样式分离写入」**;样式标准(斑马纹 / 配色 / 边框层级)见 `lark-sheets-visual-standards` 场景二。核心(同硬性规则 12):用 `+cells-get` 读源区块 `cell_styles` + `border_styles`、`+sheet-info --include row_heights,merges` 读行高 / 合并,写入时带齐样式,再用 `+batch-update` 复制合并与行高,最后回读校验。**禁止**只用 `+csv-get` 读值后只写 `{"value": ...}`——否则新区块缺边框 / 合并 / 行高,与源区块视觉不一致(本场景最常见错误)。 ### NLP 任务处理 @@ -329,8 +297,8 @@ print(df.head(10)) # 必做:横向——确认表头行 + - NLP 处理本身不应退化为纯规则代码;但可以使用代码做分批、行号映射、结果拼装和写回。 - 数据量大时**必须**分批处理,通常 30 行一批。每批处理完后立即写回表格,不要等全部处理完再一次性写入。 -- 为避免超时,NLP 处理通常不超过 300 行;超过时根据任务性质选择抽样或分批执行,并向用户明确处理范围。 -- 翻译、信息提取等任务,优先使用 `+batch-update` 将多批写入合并,减少调用轮次。 +- 为控制单次生成量,NLP 处理通常单批不超过 300 行;超过时根据任务性质选择抽样或分批执行,并向用户明确处理范围。 +- 翻译、信息提取等任务,优先使用 `+batch-update` 将多批写入合并为原子提交。 ### 格式处理优先公式 diff --git a/skills/lark-sheets/references/lark-sheets-filter-view.md b/skills/lark-sheets/references/lark-sheets-filter-view.md index a5cfeb1d7..c2a93331b 100644 --- a/skills/lark-sheets/references/lark-sheets-filter-view.md +++ b/skills/lark-sheets/references/lark-sheets-filter-view.md @@ -117,7 +117,7 @@ lark-cli sheets +filter-view-create --url "..." --sheet-id "$SID" \ ### `+filter-view-delete` -> ⚠️ 视图删除不可逆;视图不存在按幂等成功处理。先 `--dry-run` 看 view_id 确认。 +> ⚠️ 删除**已存在**的视图不可逆;目标 view_id **不存在**时按幂等成功返回(不报错)。先 `--dry-run` 看 view_id 确认。 ### Validate / DryRun / Execute 约束 diff --git a/skills/lark-sheets/references/lark-sheets-filter.md b/skills/lark-sheets/references/lark-sheets-filter.md index 19e612cb8..bd3aee05d 100644 --- a/skills/lark-sheets/references/lark-sheets-filter.md +++ b/skills/lark-sheets/references/lark-sheets-filter.md @@ -3,7 +3,7 @@ ## 真对象硬约束 + 数量校验 1. **真对象**:当用户要求"筛选 / 只看 / 仅保留 X"时,**必须**通过 `+filter-{create|update|delete}` 创建真实的筛选器对象。**禁止**用"删除不符合条件的行" / "新建子表只放符合条件的行" / 用 `+cells-set` 覆盖原表来代替——这些做法会让原数据丢失或不可恢复。 -2. **筛选数量必校**:执行筛选后**必须**回读,断言 `len(visible_rows) == expected_count`。`expected_count` 来自先用 本地脚本 在源数据上独立复现该筛选条件得到的结果数。两者不一致时禁止交付,需排查筛选条件 / 数据列类型问题。 +2. **筛选数量必校**:执行筛选后**必须**回读,断言 `len(visible_rows) == expected_count`。`expected_count` 来自先用本地脚本在源数据上独立复现该筛选条件得到的结果数。两者不一致时禁止交付,需排查筛选条件 / 数据列类型问题。 3. **混合文本列禁止字面比较**:筛选 key 是公式文本(如 `1000+200=1200`)或带单位的混合文本时,先在辅助列里抽出纯数值再筛选;不能直接用文本比较。 ## 使用场景 @@ -51,7 +51,7 @@ _公共四件套 · 系统:`--dry-run`_ | Flag | Type | 必填 | 说明 | | --- | --- | --- | --- | | `--range` | string | required | 筛选范围(A1 表示法,含表头行,如 `A1:F1000`);不要重复写入 `--properties` 中的 range 字段 | -| `--properties` | string + File + Stdin(复合 JSON) | optional | 筛选规则 JSON,含 `rules`(列级筛选规则数组,必填)和 `filtered_columns?`(激活列索引提示)。`range` 是独立 flag(不要再放此 JSON 里) | +| `--properties` | string + File + Stdin(复合 JSON) | optional | 筛选规则 JSON:`rules`(列级筛选规则数组)+ `filtered_columns?`(激活列索引提示)。`--properties` 整体可选——传它时 `rules` 不可为空;不传则只在 `--range` 上建立空筛选器(无列条件)。`range` 是独立 flag(不要再放此 JSON 里) | ### `+filter-update` diff --git a/skills/lark-sheets/references/lark-sheets-float-image.md b/skills/lark-sheets/references/lark-sheets-float-image.md index e358532bf..2475f9873 100644 --- a/skills/lark-sheets/references/lark-sheets-float-image.md +++ b/skills/lark-sheets/references/lark-sheets-float-image.md @@ -24,13 +24,8 @@ - **图片位置参数要精确**:锚点单元格的行列索引和偏移量决定了图片位置,设置不当会导致图片遮挡数据 - **创建后必须验证**:调用 `+float-image-list` 确认图片位置和大小正确 -reference_id 的映射规则: -- `image_uri`:`<|image|>:abcdef` 或者 `<|superscript|>:abcdef-<|image|>:abcdef` -- `float_image_id`:`<|float_image|>:abcdef` -其中 `abcdef` 为实际的对象 ID,占位符仅用于示意,不可直接使用。 - `image_uri` 与 `image_token` 是「指定图片资源」的两种等价方式(与 `+cells-set` 中 `embed-image` 的语义一致): -- `image_uri`:上传链路给到的图片 reference_id(如 `<|image|>:abcdef`),由系统自动转 fileToken +- `image_uri`:图片上传链路返回的 reference_id,由系统自动转 fileToken - `image_token`:图片 fileToken,常见来源是 `+float-image-list` 返回的 `image_token`(适合"换皮不换位置"等基于已有图片的复用场景) - create 时二者必须有其一;update 时**仅在需要替换图片本身时**传入新的 `image_uri` 或 `image_token`,不传则保留原图。 @@ -61,7 +56,7 @@ _公共四件套 · 系统:`--dry-run`_ | --- | --- | --- | --- | | `--image-name` | string | required | 图片名称,含扩展名(如 `logo.png`) | | `--image-token` | string | xor | 图片 file_token(与 `--image-uri` 二选一)。常见来源:`+float-image-list` 返回的 `image_token` | -| `--image-uri` | string | xor | 图片 reference_id(与 `--image-token` 二选一);形如 `<\|image\|>:abcdef` 这种带前缀的字符串 | +| `--image-uri` | string | xor | 图片 reference_id(与 `--image-token` 二选一);图片上传链路返回的 reference_id | | `--position-row` | int | required | 图片左上角所在行(0-based) | | `--position-col` | string | required | 图片左上角所在列(列字母,如 `A` / `B`) | | `--size-width` | int | required | 图片宽度(像素) | @@ -79,7 +74,7 @@ _公共四件套 · 系统:`--dry-run`_ | `--float-image-id` | string | required | 目标图片 id | | `--image-name` | string | optional | 图片名称,含扩展名(如 `logo.png`) | | `--image-token` | string | xor | 图片 file_token(与 `--image-uri` 二选一)。常见来源:`+float-image-list` 返回的 `image_token` | -| `--image-uri` | string | xor | 图片 reference_id(与 `--image-token` 二选一);形如 `<\|image\|>:abcdef` 这种带前缀的字符串 | +| `--image-uri` | string | xor | 图片 reference_id(与 `--image-token` 二选一);图片上传链路返回的 reference_id | | `--position-row` | int | optional | 图片左上角所在行(0-based) | | `--position-col` | string | optional | 图片左上角所在列(列字母,如 `A` / `B`) | | `--size-width` | int | optional | 图片宽度(像素) | @@ -116,9 +111,9 @@ lark-cli sheets +float-image-create --url "..." --sheet-id "$SID" \ --image-name "logo.png" --image-token "$TOKEN" \ --position-row 0 --position-col A --size-width 200 --size-height 150 -# 用 reference_id(部分租户直接引用) +# 用 reference_id(图片上传链路返回的 image reference_id;与 --image-token 二选一) lark-cli sheets +float-image-create --url "..." --sheet-id "$SID" \ - --image-name "logo.png" --image-uri "<|image|>:abcdef" \ + --image-name "logo.png" --image-uri "$IMAGE_URI" \ --position-row 2 --position-col B --size-width 300 --size-height 200 --z-index 1 ``` @@ -141,7 +136,7 @@ lark-cli sheets +float-image-update --url "..." --sheet-id "$SID" \ ### `+float-image-delete` ```bash -lark-cli sheets +float-image-delete --url "..." --float-image-id "$IMG_ID" --yes +lark-cli sheets +float-image-delete --url "..." --sheet-id "$SID" --float-image-id "$IMG_ID" --yes ``` ### Validate / DryRun / Execute 约束 diff --git a/skills/lark-sheets/references/lark-sheets-formula-translation.md b/skills/lark-sheets/references/lark-sheets-formula-translation.md index 50fe849a7..3c2249bfe 100644 --- a/skills/lark-sheets/references/lark-sheets-formula-translation.md +++ b/skills/lark-sheets/references/lark-sheets-formula-translation.md @@ -4,7 +4,7 @@ ## 翻译后必做:代码复现校验 -公式语法翻译完之后,**必须**用 本地脚本 在源数据上独立复现一份"等价计算结果"再写入。流程: +公式语法翻译完之后,**必须**用本地脚本在源数据上独立复现一份"等价计算结果"再写入。流程: 1. **挑 3-5 个代表性输入行**(首行 / 中段 / 末行 / 含空值 / 含异常格式各一) 2. **用 Python 复现 Excel 原公式的语义**(不是飞书译文的语义,而是用户原本想要的结果) diff --git a/skills/lark-sheets/references/lark-sheets-pivot-table.md b/skills/lark-sheets/references/lark-sheets-pivot-table.md index 3f59214be..dff2e3dfa 100644 --- a/skills/lark-sheets/references/lark-sheets-pivot-table.md +++ b/skills/lark-sheets/references/lark-sheets-pivot-table.md @@ -121,14 +121,26 @@ lark-cli sheets +pivot-list --url "..." --sheet-id "$SID" > 数据源 `--source` 必须从表头行开始;空行 / 汇总行会被当作数据参与聚合,需提前用 `+csv-get` 确认起止边界。`--source` 和 `--range` 是独立 flag(不要再放 `--properties`);`rows` / `columns` / `values` 等数组字段走 `--properties`。 > -> **落点 flag 三选一的决策(避免冲突)**: -> - **默认(推荐)**:`--target-sheet-id` / `--target-position` / `--range` 都不传 → 自动新建子表存放透视表产物。 -> - **放进指定的已有子表**:传 `--target-sheet-id <落点子表 id>` + 可选 `--target-position <子表内起点 cell,默认 A1>`。 -> - **`--range`** 只在不指定落点子表、想精确指定左上角 cell(映射到 `properties.range`)时用;与 `--target-position` 表达同一意图但落不同 wire 字段,**两者不要同时给**。一般用前两种即可,无需 `--range`。 +> **先理清 `+pivot-create` 上 5 个位置类入参(语义不同,别混)**: +> - 公共 `--sheet-id` / `--sheet-name`(**必填**,公共四件套):定位**操作所在工作表**(数据源 sheet 的上下文)。 +> - `--source`(**必填**):**源数据**区域,须自带 `Sheet!` 前缀(如 `Sheet1!A1:D100`)。 +> - `--target-sheet-id` / `--target-position` / `--range`:**产物落点**,按下面 3 种策略二选其一。 +> +> **落点 3 种策略(互斥,选其一)**: +> 1. **默认(强烈推荐)**:`--target-sheet-id` / `--target-position` / `--range` **都不传** → 服务端**自动新建子表**存放产物,绝不碰源数据。 +> 2. **放进指定的已有子表**:`--target-sheet-id <落点子表 id>`,可选 `--target-position <子表内起点 cell,默认 A1>`(这两个是**配套**使用,不是互斥)。 +> 3. **`--range`**:仅在不指定落点子表、想精确指定左上角 cell(映射到 `properties.range`)时用。⚠️ **`--range` 把产物落在公共 `--sheet-id` 指向的那张 sheet 上**——若 `--sheet-id` 就是源数据 sheet,产物会盖在源数据旁/上、**可能覆盖数据**。它与 `--target-position` 表达同一意图但落不同 wire 字段,**两者不要同时给**。 +> +> 一般用策略 1(默认新建子表)即可,无需 `--range`/`--target-*`。 ```bash -lark-cli sheets +pivot-create --url "..." --sheet-id "$SRC_SID" \ - --source "Sheet1!A1:D100" --range "F1" --properties @pivot.json +# 策略 1(推荐):只给必填的公共 sheet 定位 + 源数据,不给落点 flag → 自动新建子表,零覆盖风险 +lark-cli sheets +pivot-create --url "..." --sheet-id "$SID" \ + --source "Sheet1!A1:D100" --properties @pivot.json + +# 策略 2:落进指定的已有目标子表(不会碰源数据) +lark-cli sheets +pivot-create --url "..." --sheet-id "$SID" \ + --source "Sheet1!A1:D100" --target-sheet-id "$DEST_SID" --target-position "A1" --properties @pivot.json ``` ### `+pivot-update` @@ -138,7 +150,7 @@ lark-cli sheets +pivot-create --url "..." --sheet-id "$SRC_SID" \ ### `+pivot-delete` ```bash -lark-cli sheets +pivot-delete --url "..." --pivot-table-id "$PID" --yes +lark-cli sheets +pivot-delete --url "..." --sheet-id "$SID" --pivot-table-id "$PID" --yes ``` ### Validate / DryRun / Execute 约束 diff --git a/skills/lark-sheets/references/lark-sheets-range-operations.md b/skills/lark-sheets/references/lark-sheets-range-operations.md index 77527029b..87c26b39d 100644 --- a/skills/lark-sheets/references/lark-sheets-range-operations.md +++ b/skills/lark-sheets/references/lark-sheets-range-operations.md @@ -4,14 +4,14 @@ `+cells-clear`、`+cells-{merge|unmerge}`、`+range-{move|copy|fill|sort}`(移动 / 复制 / 排序 / 自动填充)都会让既有引用关系发生偏移或失效。**操作前必须**先确认以下两点;否则禁止执行: -1. **打印当前合并单元格 + 公式引用 + 数据验证范围**:用 `+sheet-info` + `+cells-get` 抽样目标区域和它周边的公式 / 透视表 / 图表 / 条件格式 / 筛选器的数据源;评估操作后这些引用是否仍指向正确数据。 +1. **打印当前合并单元格 + 公式引用 + 数据验证范围**:用 `+sheet-info --include merges` + `+cells-get` 抽样目标区域和它周边的公式 / 透视表 / 图表 / 条件格式 / 筛选器的数据源;评估操作后这些引用是否仍指向正确数据。 2. **`+cells-clear` 不得侵入用户授权范围之外**:清除范围只能是用户明示要清的区域;不要顺手清除"看起来没用"的相邻单元格。 排序场景的存储类型识别 + 辅助列抽数值的细则见下方「sort 操作前必读」章节。 ## 使用场景 -写入。对指定区域执行结构性操作。本 Skill 包含四个工具: +写入。对指定区域执行结构性操作。本 reference 覆盖 9 个 shortcut,按 4 类用途组织: | 操作需求 | 使用工具 | 说明 | |---------|---------|------| @@ -51,7 +51,7 @@ **⚠️ 批量操作必须用 `+batch-update`**: -当需要对**多个**不同区域执行 `+cells-{merge|unmerge}`(merge)或 `+rows-resize / +cols-resize` 时,**禁止逐个调用**,必须使用 `+batch-update`(参见 `lark-sheets-batch-update`)将所有操作合并为一次请求。逐个调用会快速耗尽工具调用轮次上限。 +当需要对**多个**不同区域执行 `+cells-{merge|unmerge}`(merge)或 `+rows-resize / +cols-resize` 时,**禁止逐个调用**,必须使用 `+batch-update`(参见 `lark-sheets-batch-update`)将所有操作合并为一次原子请求。逐个调用慢且非原子。 **例外**:`+cells-unmerge` 原生支持对覆盖多个合并区域的大 range 一次性取消,应直接单次调用,**不要**拆进 `+batch-update`。 diff --git a/skills/lark-sheets/references/lark-sheets-read-data.md b/skills/lark-sheets/references/lark-sheets-read-data.md index 71a754e12..e7cb0a5e4 100644 --- a/skills/lark-sheets/references/lark-sheets-read-data.md +++ b/skills/lark-sheets/references/lark-sheets-read-data.md @@ -124,8 +124,8 @@ _公共四件套 · 系统:`--dry-run`_ 示例: ```bash -# 简单读 -lark-cli sheets +csv-get --url "https://example.feishu.cn/sheets/shtXXX" --range "Sheet1!A1:F30" +# 简单读(sheet 定位必填:--sheet-name 或 --sheet-id 必给一个;range 的 Sheet1! 前缀不能替代它) +lark-cli sheets +csv-get --url "https://example.feishu.cn/sheets/shtXXX" --sheet-name "Sheet1" --range "A1:F30" # 用 sheet-name 模糊定位(运行时框架会先解析到 sheet-id) lark-cli sheets +csv-get --spreadsheet-token shtXXX --sheet-name "销售明细" --range "A1:F30" @@ -143,9 +143,9 @@ lark-cli sheets +csv-get --spreadsheet-token shtXXX --sheet-name "销售明细" 示例: ```bash -# 读 A1:F10 的公式 + 样式 -lark-cli sheets +cells-get --url "https://example.feishu.cn/sheets/shtXXX" \ - --range "Sheet1!A1:F10" --include formula,style +# 读 A1:F10 的公式 + 样式(sheet 定位必填) +lark-cli sheets +cells-get --url "https://example.feishu.cn/sheets/shtXXX" --sheet-name "Sheet1" \ + --range "A1:F10" --include formula,style ``` > ⚠️ 调用方在 `cells[i][j]` 中**不能**用下标推真实行列:必须读 `ranges[n].row_indices[i]` / `ranges[n].col_indices[j]`。 diff --git a/skills/lark-sheets/references/lark-sheets-visual-standards.md b/skills/lark-sheets/references/lark-sheets-visual-standards.md index df00c7679..03f59c586 100644 --- a/skills/lark-sheets/references/lark-sheets-visual-standards.md +++ b/skills/lark-sheets/references/lark-sheets-visual-standards.md @@ -127,15 +127,14 @@ #### 2A. 继续补充行/列(数据性质与已有内容一致) -**核心规则**:采样紧邻 2 行样式 → 延续 Zebra Stripes 奇偶性 → 写入时原样应用 `cell_styles` + `border_styles`。 +**核心规则**:采样紧邻 2 行 → 判断并延续 Zebra Stripes 奇偶性 → 按 write-cells 的继承清单带齐样式写入。 -**关键样式要点**: +**斑马纹延续要点**(本节只管"奇偶判断"这一标准,"带哪些样式字段写入"的机制见下方指针): - 至少读 2 行(末行 + 倒数第二行)才能判断是否有斑马纹交替色 - 若倒数两行背景色不同(如 #FFFFFF 与 #F3F4F6),新行按奇偶延续,不要固定一个色 -- `border_styles` 最易遗漏(四边都要复制),否则新行会缺框线 -> 具体采样调用(用 `+cells-get` 读源行 `cell_styles` + `border_styles`、`+sheet-info` 读行高合并)见 `lark-sheets-write-cells` 的「新增列 / 新增行的样式继承」章节。 +> 具体继承哪些字段、怎么采样与写入(`+cells-get` 读源行 `cell_styles` + `border_styles`、`+sheet-info --include row_heights,merges` 读行高合并、带齐 6 类样式写入)见 `lark-sheets-write-cells` 的「新增列 / 新增行的样式继承」章节——`border_styles` 四边最易遗漏,以那里为准。 #### 2B. 基于模板区域的修改(copy 保留所有格式) diff --git a/skills/lark-sheets/references/lark-sheets-workbook.md b/skills/lark-sheets/references/lark-sheets-workbook.md index a5ca2007e..3406212cc 100644 --- a/skills/lark-sheets/references/lark-sheets-workbook.md +++ b/skills/lark-sheets/references/lark-sheets-workbook.md @@ -133,7 +133,7 @@ _公共:URL/token(无 sheet 定位) · 系统:`--dry-run`_ | Flag | Type | 必填 | 说明 | | --- | --- | --- | --- | | `--file-extension` | string | optional | 导出文件格式;`csv` 模式必须配 `--sheet-id`(可选值:`xlsx` / `csv`)(默认 `xlsx`) | -| `--sheet-id` | string | optional | 仅 csv 模式必填:指定要导出的 sheet reference_id | +| `--sheet-id` | string | optional | 仅 csv 模式必填:指定要导出哪张 sheet 为 CSV。这是 `+workbook-export` 专有 flag,与公共四件套的 sheet 定位无关(本 shortcut 不接受公共 sheet 定位) | | `--output-path` | string | optional | 本地保存路径;省略时只触发导出不下载 | ## Examples diff --git a/skills/lark-sheets/references/lark-sheets-write-cells.md b/skills/lark-sheets/references/lark-sheets-write-cells.md index 935932f65..567a2de66 100644 --- a/skills/lark-sheets/references/lark-sheets-write-cells.md +++ b/skills/lark-sheets/references/lark-sheets-write-cells.md @@ -4,7 +4,7 @@ 1. **明确写入边界**:写入前必须能回答"目标 range 的起止行列号是多少?是否落在用户授权范围内?"。除用户明示要修改的区域外,禁止扩张到原数据列以外或新建 Sheet。 2. **完整性断言**:批量写入前先把"预期写入条数"硬编码到代码里(如要填 106 条翻译 → `expected = 106`),写完后回读断言 `actual == expected`。少于预期就继续写,禁止交付半成品。 -3. **回读抽样校验**:写完关键值 / 公式后,用 `+csv-get` 或 `+cells-get` 重新读取写入区域,至少抽样 3-5 个代表性单元格(首 / 中 / 末),核对值与预期一致(与 本地脚本 计算的预期值对照)。公式特定的"先验证模板再 --copy-to-range / 修完再读回"细则见下方相关章节。 +3. **回读抽样校验**:写完关键值 / 公式后,用 `+csv-get` 或 `+cells-get` 重新读取写入区域,至少抽样 3-5 个代表性单元格(首 / 中 / 末),核对值与预期一致(与本地脚本计算的预期值对照)。公式特定的"先验证模板再 --copy-to-range / 修完再读回"细则见下方相关章节。 ## 新增列 / 新增行的样式继承(防止视觉风格不一致) @@ -58,7 +58,7 @@ - 用户说”这列 / 整列 / 这行 / 首行 / 向下复制”时,**必须**使用模板单元格 + `--copy-to-range` - 多区域写入相同格式/公式结构时,优先写一个模板,再用 `--copy-to-range` 复制到所有目标区域 -⚠️ **逐行写入公式是最常见的致命错误**:对每一行单独调用 `+cells-set` 写入公式(如调用 26 次),会快速耗尽轮次上限导致操作不完整。正确做法是 1 次模板写入 + 1 次 `--copy-to-range` = 2 次调用完成。 +⚠️ **逐行写入公式是常见低效写法**:对每一行单独调用 `+cells-set` 写公式(如 26 次)既慢又易错,且不会自动平移公式引用。正确做法是 1 次模板写入 + 1 次 `--copy-to-range`(公式引用自动平移)。 💡 **写入公式前先按迁移规则改写**:如果公式来自 Excel 或包含数组场景,先读取并遵循 `lark-sheets-formula-translation` 的规则完成改写,再把最终公式写入 `formula` 字段。 @@ -73,7 +73,7 @@ Step 2: `+cells-set` — range="A2", cells 含 value + cell_styles + border_styl ``` 这比在 99 个单元格中都重复写样式 JSON 高效得多。 -💡 **大批量数据分批写入(推荐)**:当需要写入大量行(如几十行以上)时,不要试图在一次调用中生成全部 `cells` 数据——`cells` 数组过大会导致模型生成内容过长而超时。应将数据拆分为多批,每批 20-50 行,分多次调用 `+cells-set` 逐批生成并写入(如先写 `A2:D21`,再写 `A22:D41`,依此类推)。每次调用只需生成当前批次的数据,控制单次生成量,避免超时。 +💡 **大批量数据分批写入(推荐)**:当需要写入大量行(如几十行以上)时,不要试图在一次调用中生成全部 `cells` 数据——`cells` 数组过大会让单次生成的内容过长,容易出错或被截断。应将数据拆分为多批,每批 20-50 行,分多次调用 `+cells-set` 逐批生成并写入(如先写 `A2:D21`,再写 `A22:D41`,依此类推)。每次只生成当前批次的数据,控制单次生成量。 注意: @@ -93,7 +93,7 @@ Step 2: `+cells-set` — range="A2", cells 含 value + cell_styles + border_styl 3. **`--copy-to-range` 扩展前先验证模板**:模板单元格公式自己都算错,`--copy-to-range` 复制到 100 行就是 100 个错误 4. **去重 / 筛选函数**:飞书**支持** `UNIQUE` / `FILTER` / `SPLIT`(原生数组函数,详见 `lark-sheets-formula-translation`),可直接用;`DISTINCT` 不是飞书函数,去重用 `UNIQUE`。大数据量去重 / 分组也可用透视表(`+pivot-{create|update|delete}`,值字段聚合方式选 count) 5. **循环引用预检(高频致命错误)**:写聚合公式(SUM / AVERAGE / COUNT 等)前必须明确**引用范围不包含目标单元格自身或其传递依赖**。典型反例:在 C3 写 `=SUMIF(B:B,LEFT(B3,9)&"*",C:C)`,B 列匹配 B3 前 9 位时 C3 自己也命中,导致 C3 自引用 → `~CIRCULAR~REF~`。修法:用辅助列 / 显式排除自身(`SUMIFS(C:C, B:B, ..., A:A, "<>"&A3)`)/ 缩小范围避开自己 -6. **REGEX 模式覆盖率验证**:公式里的 `REGEXEXTRACT` / `REGEXMATCH` / `REGEXREPLACE` 等正则模式落地前必须用 本地脚本 在源列上跑一遍命中率统计(`df[col].str.contains(pattern).mean()`);命中率 < 100% 时必须扩展 pattern 或加多分支(IFS / 多个 IFERROR 串联)兜底,**禁止**只覆盖样本前 N 行就交付(典型反例:用 `REGEXEXTRACT(D5,"长(\d+)")` 只匹配带"长"前缀的尺寸文本,对"宽×高"、"×"、"*"等其它分隔符直接漏匹配) +6. **REGEX 模式覆盖率验证**:公式里的 `REGEXEXTRACT` / `REGEXMATCH` / `REGEXREPLACE` 等正则模式落地前必须用本地脚本在源列上跑一遍命中率统计(`df[col].str.contains(pattern).mean()`);命中率 < 100% 时必须扩展 pattern 或加多分支(IFS / 多个 IFERROR 串联)兜底,**禁止**只覆盖样本前 N 行就交付(典型反例:用 `REGEXEXTRACT(D5,"长(\d+)")` 只匹配带"长"前缀的尺寸文本,对"宽×高"、"×"、"*"等其它分隔符直接漏匹配) 7. **公式范围与用户指令字面对齐**:用户说"对 F 至 L 列求和"就必须写 `SUM(F2:L2)` 或 `F2+G2+H2+I2+J2+K2+L2`,**不能漏列、多列、错列**。写完用 `+cells-get` 拿回 `formula` 字符串,与用户原话逐字对照(参与求和的列名一致 / 起止列号一致 / 运算符一致),不一致就是违规 ⚠️ **收到 `formula_errors` 反馈后不要只打补丁(高频致命错误)**:`+cells-set` 返回值里若出现 `formula_errors: [{cell, formula, error_type, detail}]`,说明某些 cell 公式编译失败(`error_type=compile_failed` 通常是函数语法错如 `SPLIT(x)[1]` 的下标取值飞书不支持(SPLIT 本身支持,取第 N 项用 `INDEX(SPLIT(...),N)`);`non_formula` 是 `=` 开头但解析不通过)。此时**禁止只聚焦修报错点的局部语法**(如仅把 `[1]` 换成 `INDEX(..,1)`),必须: