@amaster.ai/pi-lark 0.1.2-beta.73 → 0.1.2-beta.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +4 -4
  2. package/skills/lark-apps/SKILL.md +1 -0
  3. package/skills/lark-apps/references/lark-apps-export.md +62 -0
  4. package/skills/lark-base/SKILL.md +3 -3
  5. package/skills/lark-base/references/lark-base-dashboard-block-config.md +20 -2
  6. package/skills/lark-base/references/lark-base-view.md +109 -0
  7. package/skills/lark-sheets/SKILL.md +58 -173
  8. package/skills/lark-sheets/references/lark-sheets-batch-update.md +10 -10
  9. package/skills/lark-sheets/references/lark-sheets-chart.md +5 -5
  10. package/skills/lark-sheets/references/lark-sheets-conditional-format.md +4 -4
  11. package/skills/lark-sheets/references/lark-sheets-filter-view.md +1 -1
  12. package/skills/lark-sheets/references/lark-sheets-filter.md +2 -2
  13. package/skills/lark-sheets/references/lark-sheets-float-image.md +2 -2
  14. package/skills/lark-sheets/references/lark-sheets-formula-translation.md +90 -4
  15. package/skills/lark-sheets/references/lark-sheets-formula-verify.md +49 -13
  16. package/skills/lark-sheets/references/lark-sheets-pivot-table.md +13 -13
  17. package/skills/lark-sheets/references/lark-sheets-range-operations.md +12 -9
  18. package/skills/lark-sheets/references/lark-sheets-read-data.md +14 -12
  19. package/skills/lark-sheets/references/lark-sheets-search-replace.md +3 -3
  20. package/skills/lark-sheets/references/lark-sheets-sheet-structure.md +8 -4
  21. package/skills/lark-sheets/references/lark-sheets-sparkline.md +2 -2
  22. package/skills/lark-sheets/references/lark-sheets-styles-put.md +2 -2
  23. package/skills/lark-sheets/references/lark-sheets-visual-standards.md +16 -16
  24. package/skills/lark-sheets/references/lark-sheets-workbook.md +22 -7
  25. package/skills/lark-sheets/references/lark-sheets-write-cells.md +66 -57
  26. package/skills/lark-sheets/scripts/lark_chart_quality_check.py +42 -26
  27. package/skills/lark-sheets/scripts/lark_chart_size_advisor.py +2 -1
  28. package/skills/lark-sheets/scripts/lark_inspect_workbook.py +37 -9
  29. package/skills/lark-sheets/scripts/lark_sheet_read_cli.py +53 -0
  30. package/skills/lark-sheets/scripts/{sheets_df.py → lark_sheets_df.py} +1 -1
  31. package/skills/lark-slides/SKILL.md +11 -18
  32. package/skills/lark-slides/references/cli/lark-slides-create.md +3 -3
  33. package/skills/lark-slides/references/cli/lark-slides-delete-slide.md +1 -1
  34. package/skills/lark-slides/references/cli/lark-slides-history.md +1 -8
  35. package/skills/lark-slides/references/cli/lark-slides-media-upload.md +5 -10
  36. package/skills/lark-slides/references/cli/lark-slides-replace-slide.md +14 -15
  37. package/skills/lark-slides/references/cli/lark-slides-update-slide.md +2 -2
  38. package/skills/lark-slides/references/cli/lark-slides-xml-presentation-slide-get.md +3 -108
  39. package/skills/lark-slides/references/cli/lark-slides-xml-presentation-slide-replace.md +6 -183
  40. package/skills/lark-slides/references/cli/lark-slides-xml-presentations-get.md +26 -143
  41. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md +3 -3
  42. package/skills/lark-slides/references/lark-slides-xml-presentation-slide-replace.md +2 -2
  43. package/skills/lark-slides/references/lark-slides-xml-presentations-get.md +2 -2
  44. package/skills/lark-slides/references/workflow/error-handling.md +3 -3
  45. package/skills/lark-slides/references/workflow/slides-editing.md +10 -11
  46. package/skills/lark-sheets/references/lark-sheets-legacy-command-migration.md +0 -152
@@ -1,7 +1,7 @@
1
1
  # 飞书表格公式生成规则
2
2
 
3
3
  > **本文定位**:飞书公式正确性的**唯一权威**——书写任何飞书公式、或把 Excel 公式迁移到飞书前,先读本文。涵盖公式书写约定(绝对引用、范围语法)、投影 vs spill、`ARRAYFORMULA` / 数组语义与逐行填充、高风险引用函数、日期差、不支持函数清单。
4
- > **边界**:本文只讲"公式怎么写对";公式**怎么写入表格**(`+cells-set` / 模板单元格 + `--copy-to-range` / 容错回读)见 `lark-sheets-write-cells`。公式写入完成后可用 `lark-sheets-formula-verify` 做诊断;不要把"翻译对了"误当成"结果一定正确"。本文不含 shortcut,通用编辑准则见主 SKILL.md「飞书表格编辑准则」。
4
+ > **边界**:本文只讲"公式怎么写对";公式**怎么写入表格**(`+cells-set` / 模板单元格 + `--copy-to-range` / 容错回读)见 `references/lark-sheets-write-cells.md`。公式写入完成后必须用 `references/lark-sheets-formula-verify.md` 对本次公式范围逐段诊断并回读关键公式;不要把"翻译对了"误当成"结果一定正确"。本文不含 shortcut,通用编辑准则见主 SKILL.md「飞书表格编辑准则」。
5
5
 
6
6
  **核心原则一:飞书不像 Excel 365 那样默认 spill(溢出展开)。** 某个参数要求单值、实际传入的却是区域时,飞书默认取"投影"(按公式所在行/列取对应的那一个值);只有当求值处于**数组公式上下文内部**——最外层套了 `ARRAYFORMULA`,或公式里已有原生数组函数(`FILTER` / `XLOOKUP` / `SORT` 等,见下方清单)——才逐项展开。`ARRAYFORMULA` 与"逐行标量公式 + `--copy-to-range` 填充"导出后都保真,按需要选:前者一条公式覆盖整片、写起来短;后者每格是独立公式,导出后在 Excel 里能单格编辑。
7
7
 
@@ -19,6 +19,16 @@
19
19
  - **公式字符串用飞书范围语法**:写 `H:H`、`A2:B5`,**禁止** `H2:H` / `2:2`。要在公式里引用整行,用显式范围(如 `$A2:$Z2`)替代禁用的 `2:2`。这与 CLI 工具参数(如 `--range` / `--copy-to-range`)的 A1 表示法写法不同:参数侧合法的 `D3:D`、`1:1`、`3:6` 在公式串里反而非法。**公式串 ≠ CLI 参数**,两套规则别互相照搬,混用会导致调用失败或公式报错。
20
20
  - **产物要导出 xlsx 交付时优先 Excel 兼容函数**:同一计算能用 Excel 兼容函数(SUMIFS / TEXT / MID / FIND 等)表达就不用飞书特有函数(MAP / REGEXEXTRACT / ARRAYFORMULA 等)——特有函数在导出后的 xlsx 里可能无法重算;确需使用时,导出后核对重算正常再交付。
21
21
 
22
+ ## 业务语义契约(复杂统计公式写前必做)
23
+
24
+ 公式无错误码不等于业务逻辑正确。写入前把用户要求整理成一张短契约并逐项核对:
25
+
26
+ 1. **字段**:用表头 + 3–5 行真实值确认“姓名/工号、开始/结束、秒/分钟”等列语义,禁止只凭列字母或列名猜测。
27
+ 2. **阈值**:中文“以上 / 至少 / 不低于”用 `>=`,“超过 / 大于”用 `>`;“以下 / 至多 / 不高于”用 `<=`。阈值恰好相等的记录必须作为哨兵。
28
+ 3. **单位与时区**:显式记录秒↔分钟、百分比↔小数、Unix 秒/毫秒与 UTC→本地时区转换;日期由时间戳计算时先用一条已知记录手算。
29
+ 4. **完整范围**:公式范围覆盖源数据真实首末行,不能把探结构的前 N 行样本直接当计算范围;回读/落盘结果出现 `truncated` / `complete:false` 时先续读。
30
+ 5. **业务哨兵**:写前用本地脚本或手算得到至少一条可核预期;写后同时核首、中、末、空值、阈值边界和该预期。`formula-verify success` 只证明没有公式错误码,不能替代这些结果断言。
31
+
22
32
  ## 翻译后建议:代码复现校验
23
33
 
24
34
  公式语法翻译完之后,建议用本地脚本在源数据上独立复现一份"等价计算结果"再写入。流程:
@@ -34,12 +44,88 @@
34
44
 
35
45
  本文解决的是"公式怎么写对",不是"写进表里后一定能零错误运行"。因此:
36
46
 
37
- 1. 按本文完成公式改写后,用 `lark-sheets-write-cells` / `lark-sheets-batch-update` 把公式真实写入表格。
38
- 2. 公式一旦落表,可进入 `lark-sheets-formula-verify` 做诊断。
39
- 3. `+formula-verify` 的 `errors_found` / `partial` 是风险信号;关键输出区优先修复,非关键区可在交付说明记录。
47
+ 1. 按本文完成公式改写后,用 `references/lark-sheets-write-cells.md` / `references/lark-sheets-batch-update.md` 把公式真实写入表格。
48
+ 2. 公式一旦落表,必须对本次新增 / 修改的公式范围逐段运行 `+formula-verify --exit-on-error`;关键公式区还要回读首、中、末及汇总行的 `formula`。
49
+ 3. 每段 `status='success'` 后才结束公式任务;`errors_found` 继续修复,`partial` 缩小 `--range` 或按 sheet 拆分续扫,不能用说明替代完整验证;AI 公式不套这条 success 收敛,按下方「AI 公式」的全区间一次异步状态检查规则交付。
40
50
 
41
51
  **静态值改公式("让统计表跟随源数据变化"类任务)额外一步**:改写前先快照原静态值,公式写完后逐格与快照 diff。不一致时先尝试口径变体(`>` / `>=`、取整方式、匹配列)逼近原值;仍不一致不算失败——原静态值可能对应旧数据或含未声明口径——但必须在交付说明中给出 diff 表与所用口径的解释,禁止不声明差异直接交付。
42
52
 
