# Pwa Save Article

> 通过 PlayWithAI 资源站的 create-article 发文 API 保存文章。当用户要求把内容写成文章、发布/保存到 PlayWithAI 资源站（pwa 资源站）、存为草稿，或要求"用 API key 发文"时使用。覆盖前置检查、根据上下文构造 API 参数、脚本调用与结果反馈；信息不明确时必须停下来向用户澄清。

- Skill: `vibe-any/pwa-save-article` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add vibe-any/pwa-save-article`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vibe-any/pwa-save-article/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: vibe-any (https://skillmd.com/u/vibe-any)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/vibe-any/pwa-save-article

---


# pwa-save-article · 调用发文 API 保存文章

把一篇文章通过 PlayWithAI 资源站的 `create-article` API 保存进去。完整接口规范见项目根目录
[CREATE_ARTICLE_API.md](../../../CREATE_ARTICLE_API.md)；本 skill 只保留执行所需的最小规则。

**执行顺序固定为：① 前置检查 → ② 构造参数 → ③ 脚本调用 → ④ 反馈结果。**
任何一步遇到本文件标注「必须澄清」的情况，立即停下来用 `ask_user_question` 向用户提问，不要猜测、不要编造默认值继续执行。

## ① 前置检查

依次确认，任何一项失败即停下：

1. **调用脚本存在**：`.agents/skills/pwa-save-article/scripts/save_article.mjs`（相对项目根目录）。缺失则报告并停止，不要临时用 curl 代替。
2. **API 密钥可用**（按顺序查找第一处即可）：
   - 环境变量 `PWAI_API_KEY`；
   - 项目 `.env` 中的 `PWAI_API_KEY=`。
   - 密钥格式必须为 `pwai_` + 64 位十六进制。
   - **找不到或格式不对 → 必须澄清**：告知用户到管理后台 `/admin → API 密钥` 创建（明文只显示一次），请其提供密钥或确认已写入 `.env`。不要让用户把密钥粘贴到公开场合之外的地方。
3. **接口地址**：默认 `https://zhjrfpuoiblhbstcpkcz.supabase.co/functions/v1/create-article`，可被 `PWAI_CREATE_ARTICLE_URL`（环境变量或 `.env`）覆盖。脚本已内置此逻辑，无需手工拼接。
4. **网络可达**由脚本执行时验证，前置阶段不单独探测。

## ② 根据上下文构造参数

从用户消息、会话上下文、或用户指定的文件内容中提取以下字段，组装成一个 JSON 对象（保存为临时文件，如 `payload.json`）。字段约束（与服务端一致，脚本会本地预校验）：

| 字段          | 必填     | 规则                                                    |
| ------------- | -------- | ------------------------------------------------------- |
| `kind`        | ✅       | `original` / `open-source` / `tech` / `practice`        |
| `title`       | ✅       | 3–160 字符                                              |
| `excerpt`     | ✅       | 12–360 字符（别名 `description`）                       |
| `contentMd`   | 三选一\* | ≤ 30000 字符 Markdown（别名 `content`）                 |
| `githubUrl`   | 三选一\* | http(s) URL，仅 `open-source` 入库                      |
| `externalUrl` | 三选一\* | http(s) URL                                             |
| `coverUrl`    | 可选     | http(s) URL，留空用默认封面                             |
| `author`      | 可选     | ≤ 60 字符                                               |
| `tags`        | 可选     | ≤ 8 个 slug，`^[a-z0-9-]+$`；目录中不存在的标签会被忽略 |
| `status`      | 可选     | `draft`（默认）/ `published`                            |

\* `contentMd`、`githubUrl`、`externalUrl` 至少一项非空。

**构造时的判定规则：**

- `kind`：按内容性质推断（原创心得→`original`；介绍某个开源项目→`open-source`；技术讲解→`tech`；实操复盘/案例→`practice`）。**推断没有把握时 → 必须澄清**，列出四个栏目让用户选。
- `status`：用户明确说"发布/上线/published"才用 `published`；明确说"草稿/draft"用 `draft`；**未表态 → 必须澄清**（说明：draft 仅后台可见，published 会立即出现在前台）。
- `excerpt`：上下文没有现成摘要时，可基于正文提炼一段 12–360 字符的摘要，并在参数摘要中展示给用户。
- `tags`：只从用户明确给出的标签生成 slug（中文标签转拼音或询问用户对应 slug）；**不要自行发明标签**。用户给了标签但拿不准 slug 写法 → 必须澄清。
- 正文较长时优先读取用户指定的文件作为 `contentMd`；截断或改写正文前必须征得同意。

**调用脚本前，先向用户展示参数摘要**（标题、栏目、标签、status、正文字数），确认无误再执行——除非用户已明确表示直接保存。

## ③ 执行脚本调用 API

```bash
node .agents/skills/pwa-save-article/scripts/save_article.mjs --file <payload.json>
```

- 先用 `--dry-run` 可只做本地校验不发送（调试参数问题时先 dry-run）。
- 其他参数：`--key <pwai_…>`（临时密钥）、`--url <endpoint>`、`--stdin`（从管道读 JSON）、`--timeout <ms>`。
- 退出码：`0` 成功；`2` 前置检查失败（密钥/地址）；`3` 本地参数校验失败；`4` API 4xx；`5` 网络/5xx。
- 脚本输出人类可读摘要 + 原始 JSON，直接引用其输出，不要自己二次解析猜测。

## ④ 反馈结果

**成功（201）**：向用户报告——

- 标题、栏目 `kind`、状态 `status`、生成的 `slug`；
- `tagsApplied` 已生效的标签；若 `tagsIgnored` 非空，明确提醒哪些标签因不在标签目录中未生效；
- `status=published` 时给出前台路径 `/{kind}/{slug}`（如 `/tech/<slug>`）；`draft` 则说明需在管理后台查看。

**失败**：按退出码/HTTP 状态解释原因并给出下一步：

| 状态           | 含义                             | 建议动作                                       |
| -------------- | -------------------------------- | ---------------------------------------------- |
| `400`          | 参数校验失败（响应含 `details`） | 逐条修正 payload 后重试                        |
| `401`          | 密钥无效/已删除                  | 回到前置检查，请用户确认或重建密钥             |
| `413`          | 请求体 > 1 MB                    | 压缩或精简正文                                 |
| `429`          | 限流（约 30 次/分钟）            | 等待约 1 分钟再重试                            |
| `5xx`/网络错误 | 服务端或网络问题                 | 如实告知，不要自动重试写操作；询问用户是否重试 |

**任何失败都不得静默吞掉，也不得在未告知用户的情况下反复重试**（接口不做去重，盲目重试会产生重复文章）。

## 必须澄清的场景汇总

满足任一条件时，停止执行并向用户提问：

1. 找不到 API 密钥，或密钥格式不符合 `pwai_<64 hex>`；
2. `kind` 栏目无法从上下文可靠推断；
3. `status` 未明确（发布 or 草稿）且上下文无暗示；
4. 标签存在但 slug 写法拿不准；
5. 需要截断、改写用户正文，或正文来源有歧义；
6. 同一篇内容疑似已提交过，无法确认是否重复保存。

