SkillHub 网页发布(AI 填到「提交审核」前一步)
把 Skill 包送上 skillhub.cn。AI 的终点是「表单填好 + 截图给用户」,不是「发布成功」。
铁律
- 「提交审核」绝不代点。 提交后进入审核队列、公开可见,不可逆 —— 这是人类闸口。填完就把控制权交出去。
- 文件类型白名单在点「提交审核」时才校验。 传到表单里才发现有禁类文件 = 整份表单白填一遍。上传前必须自己先查一遍。
- 版本号默认永远是
1.0.0,必须手改成包的真实版本。 不改 = 谎报版本。 @eNref 会漂。 尤其是「上传 zip 之后」和「打开分类弹窗之后」,下方的 ref 整体重排。跨步骤复用旧 ref 必点错,每次操作前重取快照。
边界:什么时候不该走这条
| 情况 | 走哪 |
|---|---|
| 文件上传到本地技能站 | bsk(有 upload 命令) |
想用 browser-cdp 做上传 |
不行,它没 upload 命令,网页 JS 也造不出 File 对象 |
还没有合格的 zip(有 .bat/.ps1、缺 slug、有隐私泄露) |
先回头补,别直接上传 |
| 用户在浏览器里操作中被中断 | 先问,别自作主张续跑(可能用户正在手动改表单) |
前置
bsk可用(bsk status)。daemon 没起就放后台任务跑bsk daemon start --foreground—— 让它常驻,否则跨工具调用就断,会话连同填了一半的表单一起丢。- 已有要发的包与其 zip。
- 不需要任何专用脚本 —— 本文的「禁类清单」和「必填字段」本身就是手工 checklist。你自己若有流水线脚本,把它接进步骤 0 / 1 即可,本文不依赖任何特定仓库。
步骤
0. 预检(不可跳过)
逐条对照三项:
- 文件类型 —— 递归扫整个包(含
scripts/、隐藏文件),见下方禁类清单 - 隐私 —— 本机绝对路径、用户名、邮箱、内部项目名、会暴露用途的词,一个都不留
- 必填字段 —— frontmatter 里
name/slug/version/displayName齐不齐,name与slug与包目录名是否三者同名
> 只扫顶层是漏网之源 —— 禁类文件通常藏在 scripts/ 里。
自查禁类(对照用):
| 类别 | 后缀 |
|---|---|
| 允许 | .md .txt .json .yaml .yml .js .cjs .mjs .ts .py .png .jpg .svg |
| 禁·Windows 脚本 | .bat .cmd .ps1 .vbs .exe .dll .lnk .msi |
| 禁·其他脚本 | .sh .com .scr .hta .reg |
| 禁·二进制 / Office | .zip .rar .7z .iso .apk .jar .doc* .xls* .ppt* |
| 禁·杂项 | .log .tmp、隐藏文件 |
撞禁怎么办(两种救法,别直接砍功能):
1. 批处理脚本 → 改写成等价的 .py
2. 不能重写的驱动脚本 → 源码整段搬进 references/xxx.md 的代码块,正文写「首次使用落盘到临时目录再调用」。落盘内容必须保持 ASCII(PowerShell 5.1 按 ANSI 解析无 BOM 的 .ps1,塞中文直接语法报错)
1. 打包
把整个包目录打成 zip,zip 内顶层目录名必须等于 slug,否则平台认不出哪个是 SKILL.md。
Windows 默认没有 zip 命令,用 Python 即可:
import zipfile, pathlib
root = pathlib.Path("<包目录>") # 目录名 == slug
out = pathlib.Path("<输出目录>/<slug>-<version>.zip")
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
for p in sorted(root.rglob("*")):
if p.is_file() and "__pycache__" not in p.parts and not p.name.startswith("."):
z.write(p, f"{root.name}/{p.relative_to(root)}")
打完自己解回来看一眼目录结构,确认顶层确实是 slug 而不是一堆散文件。
> 打包绝不要用「目录里有什么就打什么」的全量模式。目标包必须是人工白名单,启发式反推会把第三方包和未脱敏包一起打进去。
2. 起会话、进发布页
bsk session start --json # 拿 session_id
bsk navigate "https://www.skillhub.cn/dashboard/publish" --session <S>
bsk snapshot --session <S> | grep -E 'button "发布 Skill' # 别肉眼翻两百行
进发布类型选择页后点 「发布 Skill 最快上架」(另一个 Pay Skill 是走支付的,不是这条路)。
3. 上传 zip —— 最容易翻车的一步
bsk snapshot --session <S> | grep 'button "选择 zip 文件"'
bsk click @e25 --session <S> # ① 先点可见按钮
bsk upload --file "绝对路径/<slug>-<version>.zip" @e25 --session <S> # ② 再对同一个 ref 传
为什么必须两步:隐藏的 input[type=file] 直接 upload --selector 会报 element not visible;先点可见按钮把选择器点开,再对同一 ref 传,才通。
传完先确认数量对不对(页面会显示「已选择 N 个文件,总大小 X KB」,并列出文件名)。
4. 填字段
bsk fill @eN --session <S> --value "<内容>" # 中文实测正常
必备四项 + 描述:
| 字段 | 怎么来 |
|---|---|
| Slug | 必须等于包目录名;平台认 slug,本地认 name |
| 显示名称 | 取 displayName(中文名,给用户看的) |
| 描述 | 优先点「使用此描述」 —— 平台会解析 SKILL.md 自动生成,比手打准 |
| 版本号 | 必改,抄包里的 version |
| 变更说明 | 先回源码核对再写。公开的字段不许凭印象编,改了什么就 grep 取证后再落笔 |
5. 选分类
点「请选择分类标签」→ 选一个一级 → 再勾最多 3 个二级。
这个弹窗没有「确定 / 关闭」按钮,选完直接:
bsk press Escape --session <S>
12 个一级分类:AI Agent / 商业运营 / 内容创作 / 数据分析 / 设计多媒体 / 开发编程 / 教育学习 / IT 运维与安全 / 知识管理 / 生活服务 / 办公效率 / 行业专业。(没有「游戏」)
6. 交付给用户
bsk screenshot --out "<本机临时目录>/publish-<slug>.png" --session <S>
然后把截图给用户,说清楚「请你 Alt+Tab 切到 Chrome 窗口,滚到底点提交审核」。
用户可能看不见那个窗口:bsk 开的是独立的 Agent Window,AI 侧没有把它前置到用户面前的办法(window 子命令只有 resize)。两条出路:
- 让用户 Alt+Tab / 点任务栏找标题带 SkillHub 的窗口
- 或者改走「借标签页」:让用户自己开好页面 → bsk tab borrow 接管 → 填完 bsk tab return 还回去(这条在本场景未实跑过,只在别的自动化任务里验证过命令存在;真要用先小步试一下)
踩坑表(全是踩过的)
| 症状 | 根因 | 正确做法 |
|---|---|---|
不允许的文件类型: scripts/xxx.bat |
提交那一步才校验,传到表单里才发现 | 步骤 0 递归预检 |
element not visible(上传时) |
隐藏 file input 不能直接当选择器 | 先点可见按钮,再 upload 同一 ref |
| 点了某个字段却改到了别的字段 | ref 在上传/开弹窗后整体位移 | 每次操作前重取 snapshot |
| 平台显示版本 1.0.0 | 版本号永远默认 1.0.0 | 手动改 |
| 会话、窗口连同表单一起没了 | daemon 没常驻 | daemon 用后台任务跑 --foreground |
session already has an unfinished command |
上一条命令还没回稳 | 中间 sleep 2 再发下一条 |
| 分类弹窗关不掉 | 弹窗本来就没有确认键 | bsk press Escape |
| AI 说「发布成功」了但列表里没有 | 其实没点提交,或点在错位 ref 上 | 提交前用快照核对每个字段的实际值,别信命令返回的 ok |
验收
让用户点完提交后,去 dashboard 的「我的 Skills」列表核一眼 —— 出现「显示名称 + slug + 分类 + V 版本号」才算真的发出去了。