53
+ **首次写计算结果时默认写公式**:在已有表上做统计、汇总、排名、分类计算等——无论源数据是已有单元格还是新读取的数据——默认把计算结果写成引用源数据的公式,不要用 Python 在本地算好数值再硬编码写入。公式优先原则的例外:外部抓取数据、永不变化的常量、循环引用。
54
+
55
+ ## AI 公式(`AI` 函数)
56
+
57
+ 飞书表格提供一个统一的 **`AI` 公式**:用自然语言描述需求,AI 返回文本结果。AI 公式的**写入方式与普通公式完全一致**(复用 `references/lark-sheets-write-cells.md` 的 `+cells-set` / `set_cell_range`,无需特殊接口),只是计算是**异步**的——写入后要等 AI 算完才有结果。
58
+
59
+ **AI 公式几乎必然含逗号 + 双引号(如 `=AI("翻译成中文", E2)`),默认走 `+cells-set` 的 JSON `formula` 字段,不要走 `+csv-put`**:`+csv-put` 会按逗号把公式拆列、写坏(详见 `references/lark-sheets-write-cells.md`)。`+cells-set` 里公式内部的双引号写成 `\"`。整列填充用模板 + `--copy-to-range`:
60
+
61
+ ```bash
62
+ # 种子格写一条 AI 公式(内部引号用 \" 转义),再向下铺满整列
63
+ lark-cli sheets +cells-set --url <表URL> --sheet-name <子表名> \
64
+ --range D2 --cells '[[{"formula":"=AI(\"翻译成中文\", E2)"}]]' \
65
+ --copy-to-range "D2:D107"
66
+ # 写完先对种子格 D2 做一次 +cells-get --include formula 核对文本,再用 --ai-only 校验整个写入区间;禁止用 +cells-get 轮询计算结果
67
+ lark-cli sheets +formula-verify --url <表URL> --sheet-name <子表名> --range D2:D107 --ai-only
68
+ ```
69
+
70
+ **校验纪律**:AI 公式计算是异步的。写完先做**一次性公式文本核对**(对种子格 / 首格做**一次** `+cells-get --include formula`,确认落进去的确实是 `=AI(...)` 而非 `#ERROR` 或残缺字面量)——这一步是**必经**的;被禁止的只是用 `+cells-get` / `+csv-get` 反复**轮询计算结果**。计算状态的**第一校验入口必须是 `+formula-verify --ai-only`**,`--range` 给**整个写入区间**(只读、成本低,不要抽样);注意 `--range` 只透传给后端,AI-only 汇总不保证按它收窄,**认返回里的单元格定位、不认总数**。交付判据(机读):`ai_formula_failed_count == 0`,`failed` / `unsupported` 先修;满足后即使仍有 `ai_formula_pending_count > 0` 也可交付,并告知用户后台仍在计算。若文本核对暴露出 `#ERROR` / 残缺字面量(半截括号 / 全角括号),那是公式串在写入层被转义写坏了、不是 AI 失败,回到 `+cells-set` 用 `\"` 重写(详见 `references/lark-sheets-formula-verify.md`)。
71
+
72
+ ### 语法
73
+
74
+ ```
75
+ =AI(prompt)
76
+ =AI(prompt, range)
77
+ =AI(part1, part2, ...)
78
+ ```
79
+
80
+ - `prompt`:提示词,说明要 AI 做什么(可以是字符串常量,也可以引用单元格)。
81
+ - `range`:可选,交给 AI 处理的输入数据。可以是单个单元格(如 `A2`),也可以是一段单元格(如整行 `A2:G2` 或几列 `A2:C2`)——这段单元格会作为**这一次计算的输入上下文**一并喂给 AI,公式返回**一个**结果。具体写法见下方「常见用途」。
82
+ - **多参数拼接**:`AI` 接受多个参数,会按顺序把字符串常量与单元格 / 区域引用拼成一段完整提示词。可用来把散落在不同位置的值组进一句话,例如 `=AI("结合", A2, "和", A4, "的描述,总结3个关键词")`。
83
+
84
+ ### 常见用途(同一个函数,靠提示词区分)
85
+
86
+ `range` 既可以是单个单元格,也可以引用整行 / 多列作为一次计算的输入上下文;也可以用多个参数把不同位置的值拼进同一句提示词:
87
+
88
+ | 场景 | 示例 |
89
+ |---|---|
90
+ | 翻译 | `=AI("翻译成日语", A2)` |
91
+ | 情感分析 | `=AI("判断客户情绪,只返回 Positive、Neutral、Negative", A2)` |
92
+ | 分类打标签 | `=AI("判断这封邮件是不是垃圾邮件", D2)`;结合多列辅助信息判断:`=AI("把餐厅归类到它所属的纽约市行政区,可参考街区信息", A2:C2)` |
93
+ | 信息提取 | `=AI("提取邮箱", A2)` / `=AI("提取手机号", A2)` |
94
+ | 总结 | `=AI("为这位客户的反馈写一句话总结", A2:D2)`;`=AI("用要点列出这段书籍摘要的主要主题", D2)` |
95
+ | 多值拼接 | `=AI("结合", A2, "和", A4, "的描述,总结3个关键词")` |
96
+ | 润色改写 | `=AI("改写得更正式", A2)` |
97
+ | 生成文案 | `=AI("用 10 个字以内为活动生成一句宣传语", A2)`;引用整行回应具体内容:`=AI("给评审写一封邮件,针对评审意见中的具体条目逐条回应", A2:G2)`;`=AI("根据这段岗位职责摘要,为该职位生成一组关键词", A2:C2)` |
98
+ | 数据清洗 / 标准化 | `=AI("统一公司名称写法", A2)` |
99
+ | 关键词提取 | `=AI("提取 5 个关键词,用逗号分隔", A2)` |
100
+
101
+ ### 提示词最佳实践(写对提示词是结果稳定的关键)
102
+
103
+ AI 公式的质量高度依赖提示词。推荐:
104
+
105
+ 1. **明确输出格式**:与其写"分析一下",不如写"判断情绪,只返回 Positive / Neutral / Negative"。限定可选值能让结果可机读、可再计算。
106
+ 2. **指定语言**:写"翻译成中文"比只写"翻译"更稳定。
107
+ 3. **指定长度**:如"总结成一句话""30 字以内"。
108
+ 4. **需要结构化时明确要 JSON**:如提示"返回 JSON:{category:'', score:0-100}",AI 能较稳定地输出结构化结果。
109
+
110
+ ### 与普通公式组合
111
+
112
+ `AI` 可以像普通函数一样嵌进公式链,引用单元格或区域:
113
+
114
+ ```
115
+ =IF(B2>90, AI("夸奖一下这位员工"), "")
116
+ =IF(A2="", "", AI("翻译成英文", A2))
117
+ ```
118
+
119
+ `AI(...)` 返回单个结果(标量),把它嵌进公式链时按标量对待即可,不要套 `TEXTJOIN` / `ARRAYFORMULA` 等按数组语义设计的写法——AI 公式不会 spill 出数组。
120
+
121
+ ### 用 CLI 对一列逐行处理
122
+
123
+ 对整列逐行跑 AI,推荐**模板单元格 + `--copy-to-range` 向下扩展**:在种子单元格写 `=AI("<提示词>", A2)`,再用 `--copy-to-range` 扩展到整列,相对引用会随行自增(`A2` → `A3` → …)。这样每行独立计算、行为可预测,比依赖单条公式一次铺开整列更稳。
124
+
125
+ **行数多时分批串行**:AI 公式是异步计算,一次扩展的行数越多越容易触发超时。普通公式可以照 `references/lark-sheets-write-cells.md` 的整列 / 到列尾(`H:H`、`D3:D`)用法一次铺开;**AI 公式**行数很多时建议按批(量级参考:每批约几百到一千行)**串行**扩展——写完一批、`+formula-verify --ai-only` 确认这批已进入计算后再铺下一批,不要一次铺极长的列,也不要多批并发。
126
+
127
+ **写完 AI 公式后的校验与交付**:先对种子格 / 首格做**一次** `+cells-get --include formula` 核对公式文本(**必经步骤**,确认落进去的是 `=AI(...)` 而非 `#ERROR` / 残缺字面量),随后计算状态的第一校验入口必须是 `references/lark-sheets-formula-verify.md` 的 `+formula-verify --ai-only --range <整个写入区间>`(只读、成本低,`--range` 覆盖全区间、不要抽样),**禁止用 `+cells-get` / `+csv-get` 轮询计算结果**。交付判据(机读):`ai_formula_failed_count == 0`(`--range` 不保证收窄汇总口径,按返回的单元格定位核对本次区间,不按总数比对);满足后即使仍有 `ai_formula_pending_count > 0` 也可以交付,飞书会在后台继续计算,交付时告知用户"AI 公式仍在后台运行,结果会陆续完成"。细节见 `references/lark-sheets-formula-verify.md`。
128
+
43
129
  ## 决策流程
44
130
 
45
131
  1. 最终结果是**标量**(单值)→ 直接写普通公式
@@ -1,17 +1,20 @@
1
1
  # Lark Sheet Formula Verify(+formula-verify)
2
2
 
3
- > **本文定位**:飞书表格"公式写入后是否真的零错误"的诊断入口。公式的书写规则与 Excel→飞书迁移的语义规则一律以 `lark-sheets-formula-translation` 为唯一权威,本文不重复;本文聚焦"写完之后如何用一次调用发现公式错误"。
3
+ > **本文定位**:飞书表格"公式写入后是否真的零错误"的诊断入口。公式的书写规则与 Excel→飞书迁移的语义规则一律以 `references/lark-sheets-formula-translation.md` 为唯一权威,本文不重复;本文聚焦"写完之后如何用一次调用发现公式错误"与 AI 公式的全区间一次异步状态检查交付。
4
4
  >
5
- > **边界**:本文不讲公式怎么写(去 `lark-sheets-formula-translation`),也不讲公式怎么写入表格(去 `lark-sheets-write-cells` / `lark-sheets-batch-update`)。本文只讲一件事:任务里发生公式落表、批量填充公式、`--copy-to-range` 扩展公式、导入含公式 workbook 时,如何用 `+formula-verify` 做诊断并决定是否修复。
5
+ > **边界**:本文不讲公式怎么写(去 `references/lark-sheets-formula-translation.md`),也不讲公式怎么写入表格(去 `references/lark-sheets-write-cells.md` / `references/lark-sheets-batch-update.md`)。本文只讲两件事:
6
+ >
7
+ > - **普通公式**:任务里发生公式落表、批量填充公式、`--copy-to-range` 扩展公式、导入含公式 workbook 时,对本次公式范围逐段跑 `+formula-verify --exit-on-error`;`errors_found` 修复、`partial` 拆分续扫,全部分段 `status='success'` 后才算完成。
8
+ > - **AI 公式**(`=AI(...)`):不要用普通公式的"轮询到 zero-error"逻辑;改用 `+formula-verify --ai-only --range` 按「AI 公式校验」的全区间一次异步状态检查规则交付。
6
9
 
