From 4579a5713da58d170c1a1c85deb63b8ff32b6e78 Mon Sep 17 00:00:00 2001 From: "liuxin.0319" Date: Wed, 1 Jul 2026 17:31:03 +0800 Subject: [PATCH] chore: sync lark-doc skill from online-doc --- skills/lark-doc/SKILL.md | 7 +- skills/lark-doc/references/lark-doc-create.md | 10 +- skills/lark-doc/references/lark-doc-update.md | 10 +- skills/lark-doc/references/lark-doc-xml.md | 4 +- .../style/lark-doc-create-workflow.md | 55 ++++---- .../references/style/lark-doc-style.md | 115 ++++++--------- .../style/lark-doc-update-workflow.md | 41 ++++-- skills/lark-doc/scripts/count_chars.py | 133 ++++++++++++++++++ 8 files changed, 251 insertions(+), 124 deletions(-) create mode 100644 skills/lark-doc/scripts/count_chars.py diff --git a/skills/lark-doc/SKILL.md b/skills/lark-doc/SKILL.md index 10b6876d..32c3c5e0 100644 --- a/skills/lark-doc/SKILL.md +++ b/skills/lark-doc/SKILL.md @@ -24,12 +24,12 @@ lark-cli docs +update --doc "文档URL或token" --command append --content '

**CRITICAL — 执行对应操作前,MUST 先用 Read 工具读取以下文件,缺一不可:** 1. [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md) — 认证、权限处理、全局参数(所有操作通用) 2. **读取文档(`docs +fetch`)** → 必读 [`lark-doc-fetch.md`](references/lark-doc-fetch.md)(`--scope` / `--detail` 选择、局部读取策略、`` / `` 输出结构) -3. **创建或编辑文档内容** → 必读 [`lark-doc-xml.md`](references/lark-doc-xml.md)(XML 语法规则,仅当用户明确要求 Markdown 时改读 [`lark-doc-md.md`](references/lark-doc-md.md))和 [`lark-doc-style.md`](references/style/lark-doc-style.md)(元素选择、丰富度规则、颜色语义);从零创建时加读 [`lark-doc-create-workflow.md`](references/style/lark-doc-create-workflow.md);编辑已有文档时加读 [`lark-doc-update.md`](references/lark-doc-update.md) 和 [`lark-doc-update-workflow.md`](references/style/lark-doc-update-workflow.md) +3. **创建或编辑文档内容** → 必读 [`lark-doc-xml.md`](references/lark-doc-xml.md)(XML 语法规则,仅当用户明确要求 Markdown 时改读 [`lark-doc-md.md`](references/lark-doc-md.md))和必读 [`lark-doc-style.md`](references/style/lark-doc-style.md)(写作原则:默认段落、按体裁、组件克制);从零创建时加读 [`lark-doc-create-workflow.md`](references/style/lark-doc-create-workflow.md);编辑已有文档时加读 [`lark-doc-update.md`](references/lark-doc-update.md) 和 [`lark-doc-update-workflow.md`](references/style/lark-doc-update-workflow.md) **未读完以上文件就执行相应操作会导致参数选择错误或格式错误。** > **格式选择规则(全局):** -> - **创建 / 导入场景**(`docs +create`,或 `docs +update --command append/overwrite` 的整段写入):XML 和 Markdown 都可以。用户提供 `.md` 本地文件、或明确说"导入 Markdown"时,直接用 Markdown;否则默认 XML(可用 callout、grid、checkbox 等富 block)。 +> - **创建 / 导入场景**(`docs +create`,或 `docs +update --command append/overwrite` 的整段写入):XML 和 Markdown 都可以。用户提供 `.md` 本地文件、或明确说"导入 Markdown"时,直接用 Markdown;否则默认 XML。 > - **精准编辑场景**(`docs +update` 的 `str_replace` / `block_insert_after` / `block_replace` / `block_delete` / `block_move_after` 等局部精修指令):优先使用 XML(`--doc-format xml`,即默认值)。XML 能稳定表达 block 结构和样式,局部精修更可控;不要因为 Markdown 更简单就自行切换。 ## 快速决策 @@ -39,7 +39,8 @@ lark-cli docs +update --doc "文档URL或token" --command append --content '

