用 AI Agent 把本地项目发布到华为云作品展览馆:一条 8 步流水线的踩坑记录
起因
成长中心有个任务:在开发者作品展览馆发布作品,加 200 分。我点「去完成」,发现展览馆根本没有手工上传入口——个人中心只有「我的作品」列表和一句「你还没有发布作品」。
翻页面底部找到「查看发布步骤」,才看到官方给的路径:发布这件事是由 AI 在对话里完成的,网页端只负责展示。
官方路径长什么样
提交指引页把流程拆成三步:生成并验收作品 → 在 AI 对话中安装 Skill 并发出发布口令 → 发布朋友圈。核心是这一条:
npx skills add https://gitcode.com/Lingxi-HandsOn/gallery.git --skill huawei-cloud-publish-work-to-gallery -y
装完之后,只要说一句「请将当前项目发布至开发者作品展览馆」,剩下的由 Skill 里的脚本接管。
为什么网页端不做上传按钮
我翻了展览馆前端的 JS bundle,open-web-guest 和 open-web-user 前缀下有一大批接口:作品列表、投票、点赞、分享、校区作品、排行榜、后台管理……唯独没有「提交作品」。
提交走的是另一套 open-api-public,要求三个请求头:X-Tmp-Ak、X-Tmp-Sk、X-Security-Token。也就是说,提交必须携带 STS 临时凭证,网关验完身份再注入 X-Domain-Id 给服务端。这是个刻意的架构选择:作品关联到哪个账号,由网关认证决定,前端说不了算。
8 步流水线
Skill 把这套流程拆成 8 个阶段,前一步的产物是后一步的输入:
| 步骤 | 产出 |
|---|---|
| 1 | 作品目录、账号 Domain ID、STS 临时凭证 |
| 2 | 本地服务端口、隧道访问地址 |
| 3 | git 仓库地址、分支、作品名 |
| 4 | 封面图(需过字形校验) |
| 5 | 一句话简介(严格 15~50 字符) |
| 6 | 作品详情包(文章 + 架构图,打包成 zip) |
| 7 | 投稿活动 ID |
| 8 | 发布请求 + 积分领取 |
有几个约束卡得很死,第一次跑会反复撞墙:
- 封面比例必须 16:9,且标题文字要过像素级字形校验,防止中文渲染成豆腐块
- 简介 15~50 字符,超一个字都不行
- 详情文章 500~1500 字,必须配一张系统架构图
- 发布前有门禁复核,任何一项不达标直接拒绝发请求
踩到的坑
一、Skill 仓库曾经是私有的
云声上有人反馈过:gitcode.com/Lingxi-HandsOn/gallery.git 一度变成私有仓库,导致命令直接失败。我这次试的时候已经修好了,能正常 clone。如果你遇到失败,先确认仓库可访问。
二、换行符把 shell 脚本干掉了
克隆下来的 preflight.sh 带 CRLF,在 Linux 里执行报 $'\r': command not found,紧接着 set: pipefail: invalid option name。原因是回车符被 shell 当成了命令名。修法很简单:
find scripts -type f -name '*.sh' -exec sed -i 's/\r$//' {} +
chmod +x scripts/*
三、没有 AK/SK 就没有 STS
Step 1 要用 hcloud 调 IAM 拿 Domain ID,再自委托换临时凭证。本机既没装 hcloud、也没配 AK/SK。
绕法是用 AI 开发者空间的体验版容器——那里的 hcloud 已经配好了凭证(~/.hcloud/config.json 加加密的 cipher.json),而且是 Linux,隧道能力也完整。
四、两阶段 OAuth,链接 300 秒就过期
GitCode 授权分两段:--start 立刻返回一个登录链接和 session_id,--wait 阻塞轮询到用户授权完成。
链接有效期只有 300 秒。我前后生成了三次才在窗口内点完。如果超时,只能重新 --start,之前那次 session 就废了。
五、门禁标记文件缺失
check-gates 报 ensure-utf8 标记不存在,直接判定「禁止发布」。补跑一次编码检查脚本生成标记即可。这类失败信息其实很友好——它明确告诉你缺哪个标记、回退到哪一步修。
两个设计上值得说的点
自委托:永久密钥不出容器
流程会在你的账号里创建一个叫 SELF_VERIFY 的 IAM 自委托(委托方和被委托方都是你自己),然后每次发布时 AssumeAgency 换一个 900 秒有效、最小权限的临时凭证。
网关拿到临时凭证后只做两件事:STS.GetCallerIdentity 确认账号 ID,IAM.listAuthDomains 解析账号名。用完即弃,永久 AK/SK 全程不离开本机。
凭证文件里还写了 _refresh 元数据(accountId、agencyUrn、region),这样发布过程中如果凭证过期,请求收到 401 会自动重新 AssumeAgency 并重试一次。整个流程(装字体、下 Chromium、截图、合成封面、渲染架构图)经常超过 900 秒,这个自动刷新是必需的。
门禁不是摆设
publish-work.mjs 在真正发请求之前会再跑一遍 check-gates,复核封面尺寸比例、详情包大小、各步骤标记的新鲜度(默认 1 小时)。任一不过就不发请求。
另外还有个幂等键 gallery-publish-<domainID>-<timestamp>,避免重复提交。
最终结果
#status=201
workId=0073087761800000
workName=WordsMatch
reward=success value=200 msg=成功
发布成功后接口直接把积分领取结果一起返回,reward 字段告诉我 200 分已经到手——这次没有等成长中心的延迟同步,发布接口是即时发放的。
作品页能看到封面、简介、作者、投稿活动、代码仓库地址和体验入口,全部自动生成。
小结
这套东西的本质是:把「发布」这个动作从人肉填表,变成一条带门禁的自动化流水线。门槛在于前置条件(hcloud、STS、OAuth),一旦打通,后面每次发布基本是零操作。
几个实操建议:
- 项目本身要有
.git和公开远端仓库(GitHub / GitCode / Gitee 都支持),别现建 - 在 Linux 环境跑,隧道和字体都更顺;Windows 上要自己处理换行符和 zip
- OAuth 链接生成后马上点,别拖
- 这个任务每月只能领一次积分,重复发布不会重复加分
- 点赞
- 收藏
- 关注作者
评论(0)