7
10
  ## 为什么需要自检
8
11
 
9
- 飞书在线表格已经实时算好结果,但"算出来"和"算对了"是两件事。常见缺口:
12
+ 飞书表格已经实时算好结果,但"算出来"和"算对了"是两件事。常见缺口:
10
13
 
11
14
  - 公式编译失败 → 单元格落成文本(写入类 shortcut 返回的 `formula_errors[]` 是**编译失败**信号)。
12
15
  - 公式编译成功但**运行时错误**:`#REF!` / `#DIV/0!` / `#VALUE!` / `#NAME?` / `#NULL!` / `#NUM!` / `#N/A`——这一类只看 `formula_errors[]` 看不到,必须扫单元格值。
13
16
 
14
- `+formula-verify` 把两路信号合并成一份统一 JSON:一次调用聚合全表错误清单 + 编译失败清单 + 每类错误的定位与样本,AI 一眼就能定位修复。G2 分支中,它提供诊断信号,不再作为默认交付前置条件。
17
+ `+formula-verify` 把两路信号合并成一份统一 JSON:一次调用聚合公式错误清单 + 编译失败清单 + 每类错误的定位与样本,调用方可据此定位修复。任务只要发生公式落表,就把它作为公式错误码健康检查;限定本次新增 / 修改的公式范围逐段扫描并带 `--exit-on-error`。`status='success'` 仅表示无编译/运行时错误,不判断字段映射、阈值、单位、口径或业务结果是否正确——业务语义哨兵见 `references/lark-sheets-formula-translation.md`。
15
18
 
16
19
  ## 调用契约
17
20
 
@@ -23,7 +26,8 @@
23
26
  | `--sheet-id` / `--sheet-name` | 限定子表(mutually exclusive;省略则扫全部可见子表) |
24
27
  | `--range` | 限定 A1 范围;省略则用各 sheet 的 `current_region` |
25
28
  | `--max-locations` | 每类错误样本上限,默认 20 |
26
- | `--exit-on-error` | `status='errors_found'` 时返回非 0 退出码(CI 网关用) |
29
+ | `--exit-on-error` | `status='errors_found'` 时返回非 0 退出码;`partial` 仍需调用方检查 status 并拆分续扫 |
30
+ | `--ai-only` | 只检查 `=AI(...)` 异步计算状态;与普通公式 7 类错误扫描分开使用 |
27
31
 
28
32
  返回核心字段:
29
33
 
@@ -36,7 +40,7 @@
36
40
 
37
41
  ## 写入后诊断规则
38
42
 
39
- 任何批量公式 / 含公式列写入完成后,都可以调用 `+formula-verify` 做一次诊断。不要等用户显式说"校验一下公式"才想到这里;只要任务动作包含写公式,这一步就有较高价值。触发场景:
43
+ 任何批量公式 / 含公式列写入完成后,都必须对本次新增 / 修改的公式范围逐段调用 `+formula-verify --exit-on-error`。不要等用户显式说"校验一下公式"才执行;只要任务动作包含写公式,这一步就是完成路径的一部分。AI 公式不套这条:`=AI(...)` 是异步计算,按「AI 公式校验」的全区间一次异步状态检查规则交付,不等 `status='success'`。触发场景:
40
44
 
41
45
  - `+cells-set` / `+csv-put`
42
46
  - `+cells-set --copy-to-range` / 模板单元格向整列或整块扩展公式
@@ -47,11 +51,11 @@
47
51
 
48
52
  处置规则:
49
53
 
50
- 1. `status='success'` → 记录诊断通过。
51
- 2. `status='partial'` → 扫描被内部上限截断。若该公式区是关键输出,可缩小 `--range` 或拆 `--sheet-id` 续扫;否则在交付说明中标明诊断覆盖不完整。
52
- 3. `status='errors_found'` 且 `compile_errors[]` 非空 → 根据 `compile_errors[].reason` 修正公式语法(飞书函数名 / 范围语法 / 引用样式),或在成本过高时降级为静态值并说明原因。
53
- 4. `status='errors_found'` 且只剩运行时错误 → 按 `error_summary` 的 `samples[].formula` + `depends_on` 排查根因(零除?空值参与运算?引用越界?日期差写法?数组语义?),优先修复关键输出区。
54
- 5. 同一处错误连续修复 3 次仍未通过 → 改用 `IFERROR` 包裹兜底,或退回纯值写入,并在交付说明写清不随源数据更新。
54
+ 1. `status='success'` → 当前分段无编译/运行时错误;但还必须按 `references/lark-sheets-formula-translation.md` 的业务语义契约核字段、阈值、单位、完整范围和业务哨兵。全部目标分段均为 success 且哨兵值正确后才完成。
55
+ 2. `status='partial'` → 扫描被内部上限截断;缩小 `--range` 或拆 `--sheet-id` 续扫,未扫描区域仍未知,不能用交付说明代替验证。
56
+ 3. `status='errors_found'` 且 `compile_errors[]` 非空 → 根据 `compile_errors[].reason` 修正公式语法(飞书函数名 / 范围语法 / 引用样式);确实无法表达时才降级静态值,并说明原因与不联动风险。
57
+ 4. `status='errors_found'` 且只剩运行时错误 → 按 `error_summary` 的 `samples[].formula` + `depends_on` 排查根因(零除?空值参与运算?引用越界?日期差写法?数组语义?),修复后重验。
58
+ 5. 同一处错误连续修复 3 次仍未通过 → 可用 `IFERROR` 兜底或退回纯值,但降级后的目标格已不再是公式;需回读确认没有残留错误公式,并在交付说明写清不随源数据更新。
55
59
 
56
60
  注意:
57
61
 
@@ -69,7 +73,39 @@
69
73
 
70
74
  - 关键输出区优先按 `--sheet-id` / `--sheet-name` 拆成多次调用。
71
75
  - 同 sheet 内按 `--range` 切片(如先 `A1:Z200` 再 `AA1:AZ200`),逐块诊断。
72
- - 如时间不足,说明已诊断范围和未覆盖范围。
76
+ - 续扫是完成条件的一部分:本次写入的公式范围必须全部拆分扫描到 `success`,不能因时间不足只在交付说明里列未覆盖范围就结束(同处置规则 2)。确实无法在本轮扫完时,按处置规则 5 对未验证公式降级为静态值并声明,而不是留下未验证的活公式。
77
+
78
+ ## AI 公式校验(`--ai-only`)
79
+
80
+ 飞书表格提供一个统一的 **`AI` 公式**(`=AI(prompt, [range])`,用自然语言驱动翻译 / 分类 / 情感分析 / 信息提取 / 总结 / 润色等,写法与清单见 `references/lark-sheets-formula-translation.md`)。AI 公式的写入与普通公式一致(复用 `+cells-set` / `set_cell_range`,无需特殊接口),但**计算是异步的**:写入后要等 AI 算完才有结果。普通的 `+formula-verify` 只扫本地单元格值(7 类 Excel 错误),看不到 AI 公式的计算状态。
81
+
82
+ `--ai-only` 让 `+formula-verify` 只校验 AI 公式、跳过普通公式的 Excel 错误扫描,专用于写完 AI 公式后的异步状态检查。**它必须是第一校验入口;禁止先用 `+cells-get` / `+csv-get` 轮询 AI 结果。**
83
+
84
+ - **`--ai-only` 返回字段**(机读判据以这些为准,均为整数):
85
+ - `ai_formula_total`——后端返回的 AI 公式汇总计数,**不是本次写入的单元格条数**(同一批写入的多个 AI 公式可能只计为 1),`--range` 也不收窄它——**认返回里的单元格定位,不要拿它和本次预期条数做等值比对**。
86
+ - `ai_formula_done`——已算出结果的条数。
87
+ - `ai_formula_pending_count`——仍在后台计算(`pending`)的条数。
88
+ - `ai_formula_failed_count`——失败 / 不支持的条数。
89
+ - **异步预期**:少量 AI 公式通常很快算出结果;批量写入后部分公式仍为 `pending`(计算中)属于正常现象,飞书会在后台持续计算。
90
+ - **`--exit-on-error` 兼容**:`--ai-only --exit-on-error` 时,若 `ai_formula_failed_count > 0`,返回非 0 退出码,便于脚本 / CI 收敛。
91
+ - 可与 `--sheet-id` / `--sheet-name` / `--range` 共存,表示「只在指定范围里校验 AI 公式」。
92
+ - **普通公式不要带 `--ai-only`**:带上会跳过 7 类 Excel 错误扫描,普通公式等于没验。
93
+
94
+ **`--range` 用整个写入区间,不要抽样**:`--ai-only` 是只读操作、成本低,`--range` 应覆盖本次写入的**全部** AI 公式区间(而非代表性子集)——子集抽检会漏掉「只有列尾那批被写坏」的情况。但别把 `--range` 当过滤器用:它只透传给后端,AI-only 汇总不保证按它收窄,失败项要按返回的单元格定位核对是否落在本次写入区间内。区间过大触发截断(`has_more=true`)时按「截断与续读」拆 `--range` / `--sheet-id`。
95
+
96
+ **必经步骤:一次性公式文本核对(不是轮询)**。写完 AI 公式后,先对种子格 / 首格做**一次** `+cells-get --include formula`,确认引号 / 括号没在 shell / CSV / JSON 层被破坏、单元格里落进去的确实是 `=AI(...)` 公式而非残缺字面量或 `#ERROR`。这一步只做一次、只看文本,被禁止的只是**用 `+cells-get` 反复轮询计算结果**(结果状态一律走 `--ai-only`)。
97
+
98
+ 交付判据(机读):全写入区间内 `ai_formula_failed_count == 0`;`failed` / `unsupported` 先修完再谈交付。满足后即使仍有 `ai_formula_pending_count > 0` 也可以交付,不必轮询到全部完成;交付时告知用户"AI 公式仍在后台运行,结果会陆续完成"。另外「公式在写入层被破坏、根本没算作 AI 公式」的静默失败不会体现为 `failed`,靠上面那次公式文本核对拦住——不要指望用 `ai_formula_total` 和预期条数对数(该总数未必按 `--range` 收窄)。
99
+
100
+ `ai_formula_failed_count > 0`,或文本核对暴露出 `#ERROR`、残缺括号(如 `E2)`)、半截函数名、全角括号时,说明公式串在引号层被破坏、没作为公式写进去——不要继续等 pending,回到 `+cells-set` 用 `\"` 转义重写该格(写入范例见 `references/lark-sheets-formula-translation.md` 的 AI 公式章节)。
101
+
102
+ 典型用法:
103
+
104
+ ```bash
105
+ # 写入一批 AI 公式后,对整个写入区间校验计算状态
106
+ lark-cli sheets +formula-verify --url <表URL> --sheet-name <子表名> --range <整个写入区间> --ai-only
107
+ # ai_formula_failed_count==0 即可交付;pending 会在后台继续计算
108
+ ```
73
109
 
