DSH WebUI 插件的可视化优先开发环境。
32.2/100
综合分
3
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:engines.node 要求 ^22.22.3 || >=24.11.1,不满足 Node 22.19.0。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add memorax-ai/dsh-webui-studio该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
⚠︎ 实装验证未通过(unknown · 2026/10/30) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装engines.node 要求 ^22.22.3 || >=24.11.1,不满足 Node 22.19.0
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-webui-studio @ 0.3.5
✗Node 引擎要求 ^22.22.3 || >=24.11.1 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/18 00:25:56
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 105 处,展示前 62 条)
- 发起网络请求src/browser/connection.ts:5
export const studioFetch: typeof globalThis.fetch = (input, init) => globalThis.fetch(input, init) - 删除本地文件src/host/automatic-patch.ts:452
if (write.created) await unlink(join(root, write.file)) - 读取本地文件src/host/build.ts:51
const matches = candidates.filter(candidate => candidate.files.some(file => existsSync(join(root, file)))) - 读取本地文件src/host/build.ts:62
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { - 执行外部命令来自配置/变量src/host/drafts.ts:24
const child = spawn(command, args, { cwd, env, stdio: ['ignore', 'pipe', 'pipe'], signal }) - 读取本地文件src/host/drafts.ts:99
manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')) as PluginManifest - 读取本地文件src/host/drafts.ts:120
const info = await lstat(source) - 读取本地文件src/host/drafts.ts:124
const targetInfo = await lstat(target) - 写入本地文件src/host/drafts.ts:130
await mkdir(target, { mode: info.mode, recursive: true }) - 读取本地文件src/host/drafts.ts:132
const entries = await readdir(source, { withFileTypes: true }) - 读取本地文件src/host/drafts.ts:141
const targetInfo = await lstat(target) - 写入本地文件src/host/drafts.ts:148
await copyFile(source, target) - 写入本地文件src/host/drafts.ts:149
await chmod(target, info.mode) - 写入本地文件src/host/drafts.ts:168
await rename(target, backup) - 写入本地文件src/host/drafts.ts:172
await rename(join(backup, entry), join(staging, entry)) - 写入本地文件src/host/drafts.ts:176
await rename(staging, target) - 删除本地文件递归src/host/drafts.ts:178
if (movedTarget) await rm(backup, { recursive: true, force: true }) - 删除本地文件递归src/host/drafts.ts:188
await rm(staging, { recursive: true, force: true }) - 读取本地文件src/host/drafts.ts:195
return await lstat(path) - 删除本地文件递归src/host/drafts.ts:377
rm(worktreeDir, { recursive: true, force: true }), - 删除本地文件递归src/host/drafts.ts:378
rm(repositoryDir, { recursive: true, force: true }), - 删除本地文件递归src/host/drafts.ts:379
rm(dirname(runtimeHome), { recursive: true, force: true }), - 删除本地文件src/host/element-source.ts:296
if (update.original === undefined) await unlink(join(root, file)) - 读取本地文件src/host/preview-draft.ts:21
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { - 读取本地文件src/host/preview-draft.ts:32
const profile = JSON.parse(readFileSync(profileManifest, 'utf8')) as { dependencies?: Record<string, string> } - 执行外部命令来自配置/变量src/host/preview.ts:146
const child = spawn(process.execPath, hostArgs, { - 发起网络请求src/host/preview.ts:188
const login = await fetch(launchUrl, { redirect: 'manual', signal }) - 发起网络请求src/host/preview.ts:196
return fetch(input, { ...init, headers }) - 读取本地文件src/host/project-files.ts:26
return realpath(root) - 读取本地文件src/host/project-files.ts:31
const target = await realpath(resolve(base, relativePath(input))) - 读取本地文件src/host/project-files.ts:40
for (const entry of await readdir(directory, { withFileTypes: true })) { - 读取本地文件src/host/project-files.ts:48
const info = await lstat(absolute) - 读取本地文件src/host/project-files.ts:58
const info = await lstat(target) - 读取本地文件src/host/project-files.ts:61
const content = await readFile(target) - 写入本地文件src/host/project-files.ts:80
await writeFile(temporary, content, { encoding: 'utf8', flag: 'wx' }) - 写入本地文件src/host/project-files.ts:81
await rename(temporary, target) - 删除本地文件src/host/project-files.ts:83
await unlink(temporary).catch(() => undefined) - 读取本地文件src/host/readiness.ts:64
if (!existsSync(target)) return finding('error', 'artifact-missing', `${label} ${JSON.stringify(path)} does not exist; build the Draft before publishi - 读取本地文件src/host/readiness.ts:69
return JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as DraftManifest - 读取本地文件src/host/readiness.ts:130
if (!existsSync(target)) { - 读取本地文件src/host/readiness.ts:173
if (existsSync(orderPath)) { - 读取本地文件src/host/readiness.ts:174
const order = (JSON.parse(readFileSync(orderPath, 'utf8')) as { order?: unknown }).order - 读取本地文件src/host/runtime-profile.ts:52
const manifest = JSON.parse(await readFile(join(draft.root, 'package.json'), 'utf8')) as DraftManifest - 删除本地文件递归src/host/runtime-profile.ts:123
await rm(profileDir, { recursive: true, force: true }) - 写入本地文件src/host/runtime-profile.ts:124
await mkdir(profileDir, { recursive: true }) - 读取本地文件src/host/runtime-profile.ts:125
const manifest = JSON.parse(await readFile(join(sourceProfileDir, 'package.json'), 'utf8')) as ProfileManifest - 写入本地文件src/host/runtime-profile.ts:133
await writeFile(join(profileDir, 'package.json'), `${JSON.stringify({ ...manifest, dependencies }, null, 2)}\n`) - 读取本地文件src/host/source-resolution.ts:90
const root = await realpath(path) - 读取本地文件src/host/source-resolution.ts:91
const manifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')) as PackageManifest - 读取本地文件src/host/source-resolution.ts:102
const entries = (await readdir(nodeModules)).filter(name => !name.startsWith('.')) - 读取本地文件src/host/source-resolution.ts:104
? readdir(join(nodeModules, name)).then(packages => packages.filter(item => !item.startsWith('.')).map(item => `${name}/${item}`)) - 读取本地文件src/host/source-resolution.ts:112
const draft = await realpath(draftRoot) - 读取本地文件src/host/source-resolution.ts:113
const draftManifest = JSON.parse(await readFile(join(draft, 'package.json'), 'utf8')) as PackageManifest - 读取本地文件src/host/workspace.ts:41
stored = parseWorkspace(JSON.parse(await readFile(this.file, 'utf8')) as unknown) - 写入本地文件src/host/workspace.ts:61
await mkdir(dirname(this.file), { recursive: true }) - 写入本地文件src/host/workspace.ts:63
await writeFile(temporary, `${JSON.stringify(next, null, 2)}\n`, { flag: 'wx' }) - 写入本地文件src/host/workspace.ts:64
await rename(temporary, this.file) - 读取本地文件src/index.ts:33
script: readFileSync(new URL('../dist/studio.js', import.meta.url)), - 读取本地文件src/index.ts:34
style: readFileSync(new URL('../dist/studio.css', import.meta.url)), - 读取本地文件src/index.ts:35
bridge: readFileSync(new URL('../dist/bridge.js', import.meta.url)), - 读取本地文件src/index.ts:36
icon: readFileSync(new URL('../assets/harmony-icon.png', import.meta.url)), - 读取本地文件src/index.ts:37
iconMono: readFileSync(new URL('../assets/harmony-icon-mono.png', import.meta.url)),
扫描于 2026/11/2(1 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/cordis-plugin-group@deepseek-ai/cordis-plugin-loader@deepseek-ai/dsh@deepseek-ai/dsh-agent@deepseek-ai/dsh-anonymous-user-id@deepseek-ai/dsh-api-gateway@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-authorization@deepseek-ai/dsh-bash-local@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-modules给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 可视化优先开发环境
- 交互式客户端插件开发
README
由 DeepSeek 最新模型翻译生成DeepSeek WebUI Studio
DSH WebUI 插件的可视化优先开发环境。
实时预览你的插件对 dsh webui 的修改效果,在可视化的集成开发工具中交互式地与 agent 协作构建插件客户端。
Powered by dsh-harmony.
快速开始
报告问题
功能建议
Powered by Harmony
简体中文 / English
面向真实 DSH WebUI 的可视化工作区
WebUI Studio 不是模拟页面生成器。它运行在官方 DSH WebUI 和真实插件图谱之上,把可视化检查与源码修改转化为可分发、由插件自身拥有的产物。
Studio 是 dsh-harmony 的独立下游应用。它通过公共 package exports 使用 Harmony 的 runtime、Patch engine、 service API 与 CLI 控制面,并使用 dsh-harmony-react 提供的通用 React 注册 API。依赖始终保持单向:Studio 依赖 Harmony,Harmony 不依赖 Studio。
展开完整文档(README 剩余 1 节)
DeepSeek WebUI Studio
DSH WebUI 插件的可视化优先开发环境。
实时预览你的插件对 dsh webui 的修改效果,在可视化的集成开发工具中交互式地与 agent 协作构建插件客户端。
Powered by dsh-harmony.
快速开始
报告问题
功能建议
Powered by Harmony
简体中文 / English
面向真实 DSH WebUI 的可视化工作区
WebUI Studio 不是模拟页面生成器。它运行在官方 DSH WebUI 和真实插件图谱之上,把可视化检查与源码修改转化为可分发、由插件自身拥有的产物。
Studio 是 dsh-harmony 的独立下游应用。它通过公共 package exports 使用 Harmony 的 runtime、Patch engine、 service API 与 CLI 控制面,并使用 dsh-harmony-react 提供的通用 React 注册 API。依赖始终保持单向:Studio 依赖 Harmony,Harmony 不依赖 Studio。
你可以做什么
- [x] 创建最小 DSH Web Client 插件,或导入已有的本地插件文件夹
- [x] 为每个 Draft 分配独立 Git worktree、DSH_HOME、profile、依赖树和 child Host
- [x] 预览官方 WebUI,同时不把 Draft 代码加载进稳定 Host
- [x] 正常浏览,或检查 DOM、React owner、源码候选和 Patch trace
- [x] 自动展示插件注册的 Element 控件,并将默认值与限定在当前子树内的 CSS 保存回草稿源码
- [x] 检查 Component 声明命中后生成 CSS decorator,不修改既有调用点 Props
- [x] 通过一次事务热重载调整 Harmony Provider 与单个 Patch 的顺序和启停状态
- [x] 使用 CodeMirror 编辑 Draft 源码,并保持已安装依赖源码只读
- [x] 构建、经 Harmony 应用、重载,并确认实时 Client graph revision
- [x] 新建 Draft 级 Agent,或让已有 DSH 会话临时挂载 Studio tools、Skill 与上下文后继续工作
- [x] 让外部 Agent 通过本机只读 Streamable HTTP MCP 入口检查正在运行的 WebUI
- [x] 无需离开 Studio 即可处理单次工具授权、结构化问题和计划审核
- [x] 检查 package exports、构建产物、Patch 状态、顺序、依赖和 pack 输出
- [x] 同时运行多个相互隔离的 Draft Preview Host
- [x] 将当前 WebUI profile 或其它本地 profile 复制到每个 Draft 的隔离运行环境
- [x] 通过一次事务热重载调整插件顺序并启停 Harmony Provider
工作原理
flowchart LR
A["稳定 DSH Host"] --> B["WebUI Studio"]
B --> C["Draft worktree"]
B --> D["Draft worktree"]
C --> E["独立 DSH Home + Preview Host"]
D --> F["独立 DSH Home + Preview Host"]
E --> G["Harmony runtime + 真实 WebUI"]
F --> G
稳定 Host 负责 Studio 界面、Draft registry 和 Agent session。每个 Draft 拥有隔离的 worktree 与 child Preview Host。只有在 Preview 确认新的实时 Client graph revision 后,构建结果才会激活。停止 Draft 只终止 child Host,不会删除文件和状态。
已有普通 DSH 会话可以在不丢失历史或会话身份的情况下进入 Studio 模式。退出 Studio 会移除 Draft 专属的工具、Skill 与上下文,让会话恢复为普通 DSH 组合。
Studio 的本地地址为:
http://127.0.0.1:<dsh-port>/studio
外部 Agent 可以通过以下 MCP 地址连接正在运行的实例:
http://127.0.0.1:<dsh-port>/studio/mcp
常见 MCP 客户端可使用如下配置:
{
"mcpServers": {
"dsh-webui-studio": {
"type": "http",
"url": "http://127.0.0.1:<dsh-port>/studio/mcp"
}
}
}
在外部 Agent 中将该地址添加为 Streamable HTTP MCP server,即可调用 studio_get_context、studio_get_selection、studio_get_harmony_profile、 studio_inspect_harmony_target、studio_read_dependency_source 和 studio_preview_status。这些工具只检查当前 Host;外部 Agent 继续负责修改和构建自己的 WebUI 项目。Harmony profile、Patch 与依赖源码检查由 Host 直接提供。DOM 选择信息需要打开 Studio,并在“当前实例”Preview 中选中元素。MCP 入口沿用 Studio 仅限 loopback 访问的边界,也可以通过 SSH loopback tunnel 使用。
托管数据位于 $DSH_HOME/studio/:
studio/
├── workspace.json
├── drafts/<draft-id>.json
├── repositories/<draft-id>/
├── worktrees/<draft-id>/
└── runtimes/<draft-id>/dsh-home/profiles/web/
创建新插件时,Studio 会初始化并提交一个最小 DSH Web Client package,并默认只将它保存在 Studio 内。创建时也可以记录一个新建或空白本地文件夹的绝对路径;在实例面板显式点击“保存插件到文件夹”前,Studio 不会创建或修改该目录。后续保存会同步 Studio 中的项目快照,同时保留目标目录独有的 node_modules 等文件。导入已有插件时, Studio 只接受本机绝对文件夹路径;验证 Web Client manifest 后,它会跳过 .git 与 node_modules,将快照复制到 Studio 自有 Git repository。符号链接会被拒绝,原插件文件夹始终保持只读且不会被修改。
每个 Draft 可以使用稳定 Host 当前的 web profile,也可以通过绝对文件夹路径选择另一个本地 DSH profile。Studio 会将其清单与配置复制到 Draft 的隔离运行环境,并以所选源文件夹为基准解析相对 link: 依赖;源 profile 始终不会被修改。
Draft 显示名与 npm package identity 相互独立,可在实例面板中重命名。Studio 会在 workspace.json 中保存标签顺序与当前 Draft;关闭标签只会将其移出当前工作区,不会停止或删除 Draft。Source 存在未保存修改时,必须先按 Ctrl+S 或 Command+S 保存,才能切换或关闭标签。
快速开始
[!IMPORTANT]
Studio 依赖 docs/harmony-api-requirements.md 中列出的 Harmony 公共 service 与 CLI API,最低兼容版本为 dsh-harmony@0.8.7。
dsh plugin --profile web add dsh-webui-studio
dsh web
Studio 会把 Harmony 作为传递依赖一并安装。第一次访问 /studio 时,点击 安装 Harmony 并重启;页面会安装 launcher,并在本地 DSH 进程重启后自动返回 Studio,无需再执行第二条 package 安装命令。已经安装 Harmony launcher 时会跳过此步骤。
如需开发 Studio 本身:
git clone https://github.com/memorax-ai/dsh-webui-studio.git
cd dsh-webui-studio
npm install
npm run check
dsh plugin --profile web add link:$(pwd)
dsh web
如需用发布产物验证相同的单包安装流程:
studio_tarball="$(npm pack --silent --ignore-scripts)"
dsh plugin --profile web add "file:$(pwd)/${studio_tarball}"
打开本地 dsh web 进程输出的 Studio 地址,创建或导入 Draft,然后启动它的 Preview Host。
Draft package 必须:
- 声明 dsh.client.platform: "web";
- 导出 ., ./client 和 ./package.json;
- 定义非空的 scripts.build 命令。
开发命令
| 命令 | 用途 |
| npm run typecheck | 检查 Host、浏览器应用和 Preview bridge |
| npm test | 运行单元测试与组件测试 |
| npm run build | 构建 Host、Studio UI 和 Preview bridge |
| npm run check | 运行 typecheck、测试、构建和 tarball 全新安装集成验证 |
| npm run test:integration | 将 tarball 安装到全新的 DSH home,再端到端验证 Host、Draft、Preview、构建、激活与停止 |
如需在远程 Docker 主机上运行相互隔离的 Agent 开发环境,请参阅 docs/remote-development.md。
集成测试需要 Harmony build 已公开兼容性说明中列出的 API。
设计边界
- 官方 WebUI 保持自己的同源 /api 与 WebSocket;Studio 不代理它们。
- Preview bridge 要求精确的 parent origin 和每次启动生成的 capability。
- 来自 Preview 的 DOM、React、源码、Patch 与注释数据均被视为不可信证据。
- 源码写入始终限制在所选 Draft package 内,且不会沿符号链接写到外部。
- 已注册 element boundary 与 Patch trace 只是候选证据,不代表对 DOM 的精确所有权声明。
- Element 控件通过插件 binding 修改实时 Preview。“保存到插件源码”会在 Draft 工作树中更新插件声明的默认初始化值与限定子树 CSS,不会改写组件使用位置,也不会固定运行时 binding。
- 自动 CSS Patch 使用 Harmony React 的 Component decorator。Studio 会先展示所有声明命中,再写入可立即加载的 Draft client export;现有 JSX 调用与 Props 保持不变。
常见问题
Studio 与其他 WYSIWYG 工具有何不同?
DSH WebUI 的修改不能直接改动上游源码,而要以插件形式交付。界面元素还会参与 Cordis 的插件生命周期与控制逻辑,因此问题不只是操作静态 DOM 和 CSS。预览、修改、验证与分发都需要理解 DSH 插件体系,这足以构成一套独立的专用工具。
为什么不直接让 Agent 对着源码修改?
Studio 仍然连接 DSH 内部真实的 Agent,同时为它提供更完整的项目上下文、集成预览、专用 Agent 工具与 Skill,以及更紧密的编辑、构建、检查和验证闭环。Studio 不是取代 Agent,而是为 Agent 和开发者提供更好的交互式修改体验。
Harmony 是什么,为什么选择 Harmony?
DSH WebUI 已经提供了许多 Slot 点位,但 Studio 不满足于此。我们希望实现更深层、更高自由度的修改,包括修改其他插件加入的 UI 和逻辑,同时让不同修改插件之间尽可能兼容。dsh-harmony 提供的运行时 Patch 与运行时模型,让这种能力成为可能。
相关项目
- dsh-harmony - runtime patch、事务式插件重载与 Patch 检查
- dsh-harmony-react - React-aware Patch 工厂与 Studio element/variable 注册
许可证
本项目采用 MIT License。
兼容适配分支
开发依赖统一使用 DSH 0.1.5-rc.3,并提交匹配的 npm 锁文件。Dependabot 将 DSH 开发包成组更新,使它们的 peer 依赖要求保持一致。CI 继续保留隔离的 0.1.5-rc.2 兼容基线,并明确检查 0.1.5-rc.3。
开发基线将 Cordis 固定为 4.0.2、loader 固定为 1.0.3、group 固定为 1.0.2,以匹配 DSH 的 peer 依赖要求。Dependabot 跳过这三个包的更高版本:DSH 要求这组 Cordis/group,而更高版本的 loader 要求更新的 Cordis。更新整组 DSH 开发依赖时,需重新评估这些固定版本和排除规则。Cordis 4.0.4 和 loader 1.0.5 即使一起升级,也无法通过 npm peer 依赖解析。
本分支面向 DSH 0.1.5-rc.2 至 0.1.7-rc.2,以及 0.2.0-rc.1 预发布版,使用原生 Session Controller 和 Binding Gateway 事件。隔离环境的 0.1.7-rc.2 与 0.2.0-rc.1 检查覆盖 Studio HTTP 服务、RPC、会话快照、控制、事件记录、历史、模型接口和完整的草稿预览流程;浏览器交互仍需单独验证。
适配覆盖会话日志、助手增量输出、断线恢复和审批/提问回传。Preview 保留带认证参数的启动链接,并为后台连接换取 cookie。全新安装还需要 Harmony 的安装引导启动修复;Windows 上的 rc 完整打包/Preview 测试也已通过;浏览器交互及跨平台验证仍需独立检查。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
memorax-ai/dsh-webui-studio
DSH WebUI 插件的可视化优先开发环境。
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,025未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,358已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13938 个插件含 PR 收录与…
★ 350已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7