dsh-plugin-deploy

一句话把项目发到 Cloudflare,一句话把插件发到 npm。
DeepSeek Harness 插件 · 没有云账号也能拿到线上地址 · 凭据模型看不到

npm license harness tests tracks dsh.pub

简体中文 · English

--- ``` 你:帮我把这个网站发出去 Agent:调用 deploy 工具 … ┌─────────────────────────────────────────┐ │ 临时预览地址 │ │ https://my-site.breezy-broom.workers.dev │ │ ⏱ 必须认领,否则会被删除 · 剩余 60 minutes │ │ [打开认领链接] │ └─────────────────────────────────────────┘ ``` **没有 Cloudflare 账号也能拿到能打开的线上地址。** 这不是模拟——用的是 Cloudflare 官方为 AI agent 设计的临时预览账号。 --- ## 目录 - [它解决什么问题](#它解决什么问题) - [30 秒开始](#30-秒开始) - [能力一:把项目部署到 Cloudflare](#能力一把项目部署到-cloudflare) - [能力二:把你做的 dsh 插件发布出去](#能力二把你做的-dsh-插件发布出去) - [不想打字?会话标题旁有个按钮](#不想打字会话标题旁有个按钮) - [配置凭据](#配置凭据) - [它为什么会打断你](#它为什么会打断你) - [安全设计](#安全设计) - [已知限制](#已知限制) - [常见问题](#常见问题) - [从源码开发](#从源码开发) - [致谢与相关项目](#致谢与相关项目) - [License](#license) --- ## 它解决什么问题 AI 帮你写完了一个网站、一个 Worker、一个插件——然后卡在最后一公里: | 你想做的事 | 没有这个插件时 | 有了之后 | |---|---|---| | 把刚做好的页面发出去看看 | 注册 Cloudflare → 建项目 → 装 wrangler → 写配置 → 调试认证 | 说一句「发出去」,拿到 URL | | 部署到自己的账号 | 每次都要处理认证状态、写 `wrangler.jsonc` | 存一次 token 引用名,之后一句话 | | 把做好的 dsh 插件发布 | 手动检查 9 处易错点 → `npm pack` 看清单 → `npm publish` 撞 2FA | 一条命令,校验不过就不让发 | 而且它**不会**为了省事牺牲安全:token 永远不进对话、不进日志;对外发布一定要你点确认。 --- ## 30 秒开始 ```sh # 装进你的 dsh profile(需要 pnpm 在 PATH 上) npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add dsh-plugin-deploy@0.2.2 # 启动 npx @deepseek-ai/dsh@0.2.1-rc.2 web ``` 桌面版可在插件市场更新,或使用**桌面版附带的** CLI:`dsh plugin --profile desktop add dsh-plugin-deploy@0.2.2`。先确认 `dsh --version`;PATH 中的旧 CLI 可能与桌面版不同。 然后在对话里说: > 帮我把 `./my-site` 这个目录发出去 就这样。**首次不需要任何账号**——插件会走 Cloudflare 的临时预览账号,几十秒后给你一个能打开的地址。 > [!NOTE] > 需要本机装了 [Wrangler](https://developers.cloudflare.com/workers/wrangler/install-and-update/) ≥ 4.102.0(临时预览要求)。没装的话插件会告诉你怎么装,不会闷头失败。 > [!TIP] > **刚发布的新版本装不到?** pnpm 有 `minimumReleaseAge` 供应链保护,新版本在冷却期内不会被自动选中——`add dsh-plugin-deploy` 可能装到上一个版本。想立刻用最新版就显式指定:`add dsh-plugin-deploy@0.2.2`。 --- ## 能力一:把项目部署到 Cloudflare 插件提供工具 `deploy` 与斜杠命令 `/deploy`。 ### 两种模式,自动选,也可以指定 | 模式 | 适合谁 | 拿到什么 | 需要账号吗 | |---|---|---|---| | **`temporary`** 临时预览 | 想立刻看效果、还没有 Cloudflare 账号 | `*.workers.dev` 地址 + **60 分钟**认领窗口 | ❌ 不需要 | | **`account`** 自有账号 | 要长期在线的正式地址 | 你账号下的持久 URL | ✅ 需要(token 或已 `wrangler login`) | 默认 `auto`:本机已认证就走 `account`,没认证就走 `temporary`。想强制某一种,直接说「用临时预览」或「发到我的账号」。 ### 关于临时预览,你必须知道的 这是 Cloudflare 官方能力([Claim deployments](https://developers.cloudflare.com/workers/platform/claim-deployments/)),文档里明写是为 AI agent 场景设计的。但有个硬约束: > [!WARNING] > **60 分钟内不认领,Cloudflare 会删除该临时账号及其全部资源。** > 插件会在结果卡片里显示倒计时和认领链接,并在下次部署时提醒你还有未认领的记录。 > 认领链接本身是一种凭据,它会出现在会话记录里——**别把这个会话分享出去**。 插件在文案上严格区分:临时预览叫「临时预览地址」,绝不说成「已上线」。 ### 支持的项目形态 - 纯静态目录(`index.html` 等) - Vite 类构建产物(`dist/`) - 已有 `wrangler.jsonc` / `wrangler.toml` / `wrangler.json` 的 Worker 项目 检测不出来时**会问你**,不会瞎猜。没有 wrangler 配置的项目,插件会临时生成一份——写在系统临时目录,**不往你的仓库里塞文件**。 --- ## 能力二:把你做的 dsh 插件发布出去 插件提供工具 `publish_plugin` 与斜杠命令 `/publish-plugin`。 > 这部分是给**插件作者**用的:你用 dsh 写了个插件,想让别人装得上。 ### 三种模式 ```sh check # 只校验,不执行包脚本、不改项目文件(默认) pack # 校验通过 → 打出 .tgz npm # 校验通过 + 你点确认 → 发布到 npm ``` ### 校验才是重点 生态里大量插件「装上了但不激活」「npm 发布漏文件」「GitHub 装下来缺 lib/」。发布前这 9 条会逐项检查: | 检查 | 拦住什么 | |---|---| | `dsh-compat` | 使用当前宿主的兼容性规则检查 `engines.dsh`(优先)或 DSH peer 范围,拦住新版安装拒绝 | | `dsh-plugin` | 没有 `dsh.bundle.patch` → 装了不激活,只有一行 stderr 警告 | | `patch-in-pack` | patch 文件没进 npm 包 → 同上,但更隐蔽 | | `client-bundle` | `lib/client.js` 不是 factory 形态或 id 不匹配 → 浏览器报 `loaded without registering` | | `main-entry` | 主入口没进包 | | `deps` | 残留 `workspace:` 协议 → 用户装不上;`@deepseek-ai/dsh*` 写成 `0.0.x` → 装到旧 train | | `pack-clean` | `.env` / `.npmrc` / 私钥 / `node_modules` 混进发布包 | | `version-available` | 版本号已被占用 | | `scan` | 如果你的仓里装了 [dsh-plugin-assistant](https://github.com/Octo-o-o-o/dsh-plugin-assistant),顺带跑一遍它的规则扫描 | **任何一条不过,`pack` 和 `npm` 都不执行**(fail closed)。 检查、打包和发布均不会执行目标包的生命周期脚本;请先构建 `lib/` 等发布产物,再调用本工具。 ### 发布到 npm ``` 你:把这个插件发布到 npm Agent:[9 条校验全过] → [审批:即将发布 xxx@0.1.0 到公共仓库] → 你点「允许一次」→ 发布 ``` npm 的 token 处理和别的工具不同——它**不读环境变量**。插件的做法是:临时 `.npmrc` 里只写 `${DSH_NPM_TOKEN}` 这个引用,真值经进程环境传给 npm,用完删除。**不碰你的 `~/.npmrc`,token 不落盘。** > [!TIP] > 本插件非交互式直接发布需要具有发布权限且开启 **Bypass 2FA** 的 **granular token**,并须符合账号、组织和包的策略。设置较短有效期,用完撤销;策略禁止绕过二次验证时,改用终端交互式发布或 [npm 官方 staging 流程](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages/#staged-publishing),当前插件不支持 staging。参见 [npm 直接发布要求](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages/#direct-publishing)。 --- ## 不想打字?会话标题旁有个按钮 装好后,会话标题旁边的动作栏会多出一个 **发布** 按钮(点开是两个选项): | 选项 | 等价于你手打 | |---|---| | 部署到 Cloudflare | 「把当前工作区部署到 Cloudflare」 | | 检查插件发布 | 「检查当前工作区能否作为 dsh 插件发布」 | > [!IMPORTANT] > 按钮**不会**绕过 agent 直接执行。它做的是把这句话写进输入框并提交——之后一切照常:模型调工具、条款确认、审批、结果卡片、会话记录,一个不少。 > > 这是刻意的。dsh 的 `approval.request()` 强制要求在**开启的 agent turn 内**调用(源码原文:`the approval/asked + approval/decided audit pair must be turn-enclosed`)。UI 直接触发的动作既拿不到审批,也不会留下会话记录——对不可逆的对外动作,那是不能接受的。 **它对哪个目录生效?** 按钮不硬编码路径,用的是**当前会话的工作区**。所以: - 想让它直接可用 → 把会话工作区选成你的项目 / 插件仓 - 工作区是个容器目录(比如 `~/WorkSpace`)→ agent 会告诉你「这不是一个插件包」,这时直接打字说明目录即可 草稿里已经有内容时按钮会禁用(`setDraft` 是全量写入,避免冲掉你写了一半的话);agent 正忙时也不会抢。 部署 / 校验的结果卡片上还有「重新部署」「重新校验」,走同一条路径。 --- ## 配置凭据 进侧栏 **插件 → 已安装 → dsh-plugin-deploy**,展开 **Cloudflare 部署** 卡片: | 字段 | 填什么 | 说明 | |---|---|---| | API token 引用名 | 默认 `CLOUDFLARE_API_TOKEN` | 这里填的是**名字**,不是 token 本身 | | npm token 引用名 | 默认 `NPM_TOKEN` | 同上 | | 写入 token 值(只写) | 粘贴真实 token | 保存后输入框清空,**永不回填**;右侧胶囊显示「已配置 / 未配置」 | 改动会留在卡片里,点底部**保存**才写入;**放弃修改**退回上次保存的状态。卡片有未保存改动时,收起状态下标题旁也会显示「未保存」徽章。 设计上分成两层:**配置里只存引用名**,**值交给 dsh 凭据服务**(存在 `$DSH_HOME/.credentials.yaml`,权限 `0600`)。卡片只会告诉你「已配置 / 未配置」,任何界面、任何响应都拿不到值。 在两个「写入 token」输入框下,可以展开「如何获取 Cloudflare token / npm token」:页面直接提供官方入口、创建步骤、资源范围、发布权限与保存方法。说明默认折叠,已配置用户可直接使用原来的表单。 Cloudflare 可使用 `Edit Cloudflare Workers` 模板创建 token。把 Account Resources 限定到部署使用的账号;配置了自定义域名路由时,把 Zone Resources 限定到对应站点,不需要路由时移除 Workers Routes 写权限。按项目实际使用的服务移除未使用的 KV、R2、Tail 等权限,并设置较短有效期。推荐配置 API token;本机终端的 `wrangler login` 登录状态在默认 `workspace-write` 沙箱中可能无法读取,使用前需确认当前权限允许访问登录状态。参见 [Cloudflare 创建说明](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/)和[模板默认权限](https://developers.cloudflare.com/fundamentals/api/reference/template/)。 npm token 需要 `Read and write (publish and stage)` 权限,访问范围限定到目标包或作用域。本插件以非交互方式直接发布,因此必须开启 **Bypass 2FA**,且账号、组织和包的策略允许使用此类 token。若策略禁止绕过二次验证,改用终端交互式发布或 npm 官方 staging 流程。`stage only` token 无法用于本插件的直接发布;当前插件尚未提供 staging 流程。参见 [npm 创建说明](https://docs.npmjs.com/creating-and-viewing-access-tokens/)和[直接发布要求](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages/#direct-publishing)。 --- ## 它为什么会打断你 这个插件会在两个地方停下来问你。这是刻意设计,不是没做完: **1. 服务条款**(仅临时预览) 创建临时账号等于接受 Cloudflare 的服务条款与隐私政策。wrangler 在非交互环境下会**自动替你接受**——插件不接受这种默认,会把两个链接原样摆出来让你确认。 **2. 发布审批** 部署到公网、发布到 npm 都是不可逆的对外动作。插件走 dsh 的 approval 通道申请一次性授权,**只有你点「允许一次」才继续**;拒绝、超时、审批服务不可用,一律中止(fail closed)。审批理由里不含任何凭据。 --- ## 安全设计 | 措施 | 具体做法 | |---|---| | 凭据不进模型上下文 | 工具参数里**没有** token 字段,只有引用名;值经进程环境变量传给子进程 | | 凭据不进日志 | dsh 的核心不变量是「模型可见 ⟺ 被记录」,所以 token 绝不进命令行、结果文本、审批理由 | | 输出脱敏 | 命令输出返回前过滤 token / `_authToken` / `Bearer` 等形态 | | 不污染你的环境 | 临时配置、tarball、npm cache 全部写系统临时目录;不改 `~/.wrangler`、不改 `~/.npmrc` | | 临时预览用隔离环境 | 走独立 `HOME`,读不到你本机的 Cloudflare 凭据,也**不需要你登出** | | 不可逆动作要审批 | 部署、发布都要一次性授权 | --- ## 已知限制 如实列出,不粉饰: - **只支持 Cloudflare**。Vercel / Netlify / VPS / 自定义域 / 回滚 / Next.js SSR(OpenNext)都不在当前范围。 - **临时预览 60 分钟过期**,不认领就没了。这是 Cloudflare 的规则,插件只能提醒。 - **临时账号资产上限**:≤1,000 个文件、单文件 ≤5 MiB。 - **`account` 模式下 wrangler 会写 `~/.wrangler/logs`**,在 Workspace Write 沙箱下可能报 `EPERM`。实测不影响部署结果(退出码 0),属噪音。 - **stderr 有 64 KB 上限**(harness 未暴露 `stderrMaxBytes`),极端情况下诊断信息可能被截断。 - **发布只做 npm 和 tarball**。GitHub 直装、[dsh.pub](https://dsh.pub) 收录只在结果里给引导,不代你执行。 - **未在 TUI / headless profile 下验证**。无交互提供方时按 fail-closed 处理,但没有实跑证据。 - 需要 dsh **`>=0.2.1-rc.2 <0.3.0-0`**;真机验证版本为 `0.2.1-rc.2`。旧 `0.1.x` Harness 请保留旧插件版本。新版设置使用 Config `.volatile()`,每次操作读取当前值;凭据刷新订阅 `credentials/reference-updated`。 --- ## 常见问题
提示「本机已认证,无法使用临时预览」怎么办? 早期版本会这样。**现在不会了**:显式要求临时预览时,插件会用隔离 `HOME` 执行,读不到你本机凭据,因此**不需要 `wrangler logout`**。如果仍看到这个提示,说明装的是旧版本,升级即可。
临时预览的地址打不开(404)? 临时账号刚创建时边缘节点有传播延迟,等 10–20 秒重试即可。实测约 12 秒后返回 200。
我的项目里会被塞进奇怪的文件吗? 不会。临时 wrangler 配置、tarball、npm cache 都写在系统临时目录。早期版本曾把生成的配置写进项目根、结果被当成静态资源发到公网——这个问题已修复,并加了 `.assetsignore` 兜底。
发布到 npm 卡在 OTP? 本插件不能交互输入 OTP。直接发布需要有发布权限且开启 **Bypass two-factor authentication** 的 granular token,并须符合账号、组织和包的策略。建议设置较短有效期,发完撤销。策略禁止时,改用终端交互式发布或 npm 官方 staging 流程。
能部署 Next.js 吗? 静态导出可以。SSR 需要 [OpenNext 适配器](https://github.com/opennextjs/opennextjs-cloudflare),当前版本不处理——插件会如实告诉你,不会假装成功。
凭据存在哪?会被上传吗? 存在 dsh 凭据服务(`$DSH_HOME/.credentials.yaml`,`0600`)。除了传给 wrangler / npm 子进程执行部署外,不会发送到任何地方。插件本身不联网上报。
--- 新版迁移与本次验证记录见 [Harness 0.2 兼容报告](docs/HARNESS-0.2-COMPATIBILITY.md)。 ## 从源码开发 ```sh git clone https://github.com/Octo-o-o-o/dsh-plugin-deploy.git cd dsh-plugin-deploy npm install node build.mjs # 构建 lib/index.js 与 lib/client.js npm run typecheck npm test # 118 个测试,执行前自动构建 # 装本地版本调试(路径必须绝对) npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add "$PWD" ``` 结构: ``` src/ ├── index.ts # 插件入口:注册工具、命令、设置 ├── deploy.ts # 部署编排:检测 → 条款 → 审批 → 执行 ├── mode.ts # L1/L2 模式判定 ├── isolated-home.ts # 临时预览的隔离 HOME ├── publish.ts # 发布编排 ├── publish-checks.ts # 9 条发布校验 ├── redact.ts # 输出脱敏 └── client/ # Web UI:设置卡片 + 两个结果卡片 ``` 浏览器侧产物必须是 dsh 的 lazy-CJS factory bundle(`window.__ModuleLoader__.load({id, factory})`),`build.mjs` 里已经配好 banner + intro + footer 三段——**三段缺一不可**,漏了 intro 会在浏览器里抛 `module is not defined`。 --- ## 致谢与相关项目 - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — 一切皆插件的 agent 底座 - [Cloudflare Workers](https://developers.cloudflare.com/workers/) — 临时预览账号([官方设计说明](https://developers.cloudflare.com/workers/platform/claim-deployments/)) - [dsh-plugin-assistant](https://github.com/Octo-o-o-o/dsh-plugin-assistant) — 本插件开发时用的规则包:钉版本的事实层 + Edit 时门禁 - [dsh.pub](https://dsh.pub) — 社区插件目录 本项目与 DeepSeek 官方无隶属关系。 ## License [MIT](LICENSE)