74
110
  ## 常见陷阱
75
111
 
@@ -77,5 +113,5 @@
77
113
  |---|---|
78
114
  | 错误字符串本地化 | 后端按内部 `error_kind` / `compute_status` 字段识别错误类别,不走字符串匹配;调用方拿到的 7 类英文错误代码由后端统一规范输出,与 locale 无关。 |
79
115
  | `formatted_value` 可能隐藏错误 | 某些条件格式 / 自定义数字格式会把 `#DIV/0!` 显示成空白。后端直接读 cell `error_kind`,不依赖 `formatted_value`,绕开此类被遮蔽。 |
80
- | 把 `partial` 当全量健康 | `partial` 仅表示**已扫描部分**无错误,剩余区域未知。关键公式区应继续缩小范围诊断;非关键区可在交付说明标明覆盖不足。 |
116
+ | 把 `partial` 当全量健康 | `partial` 仅表示**已扫描部分**无错误,剩余区域未知;缩小 ranges 或按 sheet 拆分,直到本次普通公式范围全部 success。 |
81
117
  | 编译失败 vs 运行时错误 | 同一份报告里 `compile_errors[]` 与 `error_summary` 并存。语义层先解决 `compile_errors[]`、再做运行时自检。 |
@@ -30,13 +30,14 @@
30
30
  | "各部门男女人数" | 部门 | 姓名(`"count"`) | 性别 |
31
31
 
32
32
  **常见配置错误(必须注意)**:
33
+ - **值字段类型与聚合器匹配**:`sum/average/median/product/stdDev/stdDevp/var/varp` 只用于数值列;数字个数用 `countNums`,非空记录数用 `count`。mixed 列先保留原值并新增清洗结果/失败标记,记录总数、成功、失败、空值和统计分母,再对清洗后的数值列聚合。
33
34
  - **数据源范围必须精确**:透视表的数据源范围必须包含表头行,且精确覆盖全部数据行列。范围过大(包含空行/空列)或过小(遗漏数据列)都会导致透视表结果错误
34
35
  - **行列字段选择要匹配用户意图**:用户说"按商品统计金额"→ 行字段=商品,值字段=金额(`summarize_by: "sum"`)。不要把行列字段搞反
35
36
  - **聚合类型要匹配**:用户说"统计数量"→ `summarize_by: "count"`;"统计总额"→ `"sum"`;"统计平均"→ `"average"`。完整合法值:`sum` / `count` / `average` / `max` / `min` / `product` / `countNums` / `stdDev` / `stdDevp` / `var` / `varp` / `distinct` / `median`。按用户意图选聚合方式,不要拿 `count` 顶替 `sum`
36
37
  - **`--properties` 还原生支持**:计算字段 `calculated_fields[].summarize_by ∈ {sum, custom}`、重复行标签 `repeat_row_labels: true`——别因速查表没列就判"不支持"绕路
37
38
  - **参数长度限制**:如果透视表配置 JSON 过长(数据源范围跨越大量行列),可能导致工具调用失败。此时应先确认数据范围的精确边界,避免传入过大的 range
38
39
  - **落点不能覆盖任何已有数据(不只是 `--source` 范围)**:透视表创建后会向右下**展开**,展开区域哪怕只盖到一个已有单元格(即便已避开源数据),也会报「目标位置不能与数据源重叠」并产生 `#REF!`。创建前无法精确预知展开尺寸,故**强烈优先默认策略**(不传 `--target-sheet-id/-name` 与 `--target-position`/`--range`,后端自动新建空白子表),零覆盖风险;非要落到已有子表,必须挑一片足够大的纯空白区
39
- - **创建后必须校验(用 `info` 读取展开后的真实占用区域)**:创建后调用 `+pivot-list` 读 `info.error_state` 与 `info.content_range`/`page_range`——`error_state` 非 `None`(如 `Cover` 盖到其它内容 / `Shrink` 展不开)说明落点冲突,应删除后重建到空白区;`content_range`/`page_range` 是展开后**实际占用区域**,可用 `+csv-get` 抽查其边缘外有没有盖掉原有数据,确认结构正确
40
+ - **创建后轮询并校验**:调用 `+pivot-list --sheet-id/--sheet-name <落点表> --pivot-table-id <id>`。`Loading` / `ServiceCalcLoading` 是瞬态,继续轮询到 `info.loaded=true` 且 `error_state=None`;`Cover` / `Shrink` 等终态错误再删除重建。随后用 `info.content_range/page_range` 回读展开区,确认非空、尺寸、总计位置和用户点名的指标。
40
41
 
41
42
  ## Shortcuts
42
43
 
@@ -64,11 +65,11 @@ _公共:URL/token(无 sheet 定位) · 系统:`--dry-run`_
64
65
  | Flag | Type | 必填 | 说明 |
65
66
  | --- | --- | --- | --- |
66
67
  | `--properties` | string + File + Stdin(复合 JSON) | required | JSON:{"rows":[...],"columns":[...],"values":[...],"filters":[...],"show_row_grand_total":true,"show_col_grand_total":true}(数据源走 --source,不要再放进 properties.source) |
67
- | `--target-position` | string | optional | 透视表落点子表内的起始 cell(A1 格式,如 `A1`),映射到顶层 `target_position`,默认 `A1`(值为 A1 时不下发)。它与 `--range` 都表达落点但落在不同 wire 字段,避免两者同时给冲突值 |
68
+ | `--target-position` | string | optional | 透视表落点子表内的起始 cell(A1 格式,如 `A1`),默认 `A1`(值为 A1 时不下发)。它与 `--range` 落在同一 wire 字段 `properties.range`,给非默认值时优先于 `--range`;两者同时给非默认值会被拒绝,只传其一 |
68
69
  | `--target-sheet-id` | string | xor | 透视表落点目标子表的 reference_id(与 `--target-sheet-name` 互斥,优先于 --target-sheet-name;都不传时自动新建一张子表放置透视表——推荐)。与数据源 sheet 区分:数据源 sheet 写在 --source 的 A1 引用里(带 sheet 前缀,形如 `'Sheet1'!A1:D100`)。 |
69
70
  | `--target-sheet-name` | string | xor | 透视表落点目标子表的名称(与 `--target-sheet-id` 互斥;都不传时自动新建一张子表放置透视表——推荐)。与数据源 sheet 区分:数据源 sheet 写在 --source 的 A1 引用里(带 sheet 前缀,形如 `'Sheet1'!A1:D100`)。 |
70
71
  | `--source` | string | required | 透视表源数据区域(A1 表示法,格式 `'SheetName'!StartCell:EndCell`,如 `'Sheet1'!A1:D100`) |
71
- | `--range` | string | optional | 透视表左上角放置位置(A1 单值,如 `F1`,仅 create 生效),映射到 `properties.range`;省略时放在落点子表(默认新建子表)的左上角。它与 `--target-position` 都表达落点但落在不同 wire 字段,避免两者同时给冲突值 |
72
+ | `--range` | string | optional | 透视表左上角放置位置(A1 单值,如 `F1`,仅 create 生效),映射到 `properties.range`;省略时放在落点子表(默认新建子表)的左上角。它与 `--target-position` 落在同一 wire 字段,两者同时给非默认值会被拒绝,只传其一 |
72
73
 
73
74
  ### `+pivot-update`
74
75
 
@@ -114,7 +115,7 @@ _创建/更新的透视表属性_
114
115
 
115
116
  公共四件套:所有 shortcut 顶部排列 `--url` / `--spreadsheet-token` / `--sheet-id` / `--sheet-name`,其中 `--sheet-id` / `--sheet-name` 在 `+pivot-update` / `+pivot-delete` / `+pivot-list` 上是公共四件套语义(定位透视表所在 sheet,XOR 必传一个)。
116
117
 
117
- **`+pivot-create` 例外**:placement 选择器用 `--target-sheet-id` / `--target-sheet-name`(XOR,两个都不传时后端自动新建子表存放产物,强烈推荐,绝不碰源数据)。数据源 sheet 写在 `--source` 的 `'SheetName'!Range` 里,不靠 sheet 选择器 flag。
118
+ **`+pivot-create` 例外**:placement 选择器用 `--target-sheet-id` / `--target-sheet-name`(至多一个、都可省略;省略时后端自动新建子表,推荐)。数据源 sheet 写在 `--source` 的 `'SheetName'!Range` 里。
118
119
 
119
120
  ### `+pivot-list`
120
121
 
@@ -124,7 +125,7 @@ lark-cli sheets +pivot-list --url "..." --sheet-id "$SID"
124
125
 
125
126
  > **返回值含 `info`(展开后的占用区域与状态)**:每个透视表对象除 `position` / `snapshot` 外,还返回 `info`,标明它在 sheet 上的平铺区域与状态——`info.page_range`(筛选/分页区 A1)、`info.content_range`(主体数据区 A1)、`info.span_range`(空表合并区 A1)、`info.error_state`(错误状态,如 `None`/`Cover`/`Shrink`/`Loading`)、`info.is_empty` / `info.is_hidden`、`info.row`/`info.col`(锚点)等。
126
127
  > **用途 1(判断改值还是改配置)**:当用户描述某个单元格要改动时,先 `+pivot-list` 拿到 `info`,判断该单元格是否落在 `page_range` / `content_range` 内——**落在区域内 = 属于透视表,应走 `+pivot-update` 改配置**(透视表单元格不能直接 `+cells-set` 改值);**落在区域外 = 普通单元格,正常 `+cells-set` 改值**。
