DeerFlow 中的 Vercel 免认证一键部署技能:vercel-deploy-claimable 用法与实现原理全解析
【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow
本文围绕仓库内置技能包 skills/public/vercel-deploy-claimable/SKILL.md 展开,完整讲解该技能“免认证、可认领(claimable)”的 Vercel 部署工作流:从项目打包、框架自动识别、上传到返回 Preview URL / Claim URL 的每一步。读完本文,你可以直接在 DeerFlow 的沙箱或本地终端中复现这条部署链路,并理解底层脚本的判定逻辑与 JSON 输出契约,便于二次封装或排障。
技能概览:一个带 Claim URL 的部署技能
vercel-deploy是 DeerFlow 仓库skills/public/目录下随附的公开技能包,其目录结构很典型——一个描述用法的SKILL.md加一个承载逻辑的脚本:
- skills/public/vercel-deploy-claimable/SKILL.md:技能元数据与操作说明;
- skills/public/vercel-deploy-claimable/scripts/deploy.sh:实际完成打包、上传与结果解析的 Bash 脚本。
从 SKILL.md 的 YAML front matter 可以看到它的核心定位:
name: vercel-deploy description: Deploy applications and websites to Vercel. Use this skill when the user requests deployment actions such as "Deploy my app", "Deploy this to production", "Create a preview deployment", "Deploy and give me the link", or "Push this live". No authentication required - returns preview URL and claimable deployment link. metadata: author: vercel version: "1.0.0"其中几个关键词值得注意:
- 触发意图:覆盖 “Deploy my app”“Deploy this to production”“Create a preview deployment”“Push this live” 等自然语言指令;
- 无需认证:不需要 Vercel Token、环境变量或 OAuth 流程;
- 输出两段链接:
previewUrl让用户立刻访问线上站点,claimUrl用于把该次部署转交到用户自己的 Vercel 账户。
这与 DeerFlow 的技能体系天然契合。根据 README.md 中“Skills & Tools”一节的说明,技能只有在任务需要时才被渐进式加载,保持上下文窗口精简;一个技能目录是一个包边界,一旦发现其下的SKILL.md,就会作为一个运行时技能注册。也就是说,Agent 在收到“帮我部署”这类请求并命中本技能时,才会读取本说明并把deploy.sh作为可执行步骤。
工作原理:一次免认证部署的四步链路
SKILL.md 用四句话概括了整体流程:
- 把项目打包成 tarball(排除
node_modules与.git); - 从
package.json自动识别框架类型; - 上传到部署服务;
- 返回Preview URL(可立即访问的线上地址)与Claim URL(用于把部署移交到你的 Vercel 账户)。
展开到 deploy.sh 源码层面,这条链路其实由五个明确阶段构成,脚本头部注释也给出了调用契约:
# Vercel Deployment Script (via claimable deploy endpoint) # Usage: ./deploy.sh [project-path] # Returns: JSON with previewUrl, claimUrl, deploymentId, projectId阶段一:解析输入路径
# Parse arguments INPUT_PATH="${1:-.}"脚本只接受一个可选参数INPUT_PATH,默认值为当前目录.。随后用mktemp -d创建临时目录存放打包产物,并通过trap cleanup EXIT保证无论正常结束还是异常退出,临时文件都会被清理(仅当输入为已存在的 tarball 时跳过清理)。
阶段二:判定输入类型并识别框架
脚本对输入做了三分支处理:
- 输入是
.tgz文件:直接使用该 tarball,跳过重新打包,此时无法从 tarball 内识别框架,FRAMEWORK保持null; - 输入是目录:先用
cd "$INPUT_PATH" && pwd解析出绝对路径,再调用detect_framework "$PROJECT_PATH/package.json"识别框架;若目录下没有package.json,则按“静态 HTML 项目”特殊处理(见下文); - 输入既不是目录也不是
.tgz:打印Error: Input must be a directory or a .tgz file并exit 1。
阶段三:打包项目
tar -czf "$TARBALL" -C "$PROJECT_PATH" --exclude='node_modules' --exclude='.git' .这是整个流程里唯一的“体积优化”手段:node_modules与.git都被排除在压缩包外,避免把本地依赖和历史提交上传到部署服务,也显著减小上传体积。
阶段四:上传部署端点
DEPLOY_ENDPOINT="https://claude-skills-deploy.vercel.com/api/deploy" ... RESPONSE=$(curl -s -X POST "$DEPLOY_ENDPOINT" -F "file=@$TARBALL" -F "framework=$FRAMEWORK")部署端点来自脚本常量。请求以multipart/form-data形式上送两个字段:file(指向打包好的 tarball)与framework(识别出的框架标识,未识别时为"null")。整个交互不需要任何凭据——认证被“后置”到了 Claim URL 阶段。
阶段五:解析与错误处理
脚本对返回的 JSON 做了三重防御式解析:
- 若响应包含
"error"字段,则提取错误消息并退出(exit 1); - 用
grep+cut从 JSON 字符串中提取"previewUrl"与"claimUrl"; - 若拿不到
previewUrl,把原始响应打印到 stderr 后报错退出,方便定位服务端异常。
可以看到,虽然解析方式朴素,但成功/失败路径的边界清晰,配合set -e,任何一步失败都会立即中断,不会带着残缺结果“假装成功”。
命令行用法:参数、示例与路径适配
SKILL.md 给出的标准调用方式是(注意其中路径是该技能在 Vercel 官方技能环境中的安装位置):
bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh [path]参数说明:
| 参数 | 含义 | 默认值 |
|---|---|---|
path | 待部署的目录,或一个.tgz文件 | 当前目录(.) |
三个典型示例:
# 部署当前目录 bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh # 部署指定项目目录 bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project # 直接部署已存在的 tarball bash /mnt/skills/user/vercel-deploy/scripts/deploy.sh /path/to/project.tgz路径适配提示:/mnt/skills/user/vercel-deploy/...是脚本作者在原始宿主环境(claude.ai 类技能沙箱)下的固定路径。在本仓库内,该技能包实际位于 skills/public/vercel-deploy-claimable/;因此若要在本地终端直接验证,可把仓库内的脚本本身作为参数源:
bash skills/public/vercel-deploy-claimable/scripts/deploy.sh /path/to/project在 DeerFlow 沙箱中执行时,需要以沙箱内实际的技能挂载前缀为准——仓库内其他内置技能(如data-analysis、image-generation等)的 SKILL.md 都采用/mnt/skills/public/<技能名>/scripts/...的调用约定,据此可以推断本技能被启用后沙箱内路径形如/mnt/skills/public/vercel-deploy-claimable/scripts/deploy.sh;若你把技能安装到 custom/integrations 等其它位置,前缀会相应变化。同时注意 README 中说明 DeerFlow 的沙箱只会把“已启用”技能投影到/mnt/skills,因此技能需先在设置中启用。
输出解读:人类可读与机器可读两套结果
标准输出(面向用户/日志)
SKILL.md 给出了完整的过程输出示例:
Preparing deployment... Detected framework: nextjs Creating deployment package... Deploying... ✓ Deployment successful! Preview URL: https://skill-deploy-abc123.vercel.app Claim URL: https://vercel.com/claim-deployment?code=...对照源码可知,这些进度信息是脚本刻意打到stderr(>&2)的,包括Preparing deployment...、Detected framework: $FRAMEWORK、Creating deployment package...、Deploying...、成功后的Preview URL:与Claim URL:两行;其中Detected framework仅在框架非null时打印,若项目无框架则直接跳过该行。
JSON 输出(面向程序化消费)
SKILL.md 明确强调:“The script also outputs JSON to stdout for programmatic use”。脚本在最后执行echo "$RESPONSE",把服务端返回的原始 JSON 完整输出到stdout。字段契约如下:
{ "previewUrl": "https://skill-deploy-abc123.vercel.app", "claimUrl": "https://vercel.com/claim-deployment?code=...", "deploymentId": "dpl_...", "projectId": "prj_..." }| 字段 | 含义 |
|---|---|
previewUrl | 部署成功后立即可访问的线上站点地址 |
claimUrl | 携带认领码的链接,用于把部署移交到你的 Vercel 账户 |
deploymentId | 部署标识(形如dpl_...) |
projectId | 项目标识(形如prj_...) |
这种“进度走 stderr、结果走 stdout”的设计在自动化场景下非常实用:Agent 或上层程序可以放心地把脚本 stdout 直接喂给 JSON 解析器,而不会被中间的过程日志污染。
框架自动检测:判定顺序比想象中更讲究
detect_framework()函数是脚本里逻辑最重的部分。它先从目录中读取package.json,若文件不存在则直接返回null;存在时通过has_dep()辅助函数对 package 名做grep精确匹配(不区分 dependencies 与 devDependencies,只要依赖串中出现即命中)。
源码第 27 行的注释点明了关键设计——顺序即优先级:“Order matters - check more specific frameworks first”。因为某些框架会组合出现(例如 Next.js 项目里可能同时有vite、express等间接依赖),必须把“特异性最强”的框架放在前面。实测判定顺序如下:
| 类别 | 框架 | 检测的依赖包名 |
|---|---|---|
| 全栈/SSR | Blitz | blitz |
| Next.js | next | |
| Gatsby | gatsby | |
| Remix | @remix-run/ | |
| React Router(v7 框架模式) | @react-router/ | |
| TanStack Start | @tanstack/start | |
| RedwoodJS | @redwoodjs/ | |
| Hydrogen(Shopify) | @shopify/hydrogen | |
| Vue 生态 | Nuxt | nuxt |
| Vitepress | vitepress | |
| Vuepress | vuepress | |
| Gridsome | gridsome | |
| Svelte 生态 | SvelteKit | @sveltejs/kit(映射sveltekit-1) |
| Svelte(独立) | svelte | |
| Sapper | sapper | |
| 其它前端 | Astro | astro |
| SolidStart | @solidjs/start(映射solidstart-1) | |
| Docusaurus | @docusaurus/core(映射docusaurus-2) | |
| Angular / Ionic Angular | @angular/core/@ionic/angular | |
| Ionic React | @ionic/react | |
| Create React App | react-scripts(映射create-react-app) | |
| Ember | ember-cli或ember-source | |
| Dojo | @dojo/framework | |
| Polymer | @polymer/ | |
| Preact | preact | |
| Stencil | @stencil/core | |
| UmiJS | umi(映射umijs) | |
| Hexo | hexo | |
| Eleventy | @11ty/eleventy | |
| Saber | saber | |
| Sanity | sanity或@sanity/ | |
| Storybook | @storybook/ | |
| 后端框架 | NestJS | @nestjs/core |
| Elysia | elysia | |
| Hono | hono | |
| Fastify | fastify | |
| h3 | h3 | |
| Nitro | nitropack | |
| Express | express | |
| 构建工具 | Vite | vite(注释明确标注“generic - check last among JS frameworks”) |
| Parcel | parcel | |
| 未命中 | —— | 返回null |
SKILL.md 中对支持范围的归纳是“And more”(还有更多),上面这个表则是脚本中实际可判定的完整清单。两个细节值得单独说明:
- Vitepress / Vuepress 先于 Nuxt 之后的 Svelte 系——同一 Vue 技术栈内,文档站框架(vitepress/vuepress)要先于 gridsooms 等判定;
- Vite 被刻意放在几乎所有 JS 框架之后,因为 Vite 更多是作为底层构建器出现在其它项目里,过早命中会产生错误归属。
对于纯静态 HTML 项目(无package.json),框架统一被置为null。
静态 HTML 项目的贴心处理
SKILL.md 特别说明了对“没有package.json的纯静态项目”的一条自动修正逻辑:
If there's a single
.htmlfile not namedindex.html, it gets renamed automatically. This ensures the page is served at the root URL (/).
落到源码上是这样一段:当检测到目录没有package.json时,脚本会在项目根目录(-maxdepth 1)查找.html文件;如果恰好只有一个HTML 文件、且其文件名不是index.html,就用mv把它改名为index.html,并在 stderr 打印Renaming <basename> to index.html...。
这意味着:你随手写了一个demo.html,不需要手动建目录结构,技能会保证它在部署后直接以站点根路径/提供服务。当然,这个逻辑只在“仅一个 HTML 文件”时触发——多文件站点仍需自行保证存在index.html作为入口。
向用户呈现结果的最佳实践
SKILL.md 用一个可复制的“结果呈现模板”明确要求:两个 URL 必须同时展示,缺一不可:
✓ Deployment successful! - [Preview URL](https://skill-deploy-abc123.vercel.app) - [Claim URL](https://vercel.com/claim-deployment?code=...) View your site at the Preview URL. To transfer this deployment to your Vercel account, visit the Claim URL.其语义拆解是:
- Preview URL= “现在就能看的站点”,引导用户立即打开验证效果;
- Claim URL= “把它变成你的”入口,因为本次部署没有绑定任何账户,用户需要访问该链接、通过
code认领后,部署才会出现在自己的 Vercel 项目列表中。
对于 Agent 而言,这条模板同时是一次很好的“结果结构规范”:以✓ Deployment successful!收束动作,再给出主结果(Preview URL)和后续动作指引(Claim URL),避免用户拿到一堆过程日志却不知道链接在哪。
故障排查:网络出口受限怎么办
SKILL.md 记录了唯一一个内置的故障场景:Network Egress Error——当部署因网络限制失败时(常见于运行在 claude.ai 之类受限网络环境中的技能调用),要这样引导用户修复:
Deployment failed due to network restrictions. To fix this: 1. Go to https://claude.ai/settings/capabilities 2. Add *.vercel.com to the allowed domains 3. Try deploying again也就是说,本技能依赖对 Vercel 部署服务的出网访问,如果所在平台有域名白名单机制,就需要把*.vercel.com加入允许列表后再重试。需要强调的是,在 DeerFlow 中执行时,网络出口策略取决于 DeerFlow 自身的沙箱/代理配置,而不再受 claude.ai 的 capabilities 限制;若遇到出网被沙箱网络策略拦截,应检查 DeerFlow 侧的网络白名单与代理设置。
适用前提、限制与注意事项
从文档与脚本双重证据出发,使用本技能时应清楚以下几点边界:
- 运行前提:宿主需具备
bash、tar、curl、grep等 POSIX 常用工具(deploy.sh 全部依赖它们);部署过程要求能够访问部署服务端点。 - 无需但也不支持现有凭据注入:脚本不带任何认证参数,上传即部署;账户绑定通过 Claim URL 在浏览器侧完成,因此不适合需要“直接部署进指定 Vercel 账户/Team 并走其现有环境变量”的场景。
- 体积控制:
node_modules与.git会被排除,但脚本并未内置其它文件过滤或体积上限校验,超大仓库或包含大体积资源文件的目录需要自行评估。 - 框架识别是启发式的:它基于
package.json依赖串做顺序匹配,而不是读取框架配置或构建产物;识别错误时可考虑先自行用 Vercel 框架预设或直接传入构建结果。 - 错误处理是防御式的:服务端返回的
error、缺失previewUrl都会导致脚本非零退出并把现场信息打到 stderr,供上层 Agent 读取并转述。
在 DeerFlow 中把它用起来
结合 README.md 对 DeerFlow 技能机制的描述,这套vercel-deploy技能包在 DeerFlow 中遵循统一的技能生命周期:
- 发现与加载:技能只在任务命中其描述时才被渐进式加载,不会常驻上下文;
- 启用与可见性:技能启用后才会被投影进沙箱的
/mnt/skills文件系统视图,关闭技能会同时将其从沙箱中移除(参见 README 中关于沙箱挂载与启用状态的说明); - 单轮激活:用户/Agent 可在单条请求中用
/skill-name前缀显式激活技能,使其SKILL.md作为本轮隐藏上下文加载,从而保证deploy.sh被正确、完整地执行而不是被“总结成一句建议”。
换句话说,本技能包在仓库里的角色是“部署动作的落地执行器”,它把 Vercel 的免认证 claimable 部署接口封装成了统一的 Bash 契约;而 DeerFlow 技能框架负责把它变成 Agent 可按需取用、可重复执行的标准能力。理解了两层各自的分工,无论是直接调用脚本、还是把它接入自己的 Agent 工作流,都能获得稳定一致的结果。
【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考