@lark-project/cli
Version:
飞书项目插件开发工具
165 lines (110 loc) • 9.63 kB
Markdown
# mode=apply:同步配置 + 构建上传 + 版本发布
**Checkpoint 恢复检查**(仅在 `lpm --cwd "<projectRoot>" ai state get` 有输出时;输出为空 = 无 checkpoint):
- `lastCommand` 含 `update` + `"success"` → 跳过 A1,直接执行 A2
- `lastCommand` 含 `release` + `"success"` → 跳过 A1+A2,直接执行 A3(从 `context.artifactVersion` 获取版本号)
- `lastCommand` 含 `publish` + `"success"` → 全部完成,跳到 A4 输出
- 其他 → 从 A0 开始
## A0:发布前总检 + 确认(check diff · 不可逆护栏,MUST · 来自 shared.md 「必须先确认」清单第 5 类)
A1 的 `update` 会把本地配置**覆盖**到远端草稿、抹平本地↔远端差异——因此发布前确认 **MUST 在 A1 之前**做,否则 check diff 的「配置覆盖(本地→远端最新草稿的点位增删改)」段会归零、看不出本次发布会改什么。
```bash
lpm --cwd "<projectRoot>" check diff
```
`lpm check diff` 产出 CLI 锚定的四段总检:**① 基本信息 / ② 配置覆盖(本地→远端最新草稿的点位增删改)/ ③ 权限变更 / ④ 运行时 URL 健康**。
- 把 check diff 的 stdout **整段原样**转呈用户——**不得改写、转述、增删或只摘要**(模板由 CLI 锚定,AI 不得改写)。
- `lpm check diff` 自身 `exit≠0`(取数失败)→ 视为**致命**,展示错误并终止,**不得**盲发。
- 等用户显式回复"确认发布" / "OK" / "好,发布"之类**明确同意**才进 A1;用户说"取消" / "等等" / "我再看看"→ 终止流程,保留 checkpoint 待后续 `phase=3` 恢复。
- 用户看完要改:**②** 配置不对 → 改 `point.config.local.json` 后 `lpm local-config set`;**③** 权限不对 → `lpm perm apply` 调整;**④** URL 是占位 → 改配置后 `lpm local-config set`。改完回到 A0 重跑 check diff 重新确认。
- **占位 URL 以 ④段为唯一发布前出口**:A1 的 `update` 仍会打 `⚠️ NOTICE`,但 ④段已在确认前展示过、用户也是看着它确认的——**A1 那条占位 NOTICE 不必再转呈**(避免同一警告秒级内重复)。
> 被 workflow 编排时(Phase 3.2 已先跑过 `lpm check diff` + 等"确认发布"),允许跳过 A0 这次重复确认。**独立 `mode=apply` / `phase=publish` 入口进来时,A0 无法跳过。**
>
> **从 checkpoint 恢复**直接落到 A1 之后(`lastCommand` 含 update/release + success、本地已推上远端、②配置覆盖段已归零)时,不必重跑 A0,但 **A3 的恢复护栏**(见 A3)会在 publish 前补一次确认——保证「本 session 内不经确认绝不 publish」。
## A1:同步配置到后台(兜底)
**Checkpoint**:执行前写入 `{ nextCommand: "update --source-type=local", nextStep: "A1 同步配置", lastCommandStatus: "running" }`
> Stage Config 的 `local-config set` 已经把配置推到了远端;此步为兜底确认(例如用户直接进 publish、或本地有手动修改未经 set 提交),强制把本地最新点位配置再推一次。
```bash
lpm --cwd "<projectRoot>" update --source-type=local
```
> `update` 若打出占位 URL `⚠️ NOTICE`:A0 ④段已展示过、用户已据此确认,**这里不必再转呈**(见 A0 的占位 URL 去重说明)。
- 成功 → **Checkpoint**:`{ lastCommand: "update --source-type=local", lastCommandStatus: "success", nextCommand: "release", nextStep: "A2 构建上传" }` → 继续 A2
- 失败 → **Checkpoint**:`{ lastCommand: "update --source-type=local", lastCommandStatus: "failed" }` → 展示错误,终止
## A2:构建 + 上传(release)
**Checkpoint**:执行前写入 `{ nextCommand: "release", nextStep: "A2 构建上传", lastCommandStatus: "running" }`
```bash
lpm --cwd "<projectRoot>" release
```
**耗时操作**(约 30–120s),需展示构建进度。
### 成功标志
从 stdout 中提取产物版本号:
```
Artifact version: 1
(Use this as --artifact-version when running publish)
```
正则提取:`/Artifact version: (\S+)/`
> 注意:产物版本号是后端返回的内部版本(如 `1`、`2`、`3`),不是语义化版本号。直接作为 `--artifact-version` 传给 publish 即可。无前端产物的插件(如 AI 应用)`lpm release` 输出 `Artifact version: 0`,正则照常提取到 `0`,照传即可——`--artifact-version` 本身也是可选的,省略时 publish 按"无前端产物"处理。
将提取到的版本号记为 `artifactVersion`,作为下一步 publish 的入参。
**Checkpoint**(release 成功后,**关键**):`{ lastCommand: "release", lastCommandStatus: "success", nextCommand: "publish ...", nextStep: "A3 版本发布", context: { ..., artifactVersion: "<提取到的版本号>" } }`
> **必须将 `artifactVersion` 保存到 checkpoint 的 `context` 中**,否则中断恢复后无法跳过 release 直接 publish。
### 失败处理
**Checkpoint**:`{ lastCommand: "release", lastCommandStatus: "failed" }`
**webpack 错误(自动修复最多 1 轮)**:
1. 捕获完整 stderr/stdout 中的 webpack 错误日志
2. AI 分析错误类型(常见:import 路径错误、缺少 module)
3. 修复代码文件,重新执行 `lpm release`
若修复后成功 → 继续。若仍失败 → 终止并提示:
```
❌ 构建失败(已尝试自动修复)
webpack 错误:
[完整错误日志]
请在本地修复后手动执行:
lpm release
lpm publish --artifact-version <产物版本>
```
## A3:版本发布(publish)
**Checkpoint**:执行前写入 `{ nextCommand: "publish --artifact-version <X>", nextStep: "A3 版本发布", lastCommandStatus: "running" }`
release 成功后,AI 自动准备 publish 参数,**无需向用户逐个收集**:
| 参数 | 来源 | 说明 |
|------|------|------|
| `--version` | 自动 | 不传,默认在上一版本基础上 patch +1(如 `1.0.0` → `1.0.1`) |
| `--release-notes` | AI 生成 | AI 基于当前代码改动(git diff / 文件变更)自动总结版本描述(中文) |
| `--artifact-version` | A2 输出 | 来自 release 输出的 artifactVersion |
| `--store` | AI 不传 | 默认继承上一版本的 visibility;首次发布默认 `yes`。用户明确要求"发到/不发到商店"时才显式传 `yes`/`no` |
| `--upgrade` | 默认 | `manual`(默认手动升级) |
**AI 自动总结版本描述的方式**:
1. 检查 git diff 或已变更的源码文件
2. 总结功能改动要点,生成简洁的中文描述(如"新增看板点位,支持需求图谱展示")
**发布前确认(不可逆护栏,MUST · 来自 shared.md 「必须先确认」清单第 5 类)**:
`lpm publish` 把插件发布到 Meegle 市场——**不可逆、用户可见、当前不支持回退**。发布前确认在 **A0(`lpm check diff` 四段总检)** 已做过,A3 本身不再重复确认——**除非走的是 checkpoint 恢复路径**:
> **恢复护栏(MUST)**:若本 session **未经过 A0**(如从 checkpoint 直接恢复落到 A2/A3,`lastCommand` 含 update/release + success),则在执行 `lpm publish` **之前 MUST 先补一次确认**——重跑 `lpm --cwd "<projectRoot>" check diff` 把 stdout 原样转呈用户、等"确认发布"才发。此时本地已推上远端、check diff 的②配置覆盖段已归零,但 **③ 权限变更 / ④ 运行时 URL 健康仍有效**,足以让用户在不可逆发布前最后核对一遍。用户说"取消"则终止、保留 checkpoint。
>
> 这条护栏保证「本 session 内不经一次显式确认绝不 publish」,无论是正常 A0→A1→…→A3 还是断点恢复直插 A3。
确认到位(A0 已确认,或恢复护栏刚补过确认)后,直接执行:
```bash
lpm --cwd "<projectRoot>" publish \
--release-notes "<AI 总结的版本描述>" \
--artifact-version <A2 输出的 artifactVersion> \
--upgrade manual
```
> 参数来源:`<artifactVersion>` 从 A2 `lpm release` 的 stdout `Artifact version: (\S+)` 正则提取(中断恢复时从 checkpoint `context.artifactVersion` 读);`<AI 总结的版本描述>` 由 git diff / 源码变更生成。
> 如果用户主动指定了版本号,则加上 `--version <用户指定>`。
> 本 skill 对 normal / AI 应用使用同一条 publish 命令;CLI 内部按 plugin.config.json 的 app_type 自动选择通道:normal 走版本提交三步走、AI 应用走 release_app 单调用。AI 应用下 release-notes / version / upgrade 这几个参数即使传了 CLI 也会忽略 + stderr 提示。
### 成功
**Checkpoint**:`{ lastCommand: "publish", lastCommandStatus: "success", nextStep: "A4 输出" }`
`lpm publish` 输出分享链接:
```
🍻🍻🍻 Publish successfully! Current version is 1.0.1.
Plugin share url: https://meego.example.com/openapp/plugin_share?appKey=PL_xxx
```
### 失败处理
**Checkpoint**:`{ lastCommand: "publish", lastCommandStatus: "failed" }`
| 错误类型 | 处理方式 |
|---------|---------|
| 版本号已存在 | 自动 patch +1 重试,或提示用户指定版本号 |
| 网络/权限错误 | 展示原始错误,告知用户可手动重试 |
## A4:输出
```
✅ 插件发布完成
产物版本:1.0.1(release)
发布版本:1.0.1(publish)
分享链接:https://meego.example.com/openapp/plugin_share?appKey=PL_xxx
```
> `publish` 成功时 CLI 会自动清理整个 `.lpm-cache/`(仅保留 `state.json` 供 workflow 断点恢复);发布失败或用户中断则不清理,保留缓存便于续跑。AI 不需要手动 `rm`。