127
- > **用途 2(创建后校验覆盖)**:建完透视表用 `info.error_state` 判断有没有冲突(非 `None` 即落点/展开区与已有数据重叠或展不开),用 `info.content_range`/`page_range` 拿到展开后真实占用区域再核对是否盖到原有数据。
128
+ > **用途 2(创建后校验覆盖)**:建完后轮询 `info.loaded/error_state`;`Loading` / `ServiceCalcLoading` 继续等待,`Cover` / `Shrink` 等终态错误才表示冲突。成功后用 `content_range/page_range` 核对真实占用区域与原数据边界。
128
129
 
129
130
  ### `+pivot-create`
130
131
 
@@ -133,13 +134,12 @@ lark-cli sheets +pivot-list --url "..." --sheet-id "$SID"
133
134
  > **先理清 `+pivot-create` 上 4 个位置类入参(语义不同,别混)**:
134
135
  > - `--source`(**必填**):**源数据**区域,须自带 `Sheet!` 前缀(如 `'Sheet1'!A1:D100`,sheet 名按 A1 标准单引号包裹)。源 sheet 的名字在 `--source` 字符串里,**不**通过单独 flag 传。
135
136
  > - `--target-sheet-id` / `--target-sheet-name`:**透视表的落点 sheet**(即产物放哪张子表)。两个互斥(最多传一个),都不传时后端自动新建子表存放产物(强烈推荐)。
136
- > - `--target-position`(可选,A1 表示法,默认 `A1`):落点 sheet 内的起始 cell,映射到顶层 `target_position`。
137
- > - `--range`(可选,A1 单值,仅 create 生效):跟 `--target-position` 表达同一意图但映射到 `properties.range`,**两者不要同时给**。
137
+ > - `--target-position`(可选,默认 `A1`)与 `--range`(可选)都映射到 `properties.range`,表达同一落点;不要同时给两个非默认值。
138
138
  >
139
139
  > **落点 3 种策略(互斥,选其一)**:
140
140
  > 1. **默认(强烈推荐)**:`--target-sheet-id` / `--target-sheet-name` / `--target-position` / `--range` **全都不传** → 服务端**自动新建子表**存放产物,绝不碰任何已有数据。
141
141
  > 2. **放进指定的已有子表**:传 `--target-sheet-id <落点子表 id>`(或 `--target-sheet-name`),可选 `--target-position <子表内起点 cell>`。⚠️ **若落点子表就是源数据所在的 sheet**,必须配 `--target-position` 或 `--range` 指向源数据范围**之外**的位置,否则产物默认从 A1 起会盖在源数据上。
142
- > 3. **`--range`**:跟策略 2 等价(同样需要 `--target-sheet-id` / `--target-sheet-name` 指定落点子表,不然落到自动新建子表),只是用 `properties.range` 那条 wire 路径表达位置。同样的覆盖风险,同样需要避开源数据范围。
142
+ > 3. **`--range`**:跟策略 2 等价(同样需要 `--target-sheet-id` / `--target-sheet-name` 指定落点子表,不然落到自动新建子表),只是改用 `--range` 表达同一落点(与 `--target-position` 同一 wire 字段)。同样的覆盖风险,同样需要避开源数据范围。
143
143
  >
144
144
  > 一般用策略 1(默认新建子表)即可,零覆盖风险,无需任何 `--target-*` / `--range` flag。
145
145
 
@@ -155,7 +155,7 @@ lark-cli sheets +pivot-create --url "..." \
155
155
 
156
156
  ### `+pivot-update`
157
157
 
158
- > 不允许改 `--source` / `--range`(透视表创建后位置/数据源固定);只能用 `--properties` 改 rows / columns / values / filters 等。先 `+pivot-list --pivot-table-id <id>` 回读再 patch,避免漏字段。
158
+ > 不允许改落点 range;更新配置前先 `+pivot-list --sheet-id/--sheet-name <落点表> --pivot-table-id <id>` 回读完整 snapshot,再 patch rows / columns / values / filters。需要切换数据源时,可在 `--properties` 中提供新的 `source`。
159
159
 
160
160
  ### `+pivot-delete`
161
161
 
@@ -165,8 +165,8 @@ lark-cli sheets +pivot-delete --url "..." --sheet-id "$SHEET_ID" --pivot-table-i
165
165
 
166
166
  ### Validate / DryRun / Execute 约束
167
167
 
168
- - `Validate`:`--url` / `--spreadsheet-token` XOR 必填;`+pivot-{update,delete,list}` 的 `--sheet-id` / `--sheet-name` XOR 必填一个;`+pivot-create` 例外(用 `--target-sheet-id` / `--target-sheet-name` 表达落点,两个都可空时触发 backend auto-create 子表,两个都给则报 mutually exclusive);`+pivot-create` 的 `--source` 必填且必须含表头行;`--properties` 中 `rows` / `columns` / `values` 至少非空之一;`+pivot-delete` 强制 `--yes` 或 `--dry-run`。
169
- - `DryRun`:写操作输出"将要 POST/PATCH/DELETE 的 pivot 请求模板"+ 预估输出尺寸(行数 × 列数)。
170
- - `Execute`:写后不自动回读;如需确认,自行调用 `+pivot-list --pivot-table-id <id>` 并用 `+csv-get` 抽样读透视产物核对输出尺寸 + 总计行位置。
168
+ - `Validate`:`--url` / `--spreadsheet-token` XOR 必填;update/delete/list 的 `--sheet-id` / `--sheet-name` XOR 必填;create 的 target selector 至多一个、可都省略;`--source` 与合法 `--properties` 必填;delete 强制 `--yes` 或 `--dry-run`。schema 校验类型与枚举,但允许创建空壳配置,业务完整性须靠创建后 list/data 验证。
169
+ - `DryRun`:输出将发送的 pivot 请求模板和本地 placement_warning;不联网、不预估实际展开尺寸。
170
+ - `Execute`:写后不自动回读;create/update 后必须按落点 sheet + pivot id 轮询 `+pivot-list` 到 loaded,核 error_state/content_range 与数据;delete 后 list 确认目标不存在。
171
171
 
172
- > ⚠️ pivot 输出包含总计 / 小计行;后续 chart 引用 pivot 时,`snapshot.data.refs` 必须排除这些行(见 `lark-sheets-chart` 的「⚠️ chart 数据源引用 pivot 时必须排除总计行」段)。
172
+ > ⚠️ pivot 输出包含总计 / 小计行;后续 chart 引用 pivot 时,`snapshot.data.refs` 必须排除这些行(见 `references/lark-sheets-chart.md` 的「⚠️ chart 数据源引用 pivot 时必须排除总计行」段)。
@@ -28,6 +28,8 @@
28
28
  - 调整行高列宽时,先读取相邻行列尺寸再决定像素值,不要随意猜测
29
29
  - `--copy-to-range`(`+cells-set` 的参数)复制的是值/公式/样式,不含行高列宽。需要统一尺寸时另行调用 `+rows-resize / +cols-resize`
30
30
 
31
+ **排序必须覆盖完整记录宽度**:`+range-sort --range` 是整行记录原子移动的边界,必须从记录第一列覆盖到最后一列;“按 B 列排序”只表示 `--sort-keys` 选 B,不是把 range 写成 `B:B`。范围含表头时加 `--has-header`。排序后回读前几行和末行,确认各列仍保持同行关系。
32
+
31
33
  ## 写入后列宽自适应(防内容遮挡)
32
34
 
33
35
  写入文本 / 数值后**必须**主动检查列宽是否适配,否则会出现"内容被截断 / 长数字显示为科学计数法 / 文本溢出被相邻列遮挡"等用户感知问题:
@@ -36,7 +38,7 @@
36
38
  2. **判定阈值**:当前列宽(用 `+sheet-info --include row_heights,col_widths` 拿)≥ 最长字符数 × 字体宽度系数 + buffer 才算适配。默认列宽 11 通常只够 11 个半角字符或 5-6 个汉字,写长文本前必扩宽。
37
39
  3. **修复二选一**:
38
40
  - **扩列宽**:用 `+rows-resize / +cols-resize` 把目标列宽设为 `max(表头字符数, 内容采样最长字符数) × 8 + 16` 像素(经验值)
39
- - **自动换行**:在 `+cells-set` 时给单元格设置 `cell_styles.word_wrap="auto-wrap"`(可选值:`overflow` / `auto-wrap` / `word-clip`;`cell_styles` 字段见 `lark-sheets-write-cells`),并用 `+rows-resize / +cols-resize` 调高对应行的行高
41
+ - **自动换行**:在 `+cells-set` 时给单元格设置 `cell_styles.word_wrap="auto-wrap"`(可选值:`overflow` / `auto-wrap` / `word-clip`;`cell_styles` 字段见 `references/lark-sheets-write-cells.md`),并用 `+rows-resize / +cols-resize` 调高对应行的行高
40
42
  4. **新增列默认列宽规则**:新增列宽度 ≥ `max(表头字符数, 内容采样最长字符数) × 8 + 16` 像素,**禁止**用默认 11 直接交付。
41
43
 
42
44
  **典型反例**:默认列宽 11 但内容含 12+ 字符的中文 / 含单位的数值(如 `109.10μmol/L`)/ 长数字未设 `number_format` 显示为科学计数法 —— 用户在结果表里看不到完整原值。
@@ -53,8 +55,9 @@
53
55
  4. **对合并区域设置样式**:只对完整 range 设置一次 `cell_styles`(写在左上角单元格),其余位置用 `{}` 占位。
54
56
  5. **新增合并时数据保护**:合并前确认目标区域只有左上角有数据,其余单元格为空,否则合并会导致非左上角的数据丢失。
55
57
  6. **批量取消合并一次调用即可**:当一个范围(整列 `A:A`、整行 `3:3`、矩形 `A1:D100`)内存在多个合并区域,直接调一次 `+cells-unmerge` 传入这个大范围,会一次性取消该范围内所有合并区域;**不要**为每个合并区域单独调用 unmerge,也不要用 `+batch-update` 拆成多次 unmerge。
58
+ 7. **合并 / 取消合并后必须验证**:`+sheet-info --include merges` 核目标范围,再 `+cells-get` 回读左上角值和非左上角清空状态。
56
59
 
