READMESource: main@3409173a
dsh-develop-ui
DSH(DeepSeek Harness)终端插件:底部多标签内嵌终端(@xterm/xterm + node-pty 真 shell),
不接管官方布局,侧栏 / 对话 / 右侧栏全部保持官方行为。
0.2.0 起为终端版:文件树、编辑器/预览、
@文件引用、聊天增强、命令白名单、五列布局接管 已全部移除。插件只做一件事——给你一个能用的终端。
功能
| 功能 | 说明 |
|---|---|
| 底部终端面板 | 挂官方 root 槽 shell.bottom(全宽自动行),打开时从底部升起;关闭时高度 0,PTY 会话与输出通道保留 |
| 多标签 | 一个 shell 一个 tab;✕ 关闭后激活右邻居;右键/⋯ 菜单「关闭当前 / 关闭全部 / 关闭左侧全部 / 关闭右侧全部」;最后 tab 关闭时面板自动收起 |
| 多 shell | PowerShell / PowerShell 7 / cmd / Git Bash(host 端白名单硬编码,client 只传 id);弹层显示 ✓ 上次选择与「未安装」;shell 序号按类型递增 |
| 工作区隔离 | 终端会话按当前工作区(cwd)分组:切会话只换投影,其他工作区的 PTY 与输出通道保留;所有工作区的终端视图常驻挂载(切走只是隐藏,xterm 不销毁),切回来历史与滚动位置都在;cwd 键按 Windows 语义归一(大小写 / 分隔符 / 尾斜杠不影响归属);无工作区时面板提示且不创建 |
| 高度拖拽 | 顶部手柄拖拽调高(120–480px),localStorage 记忆 |
| 复制 / 粘贴 | 终端内右键菜单(复制依赖 xterm 选区;粘贴读剪贴板写入 PTY) |
| 链接点击 | http(s):// 与裸 www. 链接悬停显示下划线与指针,单击用系统默认浏览器打开(OSC 8 超链接同样生效);只放行 http/https |
| 打开入口 | 侧栏底部「终端」开关(官方 sidebar.footer.action 列表槽位,加法) |
| 输出通道 | host 有界缓冲(512KB,超限丢弃最旧并提示)+ 单条多路复用长轮询 read-all:所有会话共用一条 15s 长轮询,常驻连接与会话数无关(每会话一条会占满浏览器同源 6 连接,导致输入 POST 排队、打字不回显) |
| 输入通道 | 每个会话一条串行输入队列:同一时刻只有一个 /input 在途,期间按键合并成批,保证按键顺序、不制造请求风暴 |
形态
DSH profile bundle 插件(Cordis 双半):
- host 半(
src/host/→lib/index.js):node-pty会话服务 +ctx.webServerHTTP 路由/api/dsh-develop-ui/terminal/*(含本机端口校验);cwd 经ctx.fs校验后processPath交给 PTY。 - client 半(
src/client/→lib/client.js):__ModuleLoader__lazy-CJS 格式 React UI; 只注册两个槽位——sidebar.footer.action(终端开关)与shell.bottom(终端面板); 会话/工作区数据走 slot 框架注入的标准钩子(useSessions/useWorkspaces), 外部模块面仅react/react/jsx-runtime。 - 不再禁用官方
ui-layout:cordis.patch.yml只 insert 自己(inject: ['webServer', 'fs'])。
运行时要求:DSH Desktop ≥ 2.0.18(dsh ≥ 0.2.1-rc.2)。插件用
engines.dsh声明这一点, 低于该版本的 DSH 会在启动时明确提示不兼容并跳过本插件(而不是带着坏 UI 启动)。
安装(手动本地安装,DSH Desktop)
流程与旧版一致;装完必须完全退出并重启 DSH Desktop,bundle 才会加载。
方式一:一键脚本(推荐)
cd E:\trae-file\deepseek-harness-client
node scripts/install-plugin.mjs --from local --force # 重建 + 打包 + 覆盖安装 + 校验
脚本依次完成:构建 → pnpm pack → pnpm add 到 profile → 注册 dsh.profile.bundles
(自动备份 package.json.bak)→ 校验产物(host/client/patch/node-pty)→ 打印重启与验证指引。
| 常用参数 | 作用 |
|---|---|
--from local |
强制重新 node build.mjs && tsc --emitDeclarationOnly + pnpm pack 后装本地 tarball |
--from npm |
装 npm 上的已发布版本(不构建) |
--version 0.2.0 |
指定 npm 版本(隐含 --from npm) |
--force |
先 pnpm remove 再装(同一版本号重装必须加) |
--dry-run |
只打印将执行的动作,不落盘 |
--uninstall |
卸载:移除插件包 + dependencies + bundles 注册 |
--profile "D:\path\profiles\desktop" |
指定其他 profile 目录 |
--registry https://registry.npmjs.org |
指定 registry(默认沿用环境 .npmrc) |
方式二:手动步骤(与脚本等价)
# ① 构建(esbuild 双入口 + 类型声明)
cd E:\trae-file\deepseek-harness-client
node build.mjs && tsc --emitDeclarationOnly
# ② 打包
pnpm pack # → dsh-develop-ui-0.2.0.tgz
# ③ 安装到 profile
cd C:\Users\User\.dsh\profiles\desktop
pnpm add "E:\trae-file\deepseek-harness-client\dsh-develop-ui-0.2.0.tgz"
# ④ 注册 bundle:编辑 package.json,把 "dsh-develop-ui" 追加进 dsh.profile.bundles
# 期望:["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-develop-ui", ...]
# ⑤ 完全退出并重启 DSH Desktop
环境备注(Windows + DSH Desktop):PATH 中
pnpm是 DSH 内置包装器,pnpm run嵌套 spawn 会被拦截——构建用node build.mjs直跑;esbuild 在文件沙箱内 spawn 被拦截, 构建需在真实终端 / 完整权限下执行(详见docs/开发记录/初始化记录.md)。
重启后验证
# a) host 半:当日日志应出现终端路由挂载,且无 bundle 加载失败
Get-Content "$env:APPDATA\DSH Desktop\logs\dsh-$(Get-Date -Format 'yyyy-MM-dd').log" -Tail 50
# 期望:[dsh-develop-ui] host half loaded (terminal)
# [dsh-develop-ui] terminal routes mounted at /api/dsh-develop-ui/terminal/*
# b) client bundle 可达(端口取 DSH Web GUI 实际监听端口)
Invoke-WebRequest -Uri "http://127.0.0.1:<端口>/plugins/dsh-develop-ui/client.js" -UseBasicParsing | Select-Object StatusCode
# 期望:200,响应体含 window.__ModuleLoader__.load({ id: "dsh-develop-ui"
# c) GUI:侧栏底部出现「终端」按钮;点开底部面板 → + 新建终端;控制台有
# [dsh-develop-ui] client half loaded (terminal)
常见问题
| 现象 | 原因与处理 |
|---|---|
日志出现 Plugin dsh-develop-ui@... is incompatible with dsh ... |
DSH 版本低于 engines.dsh(需要 dsh ≥ 0.2.1-rc.2 / DSH Desktop ≥ 2.0.18):升级 DSH Desktop |
| 侧栏底部没有「终端」按钮 | bundle 未加载:必须完全退出并重启 DSH Desktop,不是刷新页面 |
| 底部有面板但无法新建终端 | 当前会话没有工作区 cwd:先打开/新建工作区,或检查 dsh.profile.bundles 注册 |
pnpm add 后终端不可用 |
node-pty 原生模块没编译(ERR_PNPM_IGNORED_BUILDS):在 profile 执行 pnpm approve-builds 勾选 node-pty,或 profile 的 pnpm-workspace.yaml 加 onlyBuiltDependencies: [node-pty],再重跑安装脚本 |
客户端控制台报 client bundle not found |
lib/client.js 缺失:重跑 node build.mjs 后重新 pnpm pack |
| 端口 404 | GUI 端口动态分配:netstat -ano | Select-String LISTENING 取实际端口 |
| 构建/测试命令被沙箱拦截 | esbuild spawn 在文件沙箱内被拦截:需完整权限或真实终端执行 |
开发命令
pnpm install # 安装依赖
pnpm build # esbuild 双入口 + tsc 类型声明(node build.mjs && tsc --emitDeclarationOnly)
pnpm typecheck # 类型检查(tsc --noEmit)
# 测试(terminal / bundle 格式两项需先 node build.mjs 产出 lib/*.js;links / term-store 直跑 src/*.ts)
node tests/unit/terminal.test.mjs # PTY 服务(create/input/readMany 多路复用/abort/kill/缓冲上限)
node tests/unit/terminal-links.test.mjs # 链接识别(尾标点/括号/协议收敛/宽字符 range)
node tests/integration/term-store-tabs.test.mjs # 终端 tab / 工作区隔离 / 单通道并发 ≤1 / 输入保序 / 高度记忆
node tests/integration/client-bundle-format.test.mjs # bundle 格式 + 槽位接线 + SSR 冒烟 + 模块白名单
node tests/repro/double-load.test.mjs # host 半 boot 回归
# 安装/卸载插件到 DSH Desktop profile
node scripts/install-plugin.mjs --from local --force # 重建打包并覆盖安装
node scripts/install-plugin.mjs --dry-run # 预览将执行的动作
node scripts/install-plugin.mjs --uninstall # 卸载
目录结构
src/
host/
index.ts # 终端 HTTP 路由(只此 6 条)
terminal.ts # TerminalService:node-pty 会话 + 有界缓冲 + 长轮询
http-util.ts # sendJson / readJson / 本机端口校验
shared/
rpc.ts # 终端契约类型
client/
index.ts # 注册 sidebar.footer.action + shell.bottom
terminal/
TermDock.tsx # shell.bottom occupant:cwd 解析 + 面板
TermButton.tsx # sidebar.footer.action occupant:开关
TermPanel.tsx # xterm 画布 / tab 条 / shell 弹层 / 右键菜单
termStore.ts # 多工作区终端状态 + 长轮询 + 关闭策略
useTermCwd.ts # 当前工作区 cwd(标准钩子)
termCss.ts # 面板样式注入
从 0.1.x 升级
0.2.0 是终端版,行为和产物都变了:
- 不再禁用官方
ui-layout,不再提供ctx.layout/ 主题呈现 / 五列框架; - 文件树、编辑器/预览、
@文件、历史回显、提问浮层、命令白名单、系统打开全部移除; - client bundle 从 ~3.2MB 降到 ~360KB,依赖只剩
@xterm/xterm、@xterm/addon-fit、node-pty; - 升级方式:
node scripts/install-plugin.mjs --from local --force后完全重启。
No comments yet. Be the first to write one.