feat:移除了弹窗,服务器添加sls

This commit is contained in:
2026-09-08 22:39:45 +08:00
commit 6a295f9a7a
4082 changed files with 1322534 additions and 0 deletions

View File

@ -0,0 +1,242 @@
# apps automation 触发器命令族 SOP
管理妙搭应用的自动化触发器(定时 / 记录变更 / Webhook / 飞书审批四类)。全部操作需 `--as user`AuthType: user`--help` 是参数细节的完整来源;本文件只记录 Agent 不看就会做错的领域规则。
## 何时用本 skill路由锚点
**当用户消息里出现「妙搭应用名 / app_id」+ 以下任一意图,路由本 skill不要走 lark-event 或 lark-openapi-explorer**
- 「(每天 / 定时 / 每 N 小时 / 每周 X自动跑 / 自动触发 / 定时同步」→ `+automation-create --trigger-type cron`
- 「数据表 / 记录 / 表里 X 字段(新增 / 更新 / 删除 / 变化)时(触发 / 通知 / 处理)」→ `+automation-create --trigger-type record-change`
-webhook / 外部回调 / 外部系统调用 / HTTP 触发)」→ `+automation-create --trigger-type webhook`
- 「(审批 / 报销 / 请假 / 出差)(通过 / 拒绝 / 提交 / 撤回)后自动 X」→ `+automation-create --trigger-type feishu-approval`
- 「这个应用配了哪些(自动化 / 触发器 / 定时任务)」→ `+automation-list`
- 「(暂停 / 停用 / 先别自动跑 / 关掉自动触发)某个(触发器 / 定时任务 / 自动化)」→ `+automation-disable`(不是 update 改条件、不是 delete——本 skill 不提供删除)
- 「启用 / 启动已有 trigger」→ 先核对现有状态;只启用时不要修改源码或发布应用。
- 「换 / 重置 webhook 回调地址 / URL」→ `+automation-update --reset-url --app-env <preview|runtime>`
- 「换 / 重置 / 轮换 webhook token / bearer」→ `+automation-update --reset-token`
- 「触发器没反应 / enable 了不触发 / 为什么没执行 / 验证一下触发器」→ 先按「未触发时的诊断顺序」诊断;对 UPSERT 和 feishu-approval 仅验证配置边界,不承诺 handler 或 live 验证。
**边界(防误路由)**`lark-event` 是**实时事件流消费**agent 长连接订阅事件),不管妙搭应用触发器的**配置**;用户说「配 / 设置一个触发器」而不是「订阅事件流」时,本 skill 才是正确选择。「审批通过触发」在妙搭应用语境下属于本 skill 的 `feishu-approval` 类型,不是 lark-event。
### 回应「怎么配」类问题的正确姿势
用户问「怎么配 / 怎么设置一个 X 触发器」时,**先展示完整命令模板 + 你对核心参数的推断**(让用户能确认你理解对了),再追问缺失的必填项(`--name` 之类)或可选项。**不要跳过展示、直接连环追问**,那样用户没法确认你有没有理解意图。
示范:用户说「报销审批一旦通过就自动触发处理,怎么配?」
- ✅ 正确:先写出「这是 feishu-approval 类型,命令模板:`apps +automation-create --app-id <id> --name <name> --trigger-type feishu-approval --event-type approval_instance --instance-status APPROVED [--approval-code <code>]`。需要你确认:(1) 触发器名 `<name>`(2) 是否限定特定审批流程——限定就传 `--approval-code`(从飞书审批管理后台拿),不传则匹配所有审批定义」。
- ❌ 错误:直接问「叫什么名字?监听哪个审批?」——用户没法确认你有没有把「审批通过」映射到 `--event-type approval_instance --instance-status APPROVED`
同理cron/record-change/webhook 三类的「怎么配」都遵循此模式:先给命令 + 参数推断,后追问缺项。
## 命令路由
| 命令 | 用途 | Risk |
|---|---|---|
| `+automation-list` | 列出应用所有触发器(可按类型过滤、`--all` 聚合翻页) | read |
| `+automation-get` | 查看单个触发器完整配置Webhook Bearer Token 恒脱敏) | read |
| `+automation-create` | 创建触发器,四类共用一条命令,按 `--trigger-type` 分派 | write |
| `+automation-update` | 改条件/描述,或经专用 flag 管理 Webhook URL·Token | high-risk-write |
| `+automation-enable` | 启用触发器(`status→enabled`,开始自动触发) | write |
| `+automation-disable` | 停用触发器(`status→disabled`,停止触发,不删除) | write |
触发器以 **应用内唯一的 `--name`** 定位(不是 id。所有单条命令都用 `--app-id` + `--name`;名字忘了先 `+automation-list` 查。
## 四类触发器 payload
`--trigger-type` 用面向 Agent 的 kebab-case`cron` / `record-change` / `webhook` / `feishu-approval`CLI 内部转 snake_case 下推。类型专属 flag 只在对应类型生效。
### cron定时
```bash
+automation-create --app-id <id> --name daily --trigger-type cron \
--cron '0 9 * * *' [--timezone Asia/Shanghai]
```
- `--cron` 是**五段式**`minute hour day month weekday`),非六段。
- **最小间隔 30 分钟**`--cron '* * * * *'`(每分钟)或 `*/n`n<30会被 CLI 本地拦截报错后端也会二次校验
- `--timezone` 缺省补 `Asia/Shanghai`IANA 时区名)。
### record-change记录变更
```bash
+automation-create --app-id <id> --name onUpd --trigger-type record-change \
--table <table_name> --event UPDATE [--fields '["status"]']
```
- `--event` **大写枚举**`INSERT` / `UPDATE` / `UPSERT` / `DELETE`CLI uppercase但请按枚举传)。
- `--table` 是应用数据库里的**表名**对应 `+db-table-list` / `+db-table-get` 输出里 `.name` 字段的值必填妙搭应用的 dataloom 表以名称作为稳定标识符没有独立的 `table_id`
- `--fields` JSON 字符串数组仅对 `UPDATE`/`UPSERT` 有意义`'["*"]'` 表示监听所有字段不传表示不限定字段
### webhook外部回调
```bash
+automation-create --app-id <id> --name hook --trigger-type webhook \
[--white-ip-list '["1.1.1.1","2.2.2.2"]']
```
- 创建时可选 `--white-ip-list`JSON 字符串数组限制回调来源 IP
- 回调 URL **preview / runtime 两套**创建时不回显 `+automation-get` 查当前配置 `+automation-update --reset-url --app-env <preview|runtime>` 轮换
- Bearer Token 是回调鉴权凭证见下方凭证脱敏与一次性回显」。
### feishu-approval飞书审批
```bash
+automation-create --app-id <id> --name apv --trigger-type feishu-approval \
--event-type approval_instance --instance-status APPROVED [--approval-code <code>]
```
- `--event-type` 必填 `approval_instance` `approval_task`决定状态用哪套 flag
- `approval_instance` `--instance-status`可重复
- `approval_task` `--task-status`可重复
- **领域规则**状态按 `event-type` 分桶校验两桶枚举**不完全相同**`PENDING`/`APPROVED`/`REJECTED`/`REVERTED`/`OVERTIME_CLOSE`/`OVERTIME_RECOVER` 两桶共享`TRANSFERRED`/`ROLLBACK`/`DONE` task `CANCELED`/`DELETED` instance 传错桶的状态会被 CLI 本地拦截错误信息会打印该桶的合法值列表具体枚举见命令 `--help`
## approval-code 获取路径
`--approval-code` **可选**不传时匹配所有审批定义要限定某个审批流程时**飞书审批管理后台**获取具体的 code 传给它触发器 OpenAPI 不提供审批定义查询能力具体 code 需去审批管理后台查
## 凭证脱敏与一次性回显(安全关键)
- `+automation-get` / `+automation-list`**恒不返回明文 Bearer Token**——`trigger_condition.token_value` 被抹为 `null`用户想知道token 是什么list/get 都查不到明文
- `+automation-update --enable-token` / `--reset-token`明文 Bearer Token **仅当次 stdout 回显一次**同时 stderr 打印一次性告警
```text
warning: this bearer token is shown only once and is NOT stored by lark-cli — copy it now and store it in your own secret manager.
```
- Webhook URL 同理:`--reset-url` 后新 URL 仅当次回显一次,旧 URL 立即失效。
- CLI 不落盘任何明文 token/URL不写 cache / config / recent / debug log / 错误信息)。
- **Token 丢失只能 reset**:找不回,唯一恢复方式是 `+automation-update --reset-token`(旧 token 同时失效)。
## 高危确认
`+automation-update` 整体是 `high-risk-write`,任何一次调用都需显式 `--yes`;缺少时框架会要求确认(退出码 10。**不要自动补 `--yes`**——需用户明确确认后再加。以下 Webhook 动作 flag 尤其不可逆:
- `--reset-url`(旧回调 URL 立即失效,需配 `--app-env preview|runtime`
- `--reset-token`(旧 token 立即失效)
- `--disable-token`(关闭 token 校验,**不可逆**
四个 Webhook 动作 flag`--reset-url` / `--enable-token` / `--disable-token` / `--reset-token`**每次只能传一个**。不确定影响时先跑 `--dry-run` 看将发出的请求(不含明文)。
### 执行前必须完成的确认步骤(高危写强制协议)
**在带 `--yes` 执行任何高危写之前Agent 必须先完成以下 3 件事**,缺一不可——即使用户口气很急、即使命令一眼就明:
1. **确认目标唯一**:不允许"猜名字"或"批量试所有可能的名字"。若不确定 `--name`,先 `+automation-list --app-id <id>` 让用户在候选中点名;`--name` 不明的绝不执行写操作,更不要 for 循环批量试。
2. **确认可选参数已定**`--reset-url` 必须由用户明确指定 `--app-env preview` 还是 `runtime`;不要默认取 runtime 或 preview。同一触发器的 preview/runtime 是两条独立的 URL误重置另一条不可回退。
3. **告知不可逆后果并等确认**:把即将发生的 3 件事复述给用户——a旧 URL/Token 立即永久失效b新 URL/Token 仅当次回显一次、CLI 不保存c本次操作无法撤销——等用户回复"确认"再加 `--yes` 跑。
只要有一项没做,就先跟用户对齐、不要执行。这些是 skill 层的护栏,不是 CLI 层的CLI 只强制 `--yes`,不强制上面 3 件事)。
## ⚠️ 安全告警:无鉴权公网回调组合态
`--disable-token`(关闭 Bearer Token 校验,不可逆)**叠加** `--white-ip-list '[]'`(清空 IP 白名单)会让 Webhook 触发器进入「**无鉴权公网回调**」组合态——**任何来源都能触发该 Webhook**,没有任何一道防线拦截。
- 两道防线Token 校验(谁能调)+ IP 白名单(从哪能调)。**不要同时关闭这两道防线。**
- 若确需关闭 Token例如对端无法带 Bearer 头),务必**保留 IP 白名单**收敛来源;反之若要放开 IP务必**保留 Token 校验**。
- 用户同时要求「关 token 校验 + 清空 IP 白名单」时Agent 的正确响应是**在识别到该请求的第一时间**(不要等命令跑失败才补警告)向用户输出以下 3 件事,再等确认——不要只描述"没有任何防线"就停下:
1. 复述后果:这会形成无鉴权公网回调,任何来源都能触发。
2. **主动给出替代方案**:明确建议"要么只关 Token 保留 IP 白名单,要么只放开 IP 保留 Token",让用户在保留一道防线的两条备选里选一条。
3. 只有用户明确回复"我理解风险、就是要两道都关"时,才继续按高危写协议(见上节「执行前必须完成的确认步骤」)走。
## 默认 disabled
`+automation-create` 创建后触发器**默认 disabled**,不会自动触发。需 `+automation-enable` 才开始按条件自动运行(且触发器执行的是**线上已发布**的应用代码——应用未发布时即便 enable 也不会有实际效果)。
**Agent 行为约束**:用户只说"创建/配一个触发器"时,**不要**主动在同一个 turn 里 `+automation-enable`。让用户自己在下一轮决定是否启用;主动启用会:
- 让 webhook 类型立即可被外部调用(原本用户可能只是想"备好 URL 稍后用"
- 让 cron 到点真实触发(原本用户可能想"先建好观察配置"
- 让 record-change 立即响应表变更
创建成功后的推荐话术:`已创建 <name>,当前 disabled需要真正开始自动运行时告诉我我用 +automation-enable 启用它。` **不要**在创建成功后立即启用,即使 skill 里说"需 enable 才自动触发"——这条是给用户的说明,不是给 agent 的行动指令。
## 本地全栈 Trigger 闭环
当用户希望触发器实际执行业务代码时,先确认当前工作区是已初始化的应用项目,并读取其中与触发器任务匹配的 guide。
`--name` 是应用内唯一的 trigger 定位键;代码侧绑定名称必须与它逐字相同。不得用 trigger ID 或方法名代替它。具体 handler 语法和接入方式以项目 guide 为准。
### 仅创建/配置触发器
适用于 cron、record-change、webhook 和 feishu-approval。用 `+automation-create` 创建,并省略 `--status` 或显式传 `disabled`,然后报告 name 和 disabled 状态。
不要传 `--status enabled`,也不要写 handler、commit/push、release 或 enable更不能把创建 API 成功称为“可运行”。默认 disabled 是这个意图的终点,不是稍后自动 enable 的待办。
### 仅启用已有 disabled trigger
用户只要求启用已存在且 disabled 的 trigger、没有要求修改代码或制造真实 runtime 事件时,先用 `+automation-get` 核对 name、类型和 disabled 状态,再用 `+release-list --status finished --page-size 1` 核对是否存在已完成线上 release。release history 只能证明当前线上应用有已发布版本,不能证明该 trigger name 已绑定 handler。不存在 finished release 时说明 enable 只会改变配置状态、当前没有可执行的线上版本;存在时说明它会对当前线上应用激活这条 trigger 配置。随后按用户要求执行 `+automation-enable`,再用 `+automation-get` 确认 enabled。
这条路径不得修改 handler、commit/push 或 release。未发布时不得自动创建 release也不得声称 trigger 已开始实际运行。即使存在 finished release也只能把 enable 报告为配置激活;没有 handler 来源或 runtime 结果时,不得声称业务 handler 已存在、已运行或可用。若用户期待尚未发布的本地改动生效,或检查后发现确实需要新增/修改 handler转到下方“实现或更新 handler 后发布并启动/测试”路径;不要为单纯 enable 发布整个 `sprint/default`。
对 UPSERT 或 feishu-approval 只改变配置状态;由于本 guide 没有其已证实的 handler、投递或 live 验证契约,启用后也不得声称业务代码已运行或触发器已实测可用。
### 测试已有线上 trigger不改代码
用户要求测试已经发布的 trigger、没有要求修改 handler 时,先用 `+automation-get` 核对 name、类型、当前状态再用 `+release-list --status finished --page-size 1` 确认应用存在 finished release并说明本次测试覆盖当前线上代码。没有 finished release 时停止 runtime test只报告配置状态不得为测试自动修改源码、commit/push 或 release。release history 不证明该 name 已绑定 handler真实 probe 的结果才是本次验证证据;若用户期待本地未发布改动,改走代码变更闭环。
记录测试前状态,并在任何临时 enable 之前完成两类授权和全部 preflight测试请求已明确包含临时 enable或另行取得 enable 授权;同时按下方“运行时验证的操作级授权”确定具体事件、影响、载荷、观察结果和清理。原本 disabled 时完成这些门槛后才临时 enable并在验证结束后恢复 disabled原本 enabled 时不要无意义切换状态。原本为 disabled 时,无论 probe 成功、失败、结果不确定,还是临时 enable 后提前结束或中断,最终都必须 `+automation-disable` 并回读 disabled不得停在 enabled。测试意图本身不决定数据库记录、Webhook 请求或其他事件载荷。
### 仅完成 handler不发布/不启用)
仅对 cron、webhook、record-change 的 `INSERT`、`UPDATE`、`DELETE` 使用此路径。
创建或定位已明确 name 的 disabled trigger读取项目 guide按其要求实现同名业务 handler完成本地验证。只在既有 Git 确认或预授权下 commit/push停止在 `+release-create` 和 `+automation-enable` 之前。用户没有明确“发布好”时,先问,不能默认把完整应用上线。
### 把 handler 发布好,但先不要启动
仅对 cron、webhook、record-change 的 `INSERT`、`UPDATE`、`DELETE` 使用此路径。先用 `+automation-get` 定位;不存在时用 `+automation-create` 创建同名 disabled trigger再次回读确认。已存在时记录它是否 enabled。按项目 guide 完成同名业务 handler 并本地验证后commit、`git push origin sprint/default`。若 trigger 已 enabled先说明发布前必须临时停用以及可能造成的运行中断并取得这次临时停用授权未获授权时停止在发布前。取得授权后在发布前执行 `+automation-disable`,并再次用 `+automation-get` 确认 disabled。随后发布完整应用
```bash
lark-cli apps +release-create --as user --app-id <app_id> --branch sprint/default
```
若 `+release-create` 本身返回错误或未返回 `data.release_id`:视为确认未创建本轮 release新代码未上线原本 enabled 的 trigger 恢复 enabled 并回读、原本 disabled 的保持 disabled然后停止若因超时等导致创建结果未知保持 disabled先用 `+release-list --status finished --page-size 1` 核对是否已产生新 release 再决定。取得 `data.release_id` 后,对**这一轮** ID 调用 `+release-get``publishing` 时每 20 秒继续轮询,整体最多约 5 分钟;超时且状态仍不确定时报告 `release_id` 和当前 status并保持 disabled只有 `data.status=finished` 才算完成。确认 `failed` 且新代码未上线时,原本 enabled 的 trigger 恢复 enabled 并回读,原本 disabled 的保持 disabled。release 是整个应用上线可能影响既有线上功能未获得启动或测试授权时finished 后始终保持 disabled不执行 `+automation-enable`。
### 实现或更新 handler 后发布并启动/测试
仅当本轮确实需要新增或修改 cron、webhook、record-change 的 `INSERT`、`UPDATE`、`DELETE` handler且用户要求把这次代码发布后启动或测试时才使用此路径。按以下不可跳过的顺序执行
1. 用 `+automation-get` 定位并记录发布前状态,再核对其 `--name`、类型并读取项目 guide不存在时用 `+automation-create` 创建同名 trigger 并保持默认 disabled。
2. 按项目 guide 完成同名业务 handler 并本地验证。
3. 在 Git 已确认/预授权时 commit然后执行 `git push origin sprint/default`。
4. 若 trigger 当前 enabled先说明发布前必须临时停用以及可能造成的运行中断并取得这次临时停用授权未获授权时停止在发布前。取得授权后执行 `+automation-disable`,并再次用 `+automation-get` 确认 disabled原本 disabled 时不要无意义切换状态。
5. 执行 `+release-create --branch sprint/default`。若该命令本身返回错误或未返回 `data.release_id`:视为确认未创建本轮 release新代码未上线原本 enabled 的 trigger 恢复 enabled 并回读、原本 disabled 的保持 disabled 后停止;若因超时等导致结果未知,保持 disabled先用 `+release-list --status finished --page-size 1` 核对是否已产生新 release 再决定。取得 `data.release_id` 后进入下一步。
6. 对该 ID 执行 `+release-get`,只有 `data.status=finished` 才能继续;`publishing` 时每 20 秒继续轮询,整体最多约 5 分钟。超时且状态仍不确定时停止本轮轮询、报告 `release_id` 和当前 status并保持 disabled确认 `failed` 时报告发布失败,原本 enabled 的 trigger 仅在确认新代码未上线后恢复 enabled原本 disabled 的保持 disabled。发布状态仍不确定时不得进入 enable、probe 或状态恢复分支。`is_published=true` 不能代替这轮发布完成。
7. **仅启动**:取得持续启动授权后执行 `+automation-enable`,并用 `+automation-get` 确认 enabled到此结束不制造 runtime probe。
8. **测试(含“启动并测试”)**:先按下节“运行时验证的操作级授权”完成全部 preflight包括具体事件、sibling 影响、载荷、观察结果和清理;完成前保持 disabled之后才执行 `+automation-enable` 并回读,再由已授权主体制造真实 runtime 条件并核验业务结果。若同时明确要求持续启动,只有 probe 成功后才保持 enabled。
9. 若用户仅要求测试而不是持续启动,只在本轮 release 已 `finished` 且 probe 成功后恢复到发布前状态:原本 disabled 或本轮新建的 trigger `+automation-disable` 并回读;原本 enabled 的可保持 enabled。无论用户是仅测试还是启动并测试probe 失败、结果不确定或 enable 后提前结束时,一律 `+automation-disable` 并回读 disabled不得把“发布前 enabled”当作失败后的恢复依据因为本轮新代码已经上线。只有旧 release 已回滚并验证,或修复后重新发布且 probe 成功,才可再次 enabled。恢复失败时明确报告当前状态。
没有通用的 `automation-debug` 或 trigger 日志 shortcut。缺少安全事件入口、匹配环境或可观察结果时记录 blocked不能编造测试成功。
### 运行时验证的操作级授权
启用 trigger 的授权不等于制造 runtime 事件的授权测试授权也不等于任意数据库写入授权。cron 可等待计划时间webhook 只能向既有 runtime URL 发送已授权、安全且不泄露凭证的请求。record-change 在执行任何 DML 前必须明确并取得覆盖以下作用域的授权环境、表、操作、精确测试记录或筛选条件、payload、预期结果和清理方式。
优先使用专用测试记录不要任取线上业务记录。用户已明确授权精确、可撤回的测试夹具及其清理时不机械追加一轮确认目标或影响仍不清楚时必须停下。record-change probe 前先执行 `+automation-list --trigger-type record-change --all`,检查同一环境、表和操作可能命中的其他 enabled trigger若存在 sibling match必须说明聚合业务影响并取得覆盖这些影响的授权或换成隔离夹具/经授权临时停用后再测。`UPDATE` 要限定精确条件并保留恢复方式;`INSERT` 要预先约定清理;恢复 UPDATE 或清理 INSERT 也可能再次触发自动化,必须纳入影响说明和授权。`DELETE` 必须遵循 [lark-apps-db-execute.md](lark-apps-db-execute.md):先 `SELECT count(*)`、执行 `--dry-run`,展示影响后取得针对该删除目标的明确授权,再带 `--yes` 执行;清理动作若包含未预先授权的删除,同样走该门槛。
缺少安全、已授权且可清理的事件入口时,记录 blocked不得用“测试一下”推导任意 online 数据写入。
### UPSERT 与飞书审批边界
record-change 的 UPSERT 可创建 disabled 配置,但当前没有已证实的运行时代码契约;不得静默按 UPDATE 处理,也不得承诺 handler 或 live 验证。
feishu-approval 可创建 disabled 配置,并读取或更新 `event_type`、对应 status 和可选 `approval_code`。当前没有已证实的运行时 handler 契约或实际投递验证;不要把 enable 或审批 API 成功称为业务代码已执行。
### 未触发时的诊断顺序
按 `--name` / 项目 guide 要求的代码接入 → 本轮 release `finished` → enabled 状态 → 类型条件、环境和已有日志的顺序排查。客户审批投递故障属于服务端事件投递排查,不要归因于此 SOP 或改写无关业务代码。
## 常见错误与决策场景
| 现象 / 用户意图 | 正确处理 |
|---|---|
| 创建报名字冲突(`--name` 应用内唯一) | 换名或加后缀重试 |
| cron 报非法 / 间隔过小 | 检查是否五段式、分钟字段是否 `*` 或 `*/n`(n<30) |
| `--reset-url` 报缺 app-env | 补 `--app-env preview` 或 `--app-env runtime` |
| 想把 cron 触发器改成 webhook跨类型改 | update 不支持换类型,本 skill 也不提供删除。旧触发器只能 `+automation-disable` 停用(保留在应用里),另建一个 webhook 触发器;若要真正清理旧触发器,请到妙搭 web 手动删除 |
| 触发器 enable 了但不触发 | 已证实的 cron、webhook、record-changeINSERT/UPDATE/DELETE按「未触发时的诊断顺序」排查UPSERT 和 feishu-approval 仅核对配置边界,不承诺 handler 或 live 验证。 |
| 「token 泄露了」 | 优先 `+automation-update --reset-token --yes` 轮换(旧 token 立即失效),而非直接 disable-token 关校验 |
| 「回调 URL 泄露了」 | `+automation-update --reset-url --app-env <env> --yes` 轮换 |
## 不在本 skill 范围
- 审批定义查询、Webhook 消费端实现、实时触发日志 tail本期不支持。
- 身份选择、权限不足处理、exit-10 审批、通用「禁输出密钥」红线、高风险操作通用框架:见 [`../../lark-shared/SKILL.md`](../../lark-shared/SKILL.md),不在此重复。