57
- **⚠️ 多区域合并不要逐个调用**:对**多个**不同区域执行 `+cells-merge` 时,写成一份 `+styles-put --styles` 的 `cell_merges` 一次交付(合并与样式 / 行高列宽 / 冻结同属一份声明式规格,见 `lark-sheets-styles-put`);只有当合并夹在**跨类型、有顺序依赖**的操作链里(如插列 → 合并 → 写表头)才用 `+batch-update`(fail-fast,失败处置与入参格式见 `lark-sheets-batch-update`)。行高列宽同理**不需要** `+batch-update`:多行 / 多列不同尺寸直接用 `+rows-resize --heights` / `+cols-resize --widths` 的 map 形态,一次调用完成。
60
+ **⚠️ 多区域合并不要逐个调用**:对**多个**不同区域执行 `+cells-merge` 时,写成一份 `+styles-put --styles` 的 `cell_merges` 一次交付(合并与样式 / 行高列宽 / 冻结同属一份声明式规格,见 `references/lark-sheets-styles-put.md`);只有当合并夹在**跨类型、有顺序依赖**的操作链里(如插列 → 合并 → 写表头)才用 `+batch-update`(fail-fast,失败处置与入参格式见 `references/lark-sheets-batch-update.md`)。行高列宽同理**不需要** `+batch-update`:多行 / 多列不同尺寸直接用 `+rows-resize --heights` / `+cols-resize --widths` 的 map 形态,一次调用完成。
58
61
 
59
62
  **唯一例外**:`+cells-unmerge` 原生支持传一个大 range 一次性取消其中所有合并区域,应直接单次调用,**不要**拆进 `+batch-update`。
60
63
 
@@ -76,9 +79,9 @@
76
79
 
77
80
  1. sort 前先用 `+csv-get` 抽样目标列的前 3–5 行确认原始值形态,不要只看列名和用户问题就直接排。
78
81
  2. 若是纯数字或日期 → 直接 sort。
79
- 3. 若是带符号 / 表达式 / 单位的文本 → **不要直接排**:
80
- - 简单场景(货币、千分位、单位前缀):新增辅助列,用公式提取数值(如 `=VALUE(SUBSTITUTE(SUBSTITUTE(A2,"¥",""),",",""))`),按辅助列排序,排完可按需清除辅助列。
81
- - 复杂场景(多段表达式、中文单位、混合格式):分批 `+csv-get` 读到本地,按数值排序后用 `+csv-put` / `+cells-set` 分批回写。
82
+ 3. 若是带符号 / 表达式 / 单位的文本 → **不要直接排,也不要读值后用 `+csv-put` 覆盖原表来模拟排序**:
83
+ - 简单场景(货币、千分位、单位前缀):新增辅助列,用公式提取数值(如 `=VALUE(SUBSTITUTE(SUBSTITUTE(A2,"¥",""),",",""))`),再用 `+range-sort` 按辅助列原子排序;排完可按需删除辅助列。
84
+ - 复杂场景(多段表达式、中文单位、混合格式):先写辅助数值列,再用 `+range-sort`;无法可靠提取时保留原顺序并说明,禁止整块覆盖回写。
82
85
 
83
86
  ## Shortcuts
84
87
 
@@ -215,11 +218,11 @@ _排序条件列表(仅 sort 操作)_
215
218
 
216
219
  ### `+cells-clear`
217
220
 
218
- > ⚠️ **`--scope all` 清整表是不可逆的大范围破坏**:会一并抹掉该区域的合并单元格、原公式,以及图表 / 透视表引用的数据源列(这类列常在主数据区右侧,视觉上"看着没用"却被图例 / 系列引用)。**"美化 / 规范化一张已有表"永远不需要 clear 原表再重写**——若你打算"清空原表 → 写入重排后的版本",说明走错了路径,应改为原地只刷样式(见 `lark-sheets-visual-standards` 场景三)。
221
+ > ⚠️ **`--scope all` 清整表是不可逆的大范围破坏**:会一并抹掉该区域的合并单元格、原公式,以及图表 / 透视表引用的数据源列(这类列常在主数据区右侧,视觉上"看着没用"却被图例 / 系列引用)。**"美化 / 规范化一张已有表"永远不需要 clear 原表再重写**——若你打算"清空原表 → 写入重排后的版本",说明走错了路径,应改为原地只刷样式(见 `references/lark-sheets-visual-standards.md` 场景三)。
219
222
 
220
223
  > **删不掉嵌入对象**:`+cells-clear`(任何 `--scope`,含 `all`)只清单元格的值 / 格式,**删不掉**压在范围内的透视表 / 图表等嵌入对象——后端会报 `can not find embedded block`。删透视表用 `+pivot-delete`、删图表用 `+chart-delete`(先用 `+pivot-list` / `+chart-list` 拿对象 id)。
221
224
 
222
- > 需要一次清除**多个不连续 range**(如把内容搬走后批量去掉散落各处的边框/底色)时,改用 `lark-sheets-batch-update` 的 `+cells-batch-clear`,避免对 `+cells-clear` 逐个 range 调用。
225
+ > 需要一次清除**多个不连续 range**(如把内容搬走后批量去掉散落各处的边框/底色)时,改用 `references/lark-sheets-batch-update.md` 的 `+cells-batch-clear`,避免对 `+cells-clear` 逐个 range 调用。
223
226
 
224
227
  ```bash
225
228
  # dry-run 先看
@@ -270,7 +273,7 @@ lark-cli sheets +cols-resize --url "..." --sheet-id "$SID" --range "A:E" --type
270
273
 
271
274
  **列宽没有 auto-fit**:需要"列宽自适应内容"时,按"写入后列宽自适应"一节的公式估算像素值(`max(表头字符数, 内容最长字符数) × 8 + 16`)后用 `--widths` 显式设置。
272
275
 
273
- > 同时出现在 `lark-sheets-sheet-structure.md` —— 行高 / 列宽调整也算行列结构层动作。
276
+ > 同时出现在 `references/lark-sheets-sheet-structure.md` —— 行高 / 列宽调整也算行列结构层动作。
274
277
 
275
278
  ### `+range-move` / `+range-copy`
276
279
 
@@ -294,4 +297,4 @@ lark-cli sheets +range-sort --url "..." --sheet-id "$SID" --range "A1:E100" --ha
294
297
 
295
298
  - `Validate`:XOR 公共四件套;`+cells-clear` 强制 `--yes` 或 `--dry-run`;`+range-*` 校验源 / 目标 range 在同一 spreadsheet;`+range-sort` 的 `--sort-keys` 必须合法 JSON 数组且 col 都在 `--range` 内;`+rows-resize` / `+cols-resize` 两种形态二选一——统一形态必须给 `--range` 且至少给 `--height`/`--width` 或 `--type` 之一(`--type standard`/`auto` 不能与像素 flag 同给,`--type pixel` 共存 OK),map 形态(`--heights`/`--widths`)不能与 `--range`/`--height`/`--width`/`--type` 混用,map 键必须与命令维度一致(行数字 / 列字母)、不得重复,值为正整数像素或模式字符串;列宽 < 20px 拒绝(疑似 Excel 字符单位);`+cols-resize` 不接受 `auto`(列宽不支持自适应)。map 形态在 `+batch-update` 子操作里不可用(它本身就是批量提交)。
296
299
  - `DryRun`:所有写操作输出"将要 PATCH 的 range + 受影响 cell 数估算"。
297
- - `Execute`:写后不自动回读;如需确认,自行调用 `+cells-get --range <影响范围>` 抽样比对。
300
+ - `Execute`:sort/move/copy/fill 后回读首、中、末记录;merge/unmerge 后 `+sheet-info --include merges` + `+cells-get` 核范围、左上角值与边界;clear 后确认目标 scope 已空;resize 结果用 `+sheet-info` 核尺寸,不能只读 cell 值。
@@ -11,7 +11,7 @@
11
11
  - **空值与 0 / "0" 混杂**
12
12
  - **大小写 / 全角半角差异**("办公费" vs "办公费 "、"Sales" vs "sales")
13
13
 
14
- 预探后必须在公式 / 筛选条件里用 `IFERROR` / `IFS` / 提取数值的辅助列处理所有变体;不能为了通过 head(10) 的样本就直接落地。一旦设计的逻辑只覆盖 sample 中出现的格式,就属于违规。
14
+ 预探后必须在公式 / 筛选条件里用 `IFERROR` / `IFS` / 提取数值的辅助列处理所有变体;不能为了通过 head(10) 的样本就直接落地。设计的逻辑只覆盖 sample 中出现的格式,在 sample 外的行必然出错。
15
15
 
16
16
  ⚠️ **大数字(15 位以上的身份证 / 参考号 / 流水号)做去重 / 比较时禁止用 `+csv-get` 的显示值**:`+csv-get` 返回的是**格式化显示值**,15 位以上数字会被显示成 `1.04E+14` 这类科学计数法——多个本不相同的号在显示层全变成同一个 `1.04E+14`,拿去判重会**整列误判为重复**。比较 / 去重 / 匹配大数字时必须改用 `+cells-get`(取原始精确值)或把该列读为文本,禁止用 csv-get 的科学计数显示值(反例:大批长参考号被显示成科学计数后,互不相同的号全变成同一个值,被当成整列重复并错误高亮)。
17
17
 
@@ -38,7 +38,7 @@
38
38
 
39
39
  | 脚本 | 底层 shortcut | 适用场景 |
40
40
  | --- | --- | --- |
41
- | `scripts/lark_inspect_workbook.py` | `+workbook-info` / `+sheet-info` / `+csv-get` | 在线表格第一步预检:拿 sheet 清单、布局、预览、`current_region` |
41
+ | `scripts/lark_inspect_workbook.py` | `+workbook-info` / `+sheet-info` / `+csv-get` | 飞书表格第一步预检:输出所有 sheet summary、布局、预览和 `data.selection`;未点名时仅从 `resource_type=sheet && is_hidden=false` 的 visible_grid 候选中选,唯一才自动使用,多候选不得按 index 猜。 |
42
42
  | `scripts/lark_detect_subtables.py` | `+workbook-info` / `+sheet-info --include merges,hidden_rows,hidden_cols` / 小窗口 `+csv-get` | 同一 sheet 可能有多个表格区域、汇总块、备注块时,在**已知且未截断的窗口**内识别候选子表 range |
43
43
  | `scripts/lark_profile_table.py` | `+csv-get` / `+sheet-info --include hidden_rows,hidden_cols`(默认包含隐藏行列时;必要时再手工 `+cells-get` / `+table-get`) | 对**已确认且未截断的候选 range**做表头、数据范围、列类型、特殊行画像,并输出 `summary` / `field_map` / `risk_warnings` / `write_hints` |
44
44
 
@@ -56,10 +56,10 @@
56
56
  推荐链路(大表先定窗口,脚本不接受截断结果):
57
57
 
58
58
  ```bash
