站舰CMS 网站文章入驻 Skill(v1.0)
操作「站舰CMS」的 AI Agent 技能,专注于网站资讯文章入驻。核心能力:在指定频道/分类下入驻文章——频道列表查询、分类列表查询、文章列表查询、标题校验、获取网页访问地址、创建文章,全流程交互式入驻。
所有能力收敛到一个 CLI:zjcms(纯 Python 标准库实现,零第三方依赖,Python 3.8+ 即可运行)。
开始前先读 ./references/api-inventory.md(已确认接口与缺口)。任何写操作一律走 zjcms CLI,禁止凭记忆拼 HTTP 请求、禁止把 SESSION cookie 写入会被提交的源码。
> 本 skill 的授权 Key 逻辑(401 会话失效恢复 / 凭据加载 / 授权 Key 解析写回)与「网站单页入驻」(zhanjian-cms-page) 共用同一份核心模块(config.py / client.py / auth_recovery.py / autonomous.py)。两 skill 各自 vendor 同一份代码,由 build_dist.py 统一同步,保证授权逻辑一致。
何时使用
- "把这篇文章发到我的项目" / "入驻一篇资讯文章到 CMS"
- "查一下某频道下有哪些文章" / "列出可入驻的频道和分类"
- "连不上 CMS 了,怎么更新登录码"
> ⚠️ 生成文章 ≠ 自动入驻:agent 帮你写好文章文件后不会自动调用 article onboard,必须你明确说「入驻 / 发布到 CMS」等才会执行入驻。生成与入驻是两步,后者需你主动触发。
安装与凭据
技能本身无需 pip install。使用前准备凭据(二选一,优先级:环境变量 > scripts/dev/.env):
- 环境变量:
CMS_HOST、SESSION_COOKIE(裸令牌,不含SESSION=前缀)、PROJECT_ID。 - 文件:复制
scripts/dev/.env.example为scripts/dev/.env并填写你自己的值(该文件已被 gitignore,切勿提交)。
CMS_HOST 默认 cmsn.nsw99.com(测试环境)。生产环境用 zhanjian-cms-article-prod(域名 cmsn.nsw99.com)。会话令牌(SESSION_COOKIE)从浏览器登录后从 DevTools → Application → Cookies → 对应 host 复制。令牌过期后 CLI 会自动提示更新(见下方「会话失效恢复」)。
命令速查
# 列出可入驻频道(已验证)
python scripts/zjcms/cli.py channel list
# 列出某频道下的分类(已验证)
python scripts/zjcms/cli.py category list --channel <moduleId>
# 文章列表(分页)
python scripts/zjcms/cli.py article list --channel <moduleId> [--page-num 1] [--page-size 10]
# 交互式资讯文章入驻:选频道→选分类→校验标题→获取访问地址→创建文章
python scripts/zjcms/cli.py article onboard <文章目录> \
[--module-id <id>] [--category-id <id>] [--title <标题>] [--site <projectId>]
# 本地预览 401 登录码/项目选择弹窗(不联网)
python scripts/zjcms/cli.py auth demo
能力索引(v1 已实现)
| 命令 | 状态 | 说明 |
|---|---|---|
channel list |
✅ 已实装 | GET /pccms/module/extend/list/tree,可入驻频道列表 |
category list |
✅ 已实装 | GET /pccms/proj/infoCtg/list/all,频道分类列表 |
article list |
✅ 已实装 | GET /pccms/proj/infoArticle/list/all,文章列表(分页) |
article onboard |
✅ 已实装 | 交互式资讯文章入驻:选频道→选分类→校验标题→获取访问地址→创建文章 |
article create |
⏳ 规划中 | 直接 JSON payload 创建文章(article onboard 已覆盖) |
> 规划中命令的缺口见 references/api-inventory.md。实现前不要绕过 CLI 直接 curl 这些端点。
文章入驻前置要求
- 文章目录需包含
content.html(文章正文 HTML)与可选的meta.json(标题/SEO 等元数据)。 - 每篇文章必须指定所属频道与所属分类;若未用
--module-id/--category-id指定,CLI 会交互式列出让你选择(headless 环境需显式传参)。 - 标题不可与同频道已有文章重复(
validTitle校验),重复会中止并提示更换。
安全
- 写操作默认走
semi闸门:生成/打包后停下等人确认;本环境用--confirm显式放行。 - 凭据仅从环境变量或 gitignored 的
scripts/dev/.env读取,源码中不存在明文密钥。
会话失效恢复(401)
任意 CMS 调用返回 401 / 302 invalidSession,或 getProjectList 返回 200 但项目树为空(cookie 无权限/已失效)时,自动触发登录恢复:
- 自动用系统浏览器打开登录页(
CMS_LOGIN_URL),并弹出输入框(Tkinter 桌面弹窗;无图形界面时降级为控制台输入,headless 环境打印登录指引而非崩溃),提示客户重新登录后到后台「全局配置 > 网站信息 > 网站授权」复制最新授权 Key,按项目ID:授权Key发回。 - 解析并写回
scripts/dev/.env(SESSION_COOKIE+PROJECT_ID)。 - 用新凭证拉项目列表,列出可选项目供选择,选中后刷新凭据。
- 用新凭证重试原请求。
登录页入口与提示文案定义在 scripts/zjcms/auth_recovery.py 的 CMS_LOGIN_URL 与 LOGIN_HINT。open_login_url() 负责自动唤起浏览器(headless / 无浏览器时降级为打印 LOGIN_HINT 里的链接)。
目录结构
zhanjian-cms-article/
├── SKILL.md
├── scripts/
│ ├── zjcms/
│ │ ├── cli.py # argparse 入口(仅文章入驻子命令)
│ │ ├── client.py # L0:唯一直接调 CMS HTTP API 的模块(纯 urllib)— 共享核心
│ │ ├── config.py # 凭据加载 — 共享核心
│ │ ├── auth_recovery.py # 401 会话恢复(Tkinter/控制台)— 共享核心
│ │ └── autonomous.py # 写操作闸门 guard(advise/semi/auto)— 共享核心
│ └── dev/.env.example # 凭据模板(复制为 .env 填写)
└── references/
└── api-inventory.md # 已确认接口 + 缺口清单