- 移除 TodoItem 中的 priority、created_at 和 updated_at 字段 - 强制每个任务都必须有唯一 id,且由用户负责生成 - 修改合并模式逻辑,merge=true 下保留未提及的旧任务 - 支持已完成和已取消任务重新激活(状态改回 pending 或 in_progress) - 禁止 in_progress 状态退回到 pending,必须标记为 completed 或 cancelled - 优化状态转换校验,允许特定状态间合法切换 - 简化任务变更消息,移除详细的新增/更新/移除统计 - 更新文档和示例,明确 id 必须由用户生成和使用 - 修复和补充测试,增强状态转换和合并模式验证 - 调整任务时间戳生成逻辑,统一使用当前时间及索引 - 该变更提供更合理的任务状态机械及管理模式,提升稳定性和易用性
7.3 KiB
mail +lint-html
前置条件: 先阅读
../../lark-shared/SKILL.md了解通用安全规则。
作用
+lint-html 是邮件 HTML 正文的本地预检工具(read-only,无网络 IO)。
- 校验 HTML 是否符合飞书邮箱的兼容性 / 安全 / 原生写法要求;
- 自动修复非法或不规范写法(autofix 始终启用),输出
cleaned_html; - 不写入任何邮箱状态,不调用任何 OAPI。
写信链路(+send / +draft-create / +reply / +reply-all / +forward / +draft-edit body op)已强制内置同一份 lint,提交前会自动净化 HTML。默认 envelope 不携带任何 lint 字段以保持响应小巧;加 --show-lint-details 可拿到完整 lint_applied[] / original_blocked[] 两个 Finding 数组(不再返回任何 *_count 字段,调用方需要 count 时 len(arr) 即可,详见 邮件 HTML 写法指南)。本命令是写信链路 lint 的预览版,行为一致,调用更轻量,适合:
- AI / 用户在创建草稿前自检 HTML 会被怎么改写;
- CI 流水线把 HTML 模板当作产物校验。
命令
# 直接传 HTML
lark-cli mail +lint-html --body '<p>正文</p>'
# 从文件读 HTML(路径必须在 cwd 子树内)
lark-cli mail +lint-html --body-file ./template.html
# 查看完整 lint 详情
lark-cli mail +lint-html --body-file ./template.html --show-lint-details
参数
| 参数 | 必填 | 说明 |
|---|---|---|
--body <html> |
二选一 | 待检查的 HTML 内容 |
--body-file <path> |
二选一 | 从文件读取 HTML,仅支持 cwd 子树(绝对路径 / .. 越出 cwd 会被拒) |
--show-lint-details |
否 | 默认 false。true 时 envelope 同时返回 warnings[] / errors[] 完整 Finding 数组;默认仅返回 cleaned_html,避免复杂模板触发数十条装饰性 warning 把响应撑大几千 token |
--format <fmt> |
否 | json(默认)/ pretty / table / csv / ndjson |
--jq <expr> |
否 | 对返回 JSON 用 jq 表达式过滤 |
--dry-run |
否 | 不执行 lint,仅返回 dry-run 描述 |
返回值
默认 envelope(仅 cleaned_html,token-frugal):
{
"ok": true,
"data": {
"cleaned_html": "<p>...</p>"
}
}
加 --show-lint-details 后:
{
"ok": true,
"data": {
"cleaned_html": "<p>...</p>",
"warnings": [
{ "rule_id": "...", "severity": "warning", "tag_or_attr": "...", "excerpt": "...", "hint": "..." }
],
"errors": [
{ "rule_id": "...", "severity": "error", "tag_or_attr": "...", "excerpt": "...", "hint": "..." }
]
}
}
| 字段 | 说明 |
|---|---|
cleaned_html |
修复后的 HTML(autofix 始终启用);warning 已自动改写,error 已删除 |
warnings[] |
警告级 finding 数组(仅 --show-lint-details 时返回)。无违规时输出 [] |
errors[] |
错误级 finding 数组(仅 --show-lint-details 时返回)。无违规时输出 [] |
每条 finding 含:
| 字段 | 说明 |
|---|---|
rule_id |
规则编号(UPPER_SNAKE_CASE) |
severity |
"warning" 或 "error" |
tag_or_attr |
触发规则的 tag / attribute / style.<property> |
excerpt |
HTML 片段(最多 200 字节,超出截断) |
hint |
可读的修复说明 |
调用示例
下面是用 lark-cli mail +lint-html --body '<INPUT>' --show-lint-details 实跑得到的典型 case(加 --show-lint-details 才能看到 finding;默认只返回 cleaned_html),覆盖 error 类(强制删)和 warning 类(自动修复)。
Error 类(强制删除,写信链路也会拒)
1. <script> 整段删除
输入:
<script>alert(1)</script>正文
输出:
正文
原因:<script> 有 XSS 风险,整段丢弃。
2. javascript: URL 删除
输入:
<a href="javascript:void(0)">click</a>
输出:
<a class="not-doclink" style="cursor:pointer;text-decoration:none;color:rgb(20,86,240)">click</a>
原因:javascript: scheme 是 XSS 入口,href 属性被剥。
3. on* 事件 handler 删除
输入:
<p onclick="alert(1)">hi</p>
输出:
<div style="margin-top:4px;margin-bottom:4px;line-height:1.6"><div dir="auto" style="font-size:14px">hi</div></div>
原因:inline event handler(onclick / onerror 等)是脚本注入入口,属性被剥。
Warning 类(自动修复,视觉无差异)
4. <font> → <span style>
输入:
<font color="red" size="3">字</font>
输出:
<span style="color:red; font-size:16px">字</span>
原因:<font> 是 HTML4 过时标签,飞书 mail-editor 用 inline style 表达字号 / 颜色。
5. <p> 段落容器原生化
输入:
<p>正文</p>
输出:
<div style="margin-top:4px;margin-bottom:4px;line-height:1.6"><div dir="auto" style="font-size:14px">正文</div></div>
原因:飞书 mail-editor 段落实际是双层 div(外层定 margin / line-height,内层定 font-size)。
6. <ul>/<li> 列表原生化
输入:
<ul><li>第一项</li></ul>
输出:
<ul style="margin-top:0px;margin-bottom:0px;margin-left:0px;padding-left:0px;list-style-position:inside" data-list-bullet="true"><li class="temp-li bullet1" data-li-line="true" data-list="bullet1" style="line-height:1.6;margin-top:0px;margin-bottom:0px;padding-left:0px;display:list-item;list-style-type:disc;font-family:inherit;font-size:14px;margin-left:0px;list-style-position:inside" dir="auto"><span style="font-family:inherit"><span style="color:rgb(0,0,0)">第一项</span></span></li></ul>
原因:飞书 native list-block 要求 <ul> / <li> 补全 class + data marker + 双层 span 包裹,否则 li 之间会出现可见空行。
7. <blockquote> 加灰边 + 灰文字
输入:
<blockquote>引用</blockquote>
输出:
<blockquote style="padding-left:0px;color:rgb(100,106,115);border-left:2px solid rgb(187,191,196);margin:0px">引用</blockquote>
原因:补飞书原生引用样式(左侧 2px 灰边 + 灰色文字)。
8. <a> 链接补 not-doclink + LarkSuite 蓝
输入:
<a href="https://example.com">link</a>
输出:
<a href="https://example.com" class="not-doclink" style="cursor:pointer;text-decoration:none;color:rgb(20,86,240)">link</a>
原因:补 not-doclink class(防误识为内部 doc share)+ LarkSuite 品牌蓝 + 无下划线。
9. 非白名单 CSS property 删除
输入:
<p style="position:absolute;color:red">x</p>
输出:
<div style="color:red;margin-top:4px;margin-bottom:4px;line-height:1.6"><div dir="auto" style="font-size:14px">x</div></div>
原因:position 不在 inline style 白名单内被剔除,color 保留。
相关命令
- 写信 shortcut(已内置同一份 lint):
+send/+draft-create/+reply/+reply-all/+forward/+draft-edit - 知识文档:邮件 HTML 写法指南