- 连续执行多个文档写操作时,必须按 [`lark-doc-update.md`](references/lark-doc-update.md) 的「Block ID 生命周期」判断旧 block ID 是否还能复用;`overwrite` / `block_replace` / `block_delete` 后不要复用受影响的旧 ID,插入 / 复制后要重新 fetch 才能拿到新 block ID - 用户需要在文档内**创建、复制或移动**资源块(画板、电子表格、多维表格等)时,必须先读取 [`lark-doc-xml.md`](references/lark-doc-xml.md) 的「三、资源块」章节 - 写文档时,由内容和用户意图决定表达形式;流程、架构、路线图、关键指标等信息可以使用画板,但不要默认把重要信息都画板化 -- 新增画板必须隔离到 SubAgent:简单图由 SubAgent 直接插入 `完整 SVG`,不读 `lark-whiteboard`;复杂图才由主 Agent 先建 ``,再启动 SubAgent 读取 `lark-whiteboard` 写入 +- 用户给了明确字数要求(写 N 字 / x-y 字 / x 字左右 / 上下浮动)→ 生成或改写后用 `scripts/count_chars.py`(lark-doc skill 根的 `scripts/` 下,对齐飞书「总字数」)校验,按 create/update workflow 的「字数校验」闭环处理(最多 2 轮,不达标如实告知) +- 新增画板:思维导图/时序图/类图/饼图/甘特图用 Mermaid,由**主 Agent 直接插入** ``,无需 SubAgent;其他图表隔离到 SubAgent——简单图由 SubAgent 直接插入 `完整 SVG`(不读 `lark-whiteboard`),复杂图由主 Agent 先建 ``,再启动 SubAgent 读取 `lark-whiteboard` 写入 - 用户说"看一下文档里的图片/附件/素材""预览素材" → 用 `lark-cli docs +media-preview` - 用户明确说"下载素材" → 用 `lark-cli docs +media-download` - 用户明确说"下载/更新/删除文档封面图" → 用 `lark-cli docs +resource-download/+resource-update/+resource-delete --type cover` diff --git a/skills/lark-doc/references/lark-doc-create.md b/skills/lark-doc/references/lark-doc-create.md index 17fa6bc2..53f6be78 100644 --- a/skills/lark-doc/references/lark-doc-create.md +++ b/skills/lark-doc/references/lark-doc-create.md @@ -2,14 +2,14 @@ > **前置条件(MUST READ):** 生成文档内容前,必须先用 Read 工具读取以下文件,缺一不可: > 1. [`lark-doc-xml.md`](lark-doc-xml.md) — XML 语法规则(使用 Markdown 格式时改读 [`lark-doc-md.md`](lark-doc-md.md)) -> 2. [`lark-doc-style.md`](style/lark-doc-style.md) — 排版指南(元素选择、丰富度规则、颜色语义) -> 3. [`lark-doc-create-workflow.md`](style/lark-doc-create-workflow.md) — 从零创作工作流(Code-Act Loop、并行执行策略) +> 2. [`lark-doc-style.md`](style/lark-doc-style.md) — 写作原则(默认段落、按体裁、组件克制) +> 3. [`lark-doc-create-workflow.md`](style/lark-doc-create-workflow.md) — 从零创作工作流(Code-Act Loop、单 Agent 串行撰写) > > **未读完以上文件就生成内容会导致格式错误。** 从 XML(默认)或 Markdown 内容创建一个新的飞书云文档。 -> **⚠️ 格式选择规则:** 创建 / 导入场景下 XML 和 Markdown 都可以——用户提供 `.md` 本地文件、或明确说"导入 Markdown"时,直接用 Markdown;没有明确指示时默认 XML(表达能力更强,支持 callout、grid、checkbox 等富 block 类型)。不要在用户没要求的情况下主动从 XML 切到 Markdown,也不要在用户已给出 Markdown 时强行改成 XML。 +> **⚠️ 格式选择规则:** 创建 / 导入场景下 XML 和 Markdown 都可以——用户提供 `.md` 本地文件、或明确说"导入 Markdown"时,直接用 Markdown;没有明确指示时默认 XML(表达能力更强,可承载更丰富的结构化内容)。不要在用户没要求的情况下主动从 XML 切到 Markdown,也不要在用户已给出 Markdown 时强行改成 XML。 ## 命令 @@ -71,8 +71,8 @@ lark-cli docs +create --doc-format markdown --title "项目计划" --content $'# ## 参考 -- [`lark-doc-create-workflow.md`](style/lark-doc-create-workflow.md) — 从零创作工作流(Code-Act Loop、并行执行策略) -- [`lark-doc-style.md`](style/lark-doc-style.md) — 文档样式指南(元素选择 + 丰富度规则 + 颜色语义) +- [`lark-doc-create-workflow.md`](style/lark-doc-create-workflow.md) — 从零创作工作流(Code-Act Loop、单 Agent 串行撰写) +- [`lark-doc-style.md`](style/lark-doc-style.md) — 文档写作原则(默认段落、按体裁、组件克制) - [`lark-doc-xml.md`](lark-doc-xml.md) — XML 语法规范 - [`lark-doc-fetch.md`](lark-doc-fetch.md) — 获取文档 - [`lark-doc-update.md`](lark-doc-update.md) — 更新文档 diff --git a/skills/lark-doc/references/lark-doc-update.md b/skills/lark-doc/references/lark-doc-update.md index 918408fa..a2b37448 100644 --- a/skills/lark-doc/references/lark-doc-update.md +++ b/skills/lark-doc/references/lark-doc-update.md @@ -3,8 +3,8 @@ > **前置条件(MUST READ):** 生成文档内容前,必须先用 Read 工具读取以下文件,缺一不可: > 1. [`lark-doc-xml.md`](lark-doc-xml.md) — XML 语法规则(使用 Markdown 格式时改读 [`lark-doc-md.md`](lark-doc-md.md)) -> 2. [`lark-doc-style.md`](style/lark-doc-style.md) — 排版指南(元素选择、丰富度规则、颜色语义) -> 3. [`lark-doc-update-workflow.md`](style/lark-doc-update-workflow.md) — 改写增强工作流(Code-Act Loop、并行执行策略) +> 2. [`lark-doc-style.md`](style/lark-doc-style.md) — 写作原则(默认段落、按体裁、组件克制) +> 3. [`lark-doc-update-workflow.md`](style/lark-doc-update-workflow.md) — 改写增强工作流(Code-Act Loop、单 Agent 串行改写) > > **未读完以上文件就生成内容会导致格式错误。** @@ -232,7 +232,7 @@ lark-cli docs +update --doc "" --command str_replace \ > **`docs +update` 不能直接编辑已有画板的内容。** 本命令只能**新增**画板块;要修改已有画板,先用 `docs +fetch` 取到 ``,再按 [`lark-doc-whiteboard.md`](lark-doc-whiteboard.md) 启动 SubAgent 读取 [`lark-whiteboard`](../../lark-whiteboard/SKILL.md) 并写入。 -画板的语法选型与插入示例见 [`lark-doc-style.md`](style/lark-doc-style.md) 的「画板语法与插入」章节。 +画板的语法选型与插入示例见 [`lark-doc-xml.md`](lark-doc-xml.md) 与 [`lark-doc-whiteboard.md`](lark-doc-whiteboard.md)。 ## 最佳实践 @@ -252,8 +252,8 @@ lark-cli docs +update --doc "" --command str_replace \ ## 参考 -- [`lark-doc-update-workflow.md`](style/lark-doc-update-workflow.md) — 改写增强工作流(Code-Act Loop、并行执行策略) -- [`lark-doc-style.md`](style/lark-doc-style.md) — 文档样式指南(元素选择 + 丰富度规则 + 颜色语义) +- [`lark-doc-update-workflow.md`](style/lark-doc-update-workflow.md) — 改写增强工作流(Code-Act Loop、单 Agent 串行改写) +- [`lark-doc-style.md`](style/lark-doc-style.md) — 文档写作原则(默认段落、按体裁、组件克制) - [`lark-doc-xml.md`](lark-doc-xml.md) — XML 语法规范 - [`lark-doc-fetch.md`](lark-doc-fetch.md) — 获取文档 - [`lark-doc-create.md`](lark-doc-create.md) — 创建文档 diff --git a/skills/lark-doc/references/lark-doc-xml.md b/skills/lark-doc/references/lark-doc-xml.md index 7484f428..3cacba5e 100644 --- a/skills/lark-doc/references/lark-doc-xml.md +++ b/skills/lark-doc/references/lark-doc-xml.md @@ -13,8 +13,8 @@ p, h1-h9, ul, ol, li, table, thead, tbody, tr, th, td, blockquote, pre, code, hr ## 容器标签 |标签|说明|关键属性| |-|-|-| -| `` | 高亮框,子块仅支持文本、标题、列表、待办、引用 | `emoji`(默认 bulb), `background-color`, `border-color`, `text-color` | -| `` + `` | 分栏布局,各列 width-ratio 之和为 1 | `width-ratio` | +| `` | 高亮框,子块仅支持文本、标题、列表、待办、引用。**强提醒专用,使用前先看 `lark-doc-style.md` 的写作原则** | `emoji`(默认 bulb), `background-color`, `border-color`, `text-color` | +| `` + `` | 分栏布局,各列 width-ratio 之和为 1。**使用前先看 `lark-doc-style.md` 的写作原则** | `width-ratio` | | `` | 嵌入画板 | `type`: `blank` \| `mermaid` \| `plantuml` \| `svg` | | `