59
- python scripts/lark_inspect_workbook.py --url "<表格URL>"
59
+ python3 scripts/lark_inspect_workbook.py --url "<表格URL>"
60
60
  # 先用 +workbook-info 和小窗口 +csv-get 确认真实 sheet、列边界和起始区域;大表按行窗口推进。
61
- python scripts/lark_detect_subtables.py --url "<表格URL>" --sheet-name "<子表名>" --range "A1:H200"
62
- python scripts/lark_profile_table.py --url "<表格URL>" --sheet-name "<子表名>" --range "A1:H200"
61
+ python3 scripts/lark_detect_subtables.py --url "<表格URL>" --sheet-name "<子表名>" --range "A1:H200"
62
+ python3 scripts/lark_profile_table.py --url "<表格URL>" --sheet-name "<子表名>" --range "A1:H200"
63
63
  ```
64
64
 
65
65
  `lark_detect_subtables.py` / `lark_profile_table.py` 的 `+csv-get` 命中 `has_more` 会以错误退出并报告已读取的 `actual_range`,绝不基于半截数据给出候选范围或画像。遇到此错误,以 `actual_range` 为已完成窗口,缩小列数或从其末行之后继续读;跨窗口的候选范围、汇总行和写入落点必须再用 CLI 核对,不能把单个窗口结果当整表结论。
@@ -95,6 +95,8 @@ detect 最多确认 10 个跨窗口合并锚点;超限会在 `warnings` 中说
95
95
 
96
96
  - `write_hints.safe_append_col` 只是候选追加列,不代表绝对安全。新增列或覆盖区域前,必须用 `+csv-get` / `+cells-get` / `+sheet-info` 核对该列为空、没有隐藏列/公式/样式/对象依赖,且符合用户要求的落点。该字段已自动跳过隐藏列(跳过的列名列在 `write_hints.skipped_hidden_cols`)——注意 `--skip-hidden` 下隐藏列根本不出现在返回网格里,若它们正好都贴在数据右边缘,`data_range_has_col_gaps` 也不会告警,所以这层跳过是唯一的保护,别绕过它自己按「最后一列 +1」推落点。
97
97
 
98
+ ⚠️ **解析 CLI 输出只读 stdout**:数据走 stdout、诊断与警告走 stderr,解析 JSON 时别用 `2>&1` 合流(警告混进去会解析失败),用管道或单独重定向 stdout。命令失败先读 stderr 再调整,别原样重发。
99
+
98
100
  ⚠️ **大数据优先落盘、别灌进上下文**:`+csv-get` / `+cells-get` 都受调用方 Bash / 终端的单命令 stdout 输出上限约束(常见默认约 30000 字符,超过会被截断或转存为文件)。纯值分析优先用 `+csv-get` 按 `--range` 行窗口(`A1:Z500` / `A501:Z1000` …)分批重定向到文件 + 本地脚本处理 + `+csv-put` 分批回写;若确实要让结果直接进上下文又不想触发转存,给任一命令把 `--max-chars`(默认 500000)调小到略低于该上限(如 `25000`),CLI 改为优雅截断 + `has_more` 分页。
99
101
 
100
102
  > **落盘不等于读全**:`--output-path` 只是把上限从 stdout 口径放宽到有界的 2000 万字符(读取链路非流式,该上限是内存保护),不是无限。stdout 回执带 `complete` 字段——`complete:false` 时另有 `truncated` 与提示,文件里只有半截数据;多子表读取还会给 `unread_sheets` 列出预算耗尽前没读到的子表。**拿到回执先看 `complete`,不要默认整表已落全。**
@@ -250,7 +252,7 @@ lark-cli sheets +cells-get --url "https://example.feishu.cn/sheets/shtXXX" --she
250
252
 
251
253
  `+table-put`(写入侧,见 write-cells reference)的镜像:把表格读回与 `--sheets` 完全同构的 typed 协议(`sheets[]` + `columns:[列名]` + `data:[[行]]` + `dtypes:{列名:pandas_dtype}` + `formats?:{列名:number_format}` + `range`),可直接喂回 `+table-put` 或一行还原 DataFrame。
252
254
 
253
- **默认(不带 `--range`)读取整张子表的完整 used range**:会跨过表中部的整行空行 / 整列空列,覆盖到真实数据边界。每个子表都回传实际读取的 `range`(如 `A1:F10`)。**截断信号分三层**:① 子表数据被 `max_chars` 裁掉时,该子表带 `truncated: true` + `truncation_warning`;② 字符预算耗尽导致后续整表一行未读时,**顶层**也带同组字段(按提示改用 `--sheet-name` 单表重跑或提高 `--max-chars`);③ `--output-path` 落盘模式以 stdout 回执的 `complete`(命中上限时另有 `truncated`)判断文件完整。**任何一层都没报截断,也不等于逻辑读全**——used range 探测在特殊布局(大段整空行 / 空列)下可能偏窄:拿 `range` 连同返回 `data` 的实际行数、关键末行 / 末日期,与源数据行列数(`+workbook-info` / 源 xlsx)交叉核对,确认覆盖真实边界。仍要精确控制范围时显式传 `--range`;分段续读时配 `--no-header`,表头行与各段 dtypes 需自行拼接对齐。
255
+ **默认(不带 `--range`)先按整张子表物理网格探测 used range**:可跨过表中部空行 / 空列定位真实数据边界,再读取该区域。仍受 `--max-chars` 上限约束;返回 `truncated=true` 或 `complete=false` 时,文件/响应只有部分数据,改用 `--output-path`、提高上限或按 sheet/range 续读。每个子表的 `range` 只表示本次目标区域,不能单独证明内容已完整返回。
254
256
 
255
257
  列类型从每列 `number_format` 推断(日期格式→`date`/`datetime64[ns]`、数值→`number`/`float64`、bool→`bool`),`date` 列的序列号转回 ISO `yyyy-mm-dd`——日期、数字往返不丢类型。**列类型只在该列所有非空值一致时才定(`number` / `date` / `bool`);一列混了类型(如数字列混入「暂无」、日期列混入裸数字)会降为 `string`(dtypes 输出 `object`),让 `dtypes` 与 `data` 里每个值自洽——能 round-trip 回 `+table-put`、不让 pandas `astype` 崩。降级是无损的(脏值原样保留为文本);若要把零星脏值转成数值列,交给调用方在 pandas 侧做(`to_numeric(errors='coerce')`),那里原始值仍在、可追溯。** 默认读所有子表、第一行当表头(`--no-header` 把首行当数据、列名取 `col1` / `col2` …)。
256
258
 
@@ -263,11 +265,11 @@ lark-cli sheets +table-get --url "<表URL>" --sheet-name "销售"
263
265
 
264
266
  #### 输出 → DataFrame(用 `sheet_to_df` helper)
265
267
 
266
- 输出形状对齐 pandas split:`columns` 是列名数组、`data` 是二维数据、`dtypes` 是 `{列名: pandas_dtype_str}` 映射。直接喂给 `pd.DataFrame(...).astype(...)` 就能一次性还原所有列类型(不必逐列 `to_datetime` / `to_numeric`)。本 skill 把这段 2 行 helper 打包成可 import 的 [`scripts/sheets_df.py`](../scripts/sheets_df.py)(含 `df_to_sheet` 和 `sheet_to_df`,写入 / 读回成对;它在本 skill 的 `scripts/` 目录下,运行目录不在该目录时先把它加入 `sys.path` 再 import):
268
+ 输出形状对齐 pandas split:`columns` 是列名数组、`data` 是二维数据、`dtypes` 是 `{列名: pandas_dtype_str}` 映射;`truncated/complete/truncation_warning` 说明覆盖度。未截断时可直接喂给 `pd.DataFrame(...).astype(...)`。本 skill 提供 [`scripts/lark_sheets_df.py`](../scripts/lark_sheets_df.py):
267
269
 
268
270
  ```python
269
- import sys; sys.path.insert(0, "scripts") # helper 在 skill 根的 scripts/ 下;cwd 不在 skill 根时填该目录的实际路径
270
- from sheets_df import sheet_to_df
271
+ import sys; sys.path.insert(0, "scripts") # cwd 不在 skill 根时改成 scripts/ 的实际路径
272
+ from lark_sheets_df import sheet_to_df
271
273
 
272
274
  # 单 sheet
273
275
  df = sheet_to_df(out["data"]["sheets"][0])
@@ -281,12 +283,12 @@ df_sales = sheets["销售"]
281
283
 
282
284
  #### round-trip:读 → 改 → 写回(写读对偶)
283
285
 
284
- `sheet_to_df` 和 `df_to_sheet` 一对镜像 helper([`scripts/sheets_df.py`](../scripts/sheets_df.py))让 round-trip 三段读 / 改 / 写各一行:
286
+ `sheet_to_df` 和 `df_to_sheet` 一对镜像 helper([`scripts/lark_sheets_df.py`](../scripts/lark_sheets_df.py))让 round-trip 三段读 / 改 / 写各一行:
285
287
 
