# 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`。