` | (代码块,内含 `code`)| `lang`, `caption` |
 | `
` | 视图容器 | `view-type` | diff --git a/skills/lark-doc/references/style/lark-doc-create-workflow.md b/skills/lark-doc/references/style/lark-doc-create-workflow.md index d845e91c..6450a4e4 100644 --- a/skills/lark-doc/references/style/lark-doc-create-workflow.md +++ b/skills/lark-doc/references/style/lark-doc-create-workflow.md @@ -7,7 +7,7 @@ 通过自适应的 **Code-Act Loop** 驱动文档创作,而非固定模板式的工作流。每次任务都循环执行: 1. **Plan(规划)** — 根据用户目标和文档当前状态,评估下一步该做什么 -2. **Execute(执行)** — 运行相应的 `lark-cli docs` 命令,或 **spawn** Agent 子任务并行推进 +2. **Execute(执行)** — 由主 Agent 自己运行 `lark-cli docs` 命令推进正文;仅画板渲染按需隔离到 SubAgent(见步骤三) 3. **Observe(观察)** — 检查命令输出,验证正确性,确认内容是否满足用户目标 4. **Iterate(迭代)** — 如需调整,回到 Plan 继续循环 @@ -16,44 +16,51 @@ ## 典型 Code-Act Loop 流程 -### 步骤一:规划与初始创建(串行) +### 步骤一:规划与撰写(单 Agent 串行) + +正文由主 Agent 一人从规划到撰写从头到尾完成,**不拆分给并行子 Agent 分节写**——文档要靠全局视角保证前后连贯、不重复、不矛盾;分节并行会丢掉这个视角,也无法执行「全文级」的组件约束(这类约束没有任何单节子 Agent 看得到全文)。 1. 分析用户需求:受众、目的、范围 2. 设计大纲:根据任务自然选择结构。可以是短文、纪要、FAQ、方案、报告、清单或其他形式;不要默认套固定章节、固定开头或固定富 block 配比 -3. `docs +create` 创建文档。长文档可**只建骨架**:标题 + 各级标题 + 每节一句占位摘要;短文档可以一次写入完整内容 - - ⚠️ 创建较长文档时,**不要**一次性把完整章节内容塞进 `--content`。超长 `--content` 容易触发字符/参数限制。 - - 完整内容留到步骤二,由各 Agent 用 `block_insert_after --block-id <章节标题 block_id>` 分段写入。 - - ⚠️ **`@file` 路径限制**:`--content @file` 只接受当前工作目录下的相对路径,传绝对路径(如 `@/tmp/xxx.md`)会报 `unsafe file path`。需要落盘时,将文件写在 cwd 下,用完自行清理。 +3. `docs +create` 创建并撰写: + - **短文档**:一次写入完整内容 + - **长文档**:先建骨架(标题 + 各级标题),再由主 Agent **顺序逐节**用 `block_insert_after --block-id <章节标题 block_id>` 补全正文;写完一节再写下一节,始终带着已写内容的上下文,保证衔接、不重复 + - ⚠️ 不要一次性把超长完整内容塞进 `--content`,容易触发字符/参数限制;长文按节分次写入 + - ⚠️ 同一节内多次插入时,要锚到**上一个新插入的 block**(按 [`lark-doc-update.md`](../lark-doc-update.md) 的「Block ID 生命周期」),否则反复锚同一个标题会让段落顺序颠倒 + - ⚠️ 若先建骨架写了占位摘要,补正文时**删除占位摘要**,不要留残渣 + - ⚠️ **`@file` 路径限制**:`--content @file` 只接受当前工作目录下的相对路径,传绝对路径(如 `@/tmp/xxx.md`)会报 `unsafe file path`。需要落盘时,将文件写在 cwd 下,用完自行清理 -### 步骤二:分段撰写(并行 Agent) +### 步骤二:整合审查与画板识别(串行) -4. Spawn Agent 并行撰写各章节。每个 Agent 需收到: - - 文档 token、负责的章节范围、用户目标、目标读者和已有风格线索 - - `lark-doc-xml.md` 和 `lark-doc-style.md` 的完整路径(Agent 须先读取) - - 使用 `block_insert_after --block-id <章节标题 block_id>` 写入对应章节内容 +4. `docs +fetch --api-version v2 --detail with-ids` 获取文档,审查整体效果 +5. 评估内容是否满足用户目标:事实是否完整、结构是否清楚、语气是否匹配、是否保留必要素材;检查跨节有无重复、矛盾或断流。再按 `lark-doc-style.md` 的写作原则**逐节核对**,发现问题就地定向修正: + - **去列举**:叙述性内容(背景 / 现状 / 认识 / 分析 / 成效等)是否被做成了列举?是则改成段落;列举只留给真正并列的具体措施 / 步骤 / 清单。 + - **查"通篇一是二是"**:是不是每个方面 / 每节都齐刷刷"一是 / 二是 / 三是"、几乎没有叙述段落?是则给背景 / 认识 / 分析 / 过渡补上段落,「一是 / 二是」只收到列具体问题 / 措施那一处(纯清单 / 台账类除外)。 + - **查编号**:全篇是否一套、不跳号、不跳级;**有没有中文序号 + 阿拉伯小数混用(一、+ 1.1)**。 + - **查呈现**:成行成列的数据是否该用表格却写成了段落 / "A+B+C"串?"小标题 + 一句话"的小项是否被升成了标题?是则按 `lark-doc-style.md` §二改成表格 / 标签行 / 加粗引导句段落。 + - **查组件**:高亮块 / 分栏 / 画板 / 颜色是否克制、符合体裁。 +6. **画板识别**:逐章节扫描,判断是否有段落用图明显比文字更易懂(流程 / 架构 / 时间线 / 对比 / 占比等,见 `lark-doc-style.md` 的画板原则)。默认用文字,只有确需图示才记录需要插图的章节、推荐画板类型、mermaid/SVG 路径和用于画图的源内容 -### 步骤三:整合审查与画板识别(串行) +### 步骤三:画板处理与润色 -5. `docs +fetch --detail with-ids` 获取文档,审查整体效果 -6. 评估内容是否满足用户目标:事实是否完整、结构是否清楚、语气是否匹配、是否保留必要素材 -7. **画板意图识别**:逐章节扫描,按 `lark-doc-style.md`「画板意图识别」表判断是否有段落适合用图表达。重要信息优先画板化,记录需要插图的章节、推荐画板类型、mermaid/SVG 路径和用于画图的源内容 +7. **优先处理步骤二识别出的画板需求**:参考 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的方式插入图表画板。画板渲染仍隔离到 SubAgent(见下方「画板 SubAgent 子任务要求」),正文本身不交给子 Agent +8. 由**主 Agent 自行润色**(不另起内容子 Agent,正文始终一人维护):文字密集且不易读时,优先拆段、加小标题或调整顺序——叙述内容保持成段,**不要默认改成列表**,只有确属并列要点 / 步骤才用列表(见 `lark-doc-style.md`);只有确实存在行列数据时才用 ``。其余富 block 的取舍一律遵循 `lark-doc-style.md` 的写作原则,不主动堆叠。需要明显分隔的主题可补充 `
`,不强制章节间都使用。本地图片使用 `docs +media-insert` 插入 -### 步骤四:画板处理与润色(并行 Agent) +### 步骤四:字数校验(无明确字数要求则跳过) -8. **优先处理步骤三识别出的画板需求**: - 参考 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md)中的方式,插入图表画板。 -9. Spawn 内容改写 Agent 定向润色: - - 文字密集且不易读时,优先拆段、改列表、增加小标题或调整顺序;只有确实存在行列数据、并列对比或强提醒信息时,才考虑 `
` / `` / `` - - 需要明显分隔的主题可补充 `
`,不强制章节间都使用 - - 本地图片使用 `docs +media-insert` 插入 +**仅当**用户给了明确字数要求(写 N 字 / x-y 字 / x 字左右 / 上下浮动)时执行;否则**跳过本步**。字数必须用脚本量,不要自己估。 +1. 把要求归一成参数:`>x`→`--min x`;` <上面的目标参数>`(脚本在 lark-doc skill 根的 `scripts/` 下) +3. 看输出 `verdict`:`pass` 即通过;`under` → 在最该展开的节补**实质内容**(非注水);`over` → 从最长/最冗余处删减。改完**重新跑脚本复测** +4. **最多 2 轮**。2 轮后仍不达标:停止,不得为达标而注水或删关键内容;如实汇报【目标区间 / 当前字数 / 差值与方向 / 已试 2 轮 / 未达原因】并交付文档链接,**禁止谎称达标** ## Agent 子任务要求 -内容改写 Agent 必须收到:文档 token、章节范围(标题/block ID)、`lark-doc-xml.md` 和 `lark-doc-style.md` 路径、用户目标/风格要求、具体的 `docs +update` command 和 `--block-id`。 +## 画板 SubAgent 子任务要求 Mermaid 图由主 Agent 直接插入 `...`,无需 SubAgent。 -SVG SubAgent 必须收到:文档 token、插入位置(标题/block ID)、图表目标、源内容片段、`lark-doc-xml.md` 路径,以及[lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的 "SVG 设计 Workflow" 指南。它只负责插入一个 `...`,不改其他正文,也不读取 `lark-whiteboard`。 +SVG SubAgent 必须收到:文档 token、插入位置(标题/block ID)、图表目标、源内容片段、`lark-doc-xml.md` 路径,以及 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的 "SVG 设计 Workflow" 指南。它只负责插入一个 `...`,不改其他正文,也不读取 `lark-whiteboard`。 已有画板更新 SubAgent 必须收到:board_token、图表目标、推荐画板类型、源内容片段、[`../../../lark-whiteboard/SKILL.md`](../../../lark-whiteboard/SKILL.md) 路径。它只负责写入画板,不改文档正文。 diff --git a/skills/lark-doc/references/style/lark-doc-style.md b/skills/lark-doc/references/style/lark-doc-style.md index 1a09a80f..70799f7e 100644 --- a/skills/lark-doc/references/style/lark-doc-style.md +++ b/skills/lark-doc/references/style/lark-doc-style.md @@ -1,86 +1,59 @@ -# 文档表达组件参考 +# 飞书文档写作原则 -本文件说明飞书文档可用的结构化表达方式,供模型在需要时选择。它不是固定模板,也不是强制排版规范。 +写飞书文档,像一个该领域资深的人类作者那样写,而不是把内容"装配"成组件。 +本文只讲"何时用、什么风格";具体标签 / 命令语法见 [`lark-doc-xml.md`](../lark-doc-xml.md)。 -默认原则:优先理解用户目标、受众、素材形态和已有文档风格,由模型自主决定结构、语气和视觉呈现。只有当用户明确要求“美化、重排版、做成报告/方案/看起来更专业”等,或内容本身明显需要结构化承载时,才主动使用下列组件。 +## 一、用户明确要求优先 -## 一、核心原则 +用户点名要某种格式——高亮块、分栏、列表、某编号体例、表格、画板、某模板、某已有文档的风格——**一律照用户的来,下面的"默认克制"全部让位**。用户给了样例或已有文档,就沿用它的结构与语气。 -1. **服务内容,而非套模板**:先判断信息最自然的表达方式,再选择段落、列表、表格、分栏、画板等元素 -2. **尊重用户风格**:用户给出样例、语气、结构或已有文档时,优先沿用;没有要求时不强行使用固定开头、固定章节或固定视觉组件 -3. **适度结构化**:结构化 block 用于降低理解成本,不为了“丰富”而堆叠 -4. **保持一致但不过度统一**:同类信息可使用相近表达,但允许因内容差异采用不同形式 -5. **图示服务理解**:流程、架构、对比、风险、路线图、指标趋势等内容在图示明显降低理解成本时,可使用画板表达 +## 二、默认写连贯段落 -## 二、元素选择指南 +用户没指定时,**默认是连贯段落**;其余按内容类型分流,别一律"少用结构",也别什么都升标题: -需要图表时,按类型选择插入方式:思维导图/时序图/类图/饼图/甘特图可用 `` 直接内嵌;其他新图表可启动 SubAgent 插入 `完整 SVG`;只有编辑**已有**画板时才调用 **lark-whiteboard** skill。 +| 内容 | 用什么 | ❌ 别 | +|---|---|---| +| 叙述、论证、分析、说明 | **连贯段落** | 拆成列举 | +| 真·行列数据(预算、指标、对比、排期、字段说明) | **表格** | 写成段落或"A+B+C"串 | +| 字段:值(主题、时长、负责人等,少量) | **加粗标签行**或一句话 | 每字段一个标题 | +| 方法 / 措施 + 每项一段描述 | **加粗引导句段落**(「**全程督导。**…」) | 每项升标题 | +| 纯短并列项(无描述,如材料清单) | 列表 | — | +| 章节(内容成块、需在目录导航) | 标题层级 | — | -| 场景 | 可选表达方式 | -|--------------------------------------------|---------------------------------------| -| 少数需要视觉提醒的短句,如风险、限制、待确认事项或关键提醒 | 需要视觉提醒时可用 ``;普通结论、摘要或章节导语优先使用段落、列表、小标题或加粗 | -| 方案对比 / 优劣势 / Before vs After | 简短对比可用段落、列表或 ``;维度较多且需要逐项比较时再考虑 `
` 或画板 | -| 简短低风险对比 | `` 2 列分栏 | -| 需要按行列精确比较或查阅的数据,如指标、清单、字段说明、排期 | 可用 `
`;短要点、步骤、摘要或普通说明优先使用段落、列表或小标题 | -| 任务清单 / 检查项 | `` | -| 代码片段 | `
`         |
-| 引用 / 公式                                    | `
` / `` | -| 操作入口 / 跳转链接 | `
` / `` / `` 承载 -- 确定需要插入哪些图表后,参照 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的方式,插入图表画板。 +## 五、飞书特有组件,克制使用 -## 三、颜色语义 +- **高亮块 ``**:很重的强提醒信号,**默认不用**;只给"不提醒就会出错 / 遗漏"的关键项,全文极少(0~1 个),不要每节导语 / 结论都做成高亮块。 +- **分栏 ``**:仅左右信息量相当、确需并排对照的短内容;否则用段落或表格。 +- **画板**:默认用文字,只在**图示明显比文字更易懂**(流程、架构、时间线、对比、占比等)或用户要求时才用。怎么插、用哪种类型见 [`lark-doc-xml.md`](../lark-doc-xml.md) 与 [`lark-doc-whiteboard.md`](../lark-doc-whiteboard.md)。 +- **颜色**:默认朴素、不上色;需要时保持语义一致(信息蓝 / 成功绿 / 警告红 / 注意黄),不为装饰上色。可用色见 [`lark-doc-xml.md`](../lark-doc-xml.md) 的「美化系统」。 -如果使用颜色,建议保持语义一致;不需要颜色时可以保持朴素文本风格: +## 六、写完自检 -| 语义 | emoji 前缀 | callout 背景色 | 文字色 | -|-|-|-|-| -| 信息、说明 | ℹ️ "说明:" | `light-blue` | `blue` | -| 成功、推荐 | ✅ "推荐:" | `light-green` | `green` | -| 警告 / 错误 / 风险 | ⚠️❌ | `light-red` | `red` | -| 注意、待确认 | ❗"注意:" | `light-yellow` | `yellow` | -| 中性、辅助 | — | `light-gray` | — | - -- 表头可使用 `background-color="light-gray"`,也可以保持默认样式 -- 关键指标如使用 `` 突出,建议同时用 ↑↓ 或 +/- 标注方向(色觉无障碍) - -## 四、排版规范 - -- 标题层级、段落长度、列表嵌套和 Grid 列数应以可读性为准,避免过深层级和过宽分栏 -- 文档开头可以是结论、背景、摘要、问题陈述、目录或直接正文,不强制使用 `` - -## 五、质量自检 - -生成内容后可以从以下角度自检,但不要把这些项当作硬性比例或固定模板: - -| 指标 | 自检问题 | -|-|-| -| 信息表达 | 当前结构是否符合用户目标,而不是套用固定报告模板? | -| 阅读负担 | 是否有段落过长、层级过深、表格过宽或组件过多的问题? | -| 风格匹配 | 是否延续了用户给定样例或已有文档风格? | -| 组件必要性 | callout、grid、table、whiteboard 等是否真的提升理解? | -| 保真度 | 改写时是否保留了原文事实、引用、图片、附件和资源块? | +交付前快速回看: +- 该成段的叙述是否被拆成了列表 / 序号?是否**每节都机械"一是 / 二是"、缺叙述**? +- 成行成列的**数据是否该用表格**、却写成了段落或"A+B+C"串? +- **"小标题 + 一句话"的小项是否被升成了标题**(目录里一堆没信息量的条目)? +- 编号是否全篇一套、**没有中文 + 阿拉伯混用(一、+ 1.1)**、无跳号跳级? +- 高亮块 / 分栏 / 画板 / 颜色是否克制、符合体裁?引用 / 图片 / 资源块是否保留?用户点名要的格式是否照做? diff --git a/skills/lark-doc/references/style/lark-doc-update-workflow.md b/skills/lark-doc/references/style/lark-doc-update-workflow.md index 9ff07c4d..84fb7f61 100644 --- a/skills/lark-doc/references/style/lark-doc-update-workflow.md +++ b/skills/lark-doc/references/style/lark-doc-update-workflow.md @@ -5,7 +5,7 @@ ## 核心方法论 — Code-Act Loop 通过自适应的 **Code-Act Loop** 驱动文档改写,而非固定模板式的工作流。每次任务都循环执行: 1. **Plan(规划)** — 根据用户目标和文档当前状态,评估下一步该做什么 -2. **Execute(执行)** — 运行相应的 `lark-cli docs` 命令,或 **spawn** Agent 子任务并行推进 +2. **Execute(执行)** — 由主 Agent 自己运行 `lark-cli docs` 命令推进改写;仅画板渲染按需隔离到 SubAgent(见步骤二) 3. **Observe(观察)** — 检查命令输出,验证正确性,确认内容是否满足用户目标 4. **Iterate(迭代)** — 如需调整,回到 Plan 继续循环 @@ -23,33 +23,46 @@ - 需要精确跨节区间 → `docs +fetch --scope range --start-block-id xxx --end-block-id yyy`(或 `--end-block-id -1` 读到末尾) - 用户只给了模糊关键词 → `docs +fetch --scope keyword --keyword xxx --context-before 1 --context-after 1 --detail with-ids` - 用户明确要改整篇 → `docs +fetch --detail with-ids` - - 详见 [`lark-doc-fetch.md`](../lark-doc-fetch.md) "意图引导:选择正确的 --scope" + - 详见 [`lark-doc-fetch.md`](../lark-doc-fetch.md) 的「选 `--scope`(读取范围)」 2. 系统性评估:用户想改什么、现有文档风格是什么、哪些内容需要保留、哪些问题影响理解 -3. **画板意图识别**:逐章节扫描,按 `lark-doc-style.md`「画板意图识别」表判断哪些段落的信息适合用图表达。重要信息优先画板化,记录需要插图的章节(block ID)、推荐画板类型、mermaid/SVG路径和源内容片段 +3. **画板识别**:逐章节扫描,判断是否有段落用图明显比文字更易懂(流程 / 架构 / 时间线 / 对比 / 占比等,见 `lark-doc-style.md` 的画板原则)。默认用文字,只有确需图示才记录需要插图的章节(block ID)、推荐画板类型、mermaid/SVG路径和源内容片段 4. 向用户简要说明改进计划(包含识别出的画板机会) -### 步骤二:定向改写(并行 Agent) +### 步骤二:定向改写(单 Agent 串行) -5. **优先处理步骤一识别出的画板候选段落**: - 参考 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md)中的方式,插入图表画板。 -6. Spawn 内容改写 Agent 在不重叠的章节上并行改进,各 Agent 收到文档 token 和特定 block ID: +5. **优先处理步骤一识别出的画板候选段落**:参考 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的方式插入图表画板。画板渲染仍隔离到 SubAgent(见下方「画板 SubAgent 子任务要求」),正文本身不交给子 Agent +6. 由主 Agent **顺序逐节**改写,**不拆分给并行子 Agent**——这样能始终对照全文,保证风格一致、不重复、不顾此失彼,也能执行「全文级」的组件约束: - 沿用或轻微调整已有文档风格,除非用户要求彻底重排版 - - 优先通过重写段落、调整标题、拆分列表或补充小标题提升可读性 - - 富 block 是可选表达手段,不因固定比例而添加;画板类需求只走第 5 步 + - 优先通过重写段落、调整标题、补充小标题提升可读性;叙述内容保持成段,**不要默认改成列表**,只有确属并列要点 / 步骤才用列表(见 `lark-doc-style.md`) + - 富 block 是可选表达手段,不因固定比例而添加,取舍遵循 `lark-doc-style.md` 的写作原则;画板类需求只走第 5 步 ### 步骤三:验证(串行) 7. 获取更新后文档局部内容,检查是否符合用户目标和已有风格 -8. 检查是否满足用户目标并保留原有关键内容;如仍有明显问题则定向修正,向用户呈现结果 +8. 检查是否满足用户目标并保留原有关键内容。再按 `lark-doc-style.md` 的写作原则**逐节核对**,发现问题则定向修正: + - **去列举**:叙述性内容(背景 / 现状 / 认识 / 分析 / 成效等)是否被做成了列举?是则改成段落;列举只留给真正并列的具体措施 / 步骤 / 清单。 + - **查"通篇一是二是"**:是不是每个方面 / 每节都齐刷刷"一是 / 二是 / 三是"、几乎没有叙述段落?是则给背景 / 认识 / 分析 / 过渡补上段落,「一是 / 二是」只收到列具体问题 / 措施那一处(纯清单 / 台账类除外)。 + - **查编号**:全篇是否一套、不跳号、不跳级;**有没有中文序号 + 阿拉伯小数混用(一、+ 1.1)**。 + - **查呈现**:成行成列的数据是否该用表格却写成了段落 / "A+B+C"串?"小标题 + 一句话"的小项是否被升成了标题?是则按 `lark-doc-style.md` §二改成表格 / 标签行 / 加粗引导句段落。 + - **查组件**:高亮块 / 分栏 / 画板 / 颜色是否克制、符合体裁。 -## Agent 子任务要求 + 修正后向用户呈现结果。 -内容改写 Agent 必须收到:文档 token、章节范围(标题/block ID)、`lark-doc-xml.md` 和 `lark-doc-style.md` 路径、用户目标/风格要求、具体的 `docs +update` command 和 `--block-id`。 +### 步骤四:字数校验(无明确字数要求则跳过) + +**仅当**用户给了明确字数要求(写 N 字 / x-y 字 / x 字左右 / 上下浮动)时执行;否则**跳过本步**。字数必须用脚本量,不要自己估。 + +1. 把要求归一成参数:`>x`→`--min x`;` <上面的目标参数>`(脚本在 lark-doc skill 根的 `scripts/` 下) +3. 看输出 `verdict`:`pass` 即通过;`under` → 在最该展开处补**实质内容**(非注水);`over` → 从最长/最冗余处删减。改完**重新跑脚本复测** +4. **最多 2 轮**。2 轮后仍不达标:停止,不得为达标而注水或删关键内容;如实汇报【目标区间 / 当前字数 / 差值与方向 / 已试 2 轮 / 未达原因】并交付文档链接,**禁止谎称达标** + +## 画板 SubAgent 子任务要求 Mermaid 图由主 Agent 直接插入 `...`,无需 SubAgent。 -SVG SubAgent 必须收到:文档 token、插入位置(标题/block ID)、图表目标、源内容片段、`lark-doc-xml.md` 路径,以及[lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的 "SVG 设计 Workflow" 指南。它只负责插入一个 `...`,不改其他正文,也不读取 `lark-whiteboard`。 +SVG SubAgent 必须收到:文档 token、插入位置(标题/block ID)、图表目标、源内容片段、`lark-doc-xml.md` 路径,以及 [lark-doc-whiteboard.md](../lark-doc-whiteboard.md) 中的 "SVG 设计 Workflow" 指南。它只负责插入一个 `...`,不改其他正文,也不读取 `lark-whiteboard`。 已有画板更新 SubAgent 必须收到:board_token、图表目标、推荐画板类型、源内容片段、[`../../../lark-whiteboard/SKILL.md`](../../../lark-whiteboard/SKILL.md) 路径。它只负责写入画板,不改文档正文。 -**上下文节省提示**:Agent 如需在自己负责的章节内重新读取内容,优先用 `docs +fetch --scope section --start-block-id <章节标题id>`(自动覆盖整节),或 `--scope range --start-block-id xxx --end-block-id yyy` 精确区间,只拉自己的章节,不要重复拉全文。 +**上下文节省提示**:主 Agent 改某节时如需重新读取,优先用 `docs +fetch --scope section --start-block-id <章节标题id>`(自动覆盖整节),或 `--scope range --start-block-id xxx --end-block-id yyy` 精确区间,只拉当前章节,不要重复拉全文。 diff --git a/skills/lark-doc/scripts/count_chars.py b/skills/lark-doc/scripts/count_chars.py new file mode 100644 index 00000000..fa0043bb --- /dev/null +++ b/skills/lark-doc/scripts/count_chars.py @@ -0,0 +1,133 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [] +# /// +""" +统计飞书文档「总字数」,对齐飞书官方字数统计规则,用于字数遵循校验。 + +飞书官方规则(总字数):汉字 + 中文标点 + 英文单词 + 数字;英文标点、空格不计。 +计数源:文档 raw_content(飞书已抽取的纯文本,标签已剥离)。 + ⚠️ raw_content 会包含 @文档 / @人 / 卡片等飞书「不计入字数」的嵌入内容文字。 + 对「生成的散文」无影响(不含这些嵌入),与飞书一致; + 读取嵌入密集的已有文档会偏高,那不是本功能的目标场景。 +说明:数字按「位」计(每个数字算 1,与飞书总字符数口径一致); + 总字数含标题(飞书亦含标题)。 + +用法: + # 给文档 token,自动取 raw_content 并计数 + uv run scripts/count_chars.py --doc + # 直接数一段文本(stdin / 文件) + echo "文本" | uv run scripts/count_chars.py + uv run scripts/count_chars.py --file draft.txt + # 带目标校验(任选其一): + uv run scripts/count_chars.py --doc --min 380 --max 420 # 区间 [x,y] + uv run scripts/count_chars.py --doc --min 100 # >=x(>x) + uv run scripts/count_chars.py --doc --max 100 # <=y( --approx 400 # x 左右 = ±10% + +输出 JSON:{total_words, total_chars, target:{min,max}, verdict, gap} + verdict: pass | under | over | none(未给目标) + gap: 距区间还差多少(under/over 均为正数,pass=0)——告诉你要 +gap 或 -gap 字 +""" +import sys +import re +import json +import argparse +import subprocess + + +def fetch_raw_content(doc_id, identity): + cmd = ["lark-cli", "api", "GET", + f"/open-apis/docx/v1/documents/{doc_id}/raw_content", "--as", identity] + try: + out = subprocess.run(cmd, capture_output=True, text=True) + except FileNotFoundError: + sys.exit("未找到 lark-cli:请先安装/配置 lark-cli,或改用 --file / stdin 传入文本") + if out.returncode != 0: + sys.exit(f"取 raw_content 失败: {out.stderr or out.stdout}") + try: + return json.loads(out.stdout)["data"]["content"] + except Exception as e: + sys.exit(f"解析 raw_content 失败: {e}\n{out.stdout[:300]}") + + +def is_hanzi(ch): + o = ord(ch) + return (0x4E00 <= o <= 0x9FFF or 0x3400 <= o <= 0x4DBF + or 0xF900 <= o <= 0xFAFF or 0x20000 <= o <= 0x2A6DF) + + +def is_zh_punct(ch): + o = ord(ch) + # CJK 符号与标点 / 兼容形式 + if 0x3000 <= o <= 0x303F or 0xFE10 <= o <= 0xFE1F or 0xFE30 <= o <= 0xFE4F: + return True + # 全角 ASCII 标点(排除全角数字 FF10-FF19、全角字母 FF21-FF3A / FF41-FF5A) + if (0xFF01 <= o <= 0xFF0F or 0xFF1A <= o <= 0xFF20 + or 0xFF3B <= o <= 0xFF40 or 0xFF5B <= o <= 0xFF65 + or 0xFFE0 <= o <= 0xFFEE): # 全角货币 ¥£¢ 等 + return True + return ch in "·—…“”‘’" + + +def count(text): + hanzi = sum(1 for ch in text if is_hanzi(ch)) + zh_punct = sum(1 for ch in text if is_zh_punct(ch)) + en_words = len(re.findall(r"[A-Za-zÀ-ÿĀ-ɏḀ-ỿ]+", text)) + digits = len(re.findall(r"[0-90-9]", text)) # 数字按位计 + total_words = hanzi + zh_punct + en_words + digits + # 总字符数 = 所有非空白、非控制字符(仅供参考) + total_chars = sum(1 for ch in text if (not ch.isspace()) and ord(ch) >= 0x20) + return total_words, total_chars + + +def judge(words, mn, mx): + if mn is None and mx is None: + return "none", 0 + if mn is not None and words < mn: + return "under", mn - words + if mx is not None and words > mx: + return "over", words - mx + return "pass", 0 + + +def main(): + ap = argparse.ArgumentParser(description="飞书文档总字数统计与字数遵循校验") + ap.add_argument("--doc", help="文档 document_id(自动取 raw_content)") + ap.add_argument("--file", help="从文件读取文本") + ap.add_argument("--as", dest="identity", default="user", help="身份:user(默认)|bot|auto") + ap.add_argument("--min", type=int, help="字数下限(>=x)") + ap.add_argument("--max", type=int, help="字数上限(<=y)") + ap.add_argument("--approx", type=int, help="x 左右:自动展开为 [round(0.9x), round(1.1x)]") + args = ap.parse_args() + + if args.doc: + text = fetch_raw_content(args.doc, args.identity) + elif args.file: + try: + text = open(args.file, encoding="utf-8").read() + except OSError as e: + sys.exit(f"读取文件失败: {e}") + elif not sys.stdin.isatty(): + text = sys.stdin.read() + else: + ap.error("需提供 --doc / --file 或从 stdin 传入文本") + + mn, mx = args.min, args.max + if args.approx is not None: + mn, mx = round(args.approx * 0.9), round(args.approx * 1.1) + + total_words, total_chars = count(text) + verdict, gap = judge(total_words, mn, mx) + + print(json.dumps({ + "total_words": total_words, + "total_chars": total_chars, + "target": {"min": mn, "max": mx}, + "verdict": verdict, + "gap": gap, + }, ensure_ascii=False)) + + +if __name__ == "__main__": + main()