286
288
  ```python
287
289
  import json, subprocess
288
- import sys; sys.path.insert(0, "scripts") # 同上:sheets_df 在 skill 的 scripts/ 目录
289
- from sheets_df import df_to_sheet, sheet_to_df
290
+ import sys; sys.path.insert(0, "scripts") # cwd 不在 skill 根时改成 scripts/ 的实际路径
291
+ from lark_sheets_df import df_to_sheet, sheet_to_df
290
292
 
291
293
  # 1. 读
292
294
  out = json.loads(subprocess.check_output(
@@ -6,7 +6,7 @@
6
6
 
7
7
  1. **明确替换范围**:建议显式说明"只替换 X 列 / X 区域,还是全表替换"。避免默认全表替换——容易误改无关列。范围应由用户指令决定,模糊时主动询问。
8
8
  2. **dry-run 命中数量**:先用 `+cells-search` 在同一范围、同一关键词、同一匹配选项(大小写 / 精确 / 正则)下统计命中数量。把数量和**期望命中数**(用户明示的或基于业务理解推断的)对照;不一致先排查(关键词太宽?范围太大?)。
9
- 3. **替换后回读校验**:执行后再次 `+cells-search` 旧关键词,预期为 0;并对替换后的若干代表性单元格回读确认值符合预期。
9
+ 3. **替换后全量校验**:执行后再次 `+cells-search` 旧关键词,预期为 0;指定了完整 range 与旧值枚举时逐项搜索,随机抽样不能替代。**例外**:新值本身包含旧值时(如 `v1`→`v1.1`,或子串替换后新值仍含关键词),子串搜索仍会命中,此时零命中判据不成立——改用整格精确匹配(`--match-entire-cell` 类选项)核对,或直接回读代表性单元格确认已是新值,别据非零命中判未替换而重复执行(会得到 `v1.1.1`)。只有用户明确要求本地 xlsx / 下载 / 打印,或正在验证导入前的本地 Excel 文件时,才运行本地产物检查脚本。
10
10
 
11
11
  ## 使用场景
12
12
 
@@ -102,10 +102,10 @@ lark-cli sheets +cells-replace --url "https://example.feishu.cn/sheets/shtXXX" \
102
102
  --sheet-name "Sheet1" --regex --find "(\\d{4})-(\\d{2})" --replacement "$2/$1" --dry-run
103
103
  ```
104
104
 
105
- > `+cells-replace` 虽然 Risk = write,但范围大或正则错可能改一堆。**强烈推荐工作流**:先 `+cells-search` 看匹配数,再 `+cells-replace --dry-run` 预览,最后真正执行。
105
+ > `+cells-replace` 虽然 Risk = write,但范围大或正则写错可能批量修改大量非目标单元格。**建议工作流**:先 `+cells-search` 看匹配数,再 `+cells-replace --dry-run` 预览,最后真正执行。
106
106
 
107
107
  ### Validate / DryRun / Execute 约束
108
108
 
109
109
  - `Validate`:XOR 公共四件套;`--find` 非空;正则模式下 `--find` 必须是合法正则。
110
110
  - `DryRun`:`+cells-search` 输出请求模板;`+cells-replace` 额外返回预估替换数(`would_replace_count`)。
111
- - `Execute`:写后不自动回读;如需确认,自行用 `+cells-search` 复查旧值是否已不再命中。
111
+ - `Execute`:替换后必须用 `+cells-search` 复查旧值剩余命中,并回读首、中、末代表性单元格;目标是旧值命中归零或明确列出未替换项。
@@ -10,6 +10,10 @@
10
10
 
11
11
  不可逆的影响必须先在回复中告知用户,得到确认再执行。
12
12
 
13
+ ## 合并安全契约(按模块 / 分组展示)
14
+
15
+ 合并前先读目标列的完整连续区域;只有同值且连续、且非左上角单元格没有值 / 公式 / 批注 / 数据验证或需保留的独立样式时,才可合并。空值、值变化、上级模块变化或上述有效内容立即断组。先读取既有 merges,禁止与现有合并区交叠或跨组扩张;执行前记录每组 `range + 左上角原文`,从下往上或一次批量提交。完成后用 `+sheet-info --include merges` 核范围,并用 `+cells-get` 确认左上角文本未丢、组外边界未合并。
16
+
13
17
  ## 使用场景
14
18
 
15
19
  读写。管理子表结构与布局。本 reference 覆盖 9 个 shortcut(按用途分两类):
@@ -39,7 +43,7 @@
39
43
  **常见配置错误(必须注意)**:
40
44
  - **插入列直接用字母**:`+dim-insert` 的 `--position` 在列场景直接传字母(如 `C`),不要把列字母换算成 0-based 索引
41
45
  - **插入后引用偏移**:插入行/列后,原有数据的行号 / 列字母会发生偏移。如果插入后还需要对原有区域执行写入操作,必须重新计算偏移后的位置
42
- - **删除行列前先确认范围**:删除操作不可逆,执行前应确认 `--range` 精确无误。可先用 `+csv-get` 读取目标区域验证内容(`+csv-get` / `+cells-get` 见 `lark-sheets-read-data`)
46
+ - **删除行列前先确认范围**:删除操作不可逆,执行前应确认 `--range` 精确无误。可先用 `+csv-get` 读取目标区域验证内容(`+csv-get` / `+cells-get` 见 `references/lark-sheets-read-data.md`)
43
47
  - **"在 D 列左侧新增一列"的正确写法**:`--position D --count 1`(新列插在 D 列之前);要继承左侧列样式加 `--inherit-style before`。不要把 `--inherit-style after` 当成“插到 D 列右侧”,它不是插入方向参数。
44
48
  - **`+dim-move` 同维度约束**:`--source-range` 是行区间时 `--target` 必须是行号(数字),是列区间时 `--target` 必须是列字母——不可一行一列混用
45
49
  - **插入列后必须检查多行表头合并区域**:很多表格有 2-3 行的合并表头。插入列后,原有的合并区域不会自动扩展到新列。必须先用 `+sheet-info --include merges` 读取合并区域,插入后将跨越插入位置的合并区域重新设置(用 `+cells-{merge|unmerge}`),否则新列的表头会是空的、格式不连续
@@ -196,7 +200,7 @@ lark-cli sheets +dim-move --url "..." --sheet-id "$SID" --source-range "C:F" --t
196
200
 
197
201
  ### `+rows-resize` / `+cols-resize`
198
202
 
199
- > ⚠️ 这两条 shortcut 来自 `lark-sheets-range-operations` 的 `+rows-resize / +cols-resize` tool(分组在"工作表"是为了发现性)。详细参数和示例在 `lark-sheets-range-operations.md`。
203
+ > ⚠️ 这两条 shortcut 来自 `references/lark-sheets-range-operations.md` 的 `+rows-resize / +cols-resize` tool(分组在"工作表"是为了发现性)。详细参数和示例在 `references/lark-sheets-range-operations.md`。
200
204
  >
201
205
  > 常规写法:行高走 `--range` + `--height <px>`、列宽走 `--range` + `--width <px>`,无需再传 `--type`(等价于 `--type pixel`);多行 / 多列不同尺寸用 map 形态 `--heights` / `--widths`(如 `--widths '{"A":100,"C:E":120}'`)一次调用完成,不要拆多次调用或走 `+batch-update`。`--type standard` / `--type auto` 用于非像素模式,不能与像素 flag 同给。`+cols-resize.--type` 不接受 `auto`(列宽不支持自动适应)。⚠️ 单位是像素(不是 Excel 字符单位 / 磅)。
202
206
 
@@ -218,6 +222,6 @@ lark-cli sheets +dim-freeze --url "..." --sheet-id "$SID" --rows 0 --cols 2
218
222
 
219
223
  ### Validate / DryRun / Execute 约束
220
224
 
221
- - `Validate`:XOR 公共四件套;`--range` / `--source-range` 必须是合法 A1 闭区间(行用数字、列用字母,不可混用);`+dim-insert` 的 `--count` > 0;`+dim-freeze` 至少给 `--rows` / `--cols` 之一;`+dim-move` 的 `--target` 必须与 `--source-range` 同维度(行 vs 列);`+dim-delete` 强制 `--yes` 或 `--dry-run`,`--range` 与 `--ranges` 二选一、`--ranges` 各区间同维度且不可重叠(≤100 个);`+rows-resize` / `+cols-resize` 的统一形态(`--range` + `--height`/`--width` 或 `--type`)与 map 形态(`--heights`/`--widths`)二选一、不可混用;详见 `lark-sheets-range-operations.md`。
225
+ - `Validate`:XOR 公共四件套;`--range` / `--source-range` 必须是合法 A1 闭区间(行用数字、列用字母,不可混用);`+dim-insert` 的 `--count` > 0;`+dim-freeze` 至少给 `--rows` / `--cols` 之一;`+dim-move` 的 `--target` 必须与 `--source-range` 同维度(行 vs 列);`+dim-delete` 强制 `--yes` 或 `--dry-run`,`--range` 与 `--ranges` 二选一、`--ranges` 各区间同维度且不可重叠(≤100 个);`+rows-resize` / `+cols-resize` 的统一形态(`--range` + `--height`/`--width` 或 `--type`)与 map 形态(`--heights`/`--widths`)二选一、不可混用;详见 `references/lark-sheets-range-operations.md`。
222
226
  - `DryRun`:写操作输出"将要 PATCH 的目标范围 + 目标参数"。
223
- - `Execute`:写后不自动回读;如需确认,自行调用 `+sheet-info --include row_heights,col_widths,hidden_rows,hidden_cols,groups,frozen` 查看受影响的范围。
227
+ - `Execute`:写后必须调用 `+sheet-info --include row_heights,col_widths,hidden_rows,hidden_cols,groups,frozen,merges`,按本次结构动作核对受影响范围。
@@ -91,7 +91,7 @@ _创建/更新/部分删除的迷你图属性_
91
91
  # 列出整张子表的所有迷你图组
92
92
  lark-cli sheets +sparkline-list --url "..." --sheet-id "$SID"
93
93
 
94
- # 钉到单组:返回该组每一项的 sparkline_id(update / partial-delete 必需)
94
+ # 钉到单组:返回该组每一项的 sparkline_id(update 必需)
95
95
  lark-cli sheets +sparkline-list --url "..." --sheet-id "$SID" --group-id "grpA"
96
96
  ```
97
97
 
@@ -147,4 +147,4 @@ lark-cli sheets +sparkline-delete --url "..." --sheet-id "$SID" --group-id "grpA
147
147
  - `--properties`(仅 `+sparkline-create` / `+sparkline-update`)顶层只接 `config`(同组共享样式)和 `sparklines`(迷你图项数组);`+sparkline-create` 要求每个 `sparklines[i]` 含 `position` 与 `source`(或 `source_range`,二选一)。
148
148
  - `+sparkline-delete` 强制 `--yes` 或 `--dry-run`。
149
149
  - `DryRun`:写操作输出"将要 POST/PATCH/DELETE 的 sparkline group 请求模板"。
150
- - `Execute`:写后不自动回读;如需确认,自行调用 `+sparkline-list --group-id <id>` 查看 `config` / `sparklines`。
150
+ - `Execute`:create/update 后必须调用 `+sparkline-list --group-id <id>` 核对 config、项目数量、source 与 position;delete 后 list 确认目标组不存在。