dsh-single-terminal 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +144 -0
  2. package/README.zh.md +129 -0
  3. package/cordis.patch.yml +11 -0
  4. package/lib/client.js +11438 -0
  5. package/lib/client.js.map +1 -0
  6. package/lib/index.js +588 -0
  7. package/lib/types/client/controller.d.ts +86 -0
  8. package/lib/types/client/controller.d.ts.map +1 -0
  9. package/lib/types/client/controller.js +235 -0
  10. package/lib/types/client/drawer.d.ts +10 -0
  11. package/lib/types/client/drawer.d.ts.map +1 -0
  12. package/lib/types/client/drawer.js +84 -0
  13. package/lib/types/client/i18n.d.ts +8 -0
  14. package/lib/types/client/i18n.d.ts.map +1 -0
  15. package/lib/types/client/i18n.js +51 -0
  16. package/lib/types/client/index.d.ts +13 -0
  17. package/lib/types/client/index.d.ts.map +1 -0
  18. package/lib/types/client/index.js +13 -0
  19. package/lib/types/client/plugin.d.ts +23 -0
  20. package/lib/types/client/plugin.d.ts.map +1 -0
  21. package/lib/types/client/plugin.js +60 -0
  22. package/lib/types/client/protocol.d.ts +81 -0
  23. package/lib/types/client/protocol.d.ts.map +1 -0
  24. package/lib/types/client/protocol.js +5 -0
  25. package/lib/types/client/storage.d.ts +6 -0
  26. package/lib/types/client/storage.d.ts.map +1 -0
  27. package/lib/types/client/storage.js +21 -0
  28. package/lib/types/client/styles.d.ts +5 -0
  29. package/lib/types/client/styles.d.ts.map +1 -0
  30. package/lib/types/client/styles.js +103 -0
  31. package/lib/types/client/term.d.ts +15 -0
  32. package/lib/types/client/term.d.ts.map +1 -0
  33. package/lib/types/client/term.js +86 -0
  34. package/lib/types/client/toggle.d.ts +9 -0
  35. package/lib/types/client/toggle.d.ts.map +1 -0
  36. package/lib/types/client/toggle.js +19 -0
  37. package/lib/types/client/ws.d.ts +25 -0
  38. package/lib/types/client/ws.d.ts.map +1 -0
  39. package/lib/types/client/ws.js +79 -0
  40. package/lib/types/client/xterm-css.d.ts +7 -0
  41. package/lib/types/client/xterm-css.d.ts.map +1 -0
  42. package/lib/types/client/xterm-css.js +224 -0
  43. package/lib/types/host/hub.d.ts +39 -0
  44. package/lib/types/host/hub.d.ts.map +1 -0
  45. package/lib/types/host/hub.js +291 -0
  46. package/lib/types/host/index.d.ts +17 -0
  47. package/lib/types/host/index.d.ts.map +1 -0
  48. package/lib/types/host/index.js +66 -0
  49. package/lib/types/host/shells.d.ts +30 -0
  50. package/lib/types/host/shells.d.ts.map +1 -0
  51. package/lib/types/host/shells.js +202 -0
  52. package/lib/types/host/types.d.ts +109 -0
  53. package/lib/types/host/types.d.ts.map +1 -0
  54. package/lib/types/host/types.js +4 -0
  55. package/package.json +102 -0
  56. package/src/client/controller.ts +293 -0
  57. package/src/client/drawer.tsx +182 -0
  58. package/src/client/i18n.ts +58 -0
  59. package/src/client/index.ts +17 -0
  60. package/src/client/plugin.tsx +92 -0
  61. package/src/client/protocol.ts +40 -0
  62. package/src/client/storage.ts +21 -0
  63. package/src/client/styles.ts +106 -0
  64. package/src/client/term.tsx +95 -0
  65. package/src/client/toggle.tsx +43 -0
  66. package/src/client/ws.ts +81 -0
  67. package/src/client/xterm-css.ts +224 -0
  68. package/src/host/cordis-augment.d.ts +22 -0
  69. package/src/host/hub.ts +302 -0
  70. package/src/host/index.ts +78 -0
  71. package/src/host/shells.ts +216 -0
  72. package/src/host/types.ts +79 -0
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # dsh-single-terminal
2
+
3
+ **dsh-single-terminal** is a real-terminal drawer plugin for the DeepSeek
4
+ Harness (DSH) host. It docks an interactive PTY terminal (xterm.js) to the
5
+ bottom of the web app — type into it, Ctrl-C it, resize it, open as many tabs
6
+ as you need.
7
+
8
+ - **Real PTY, not an emulator** — each tab is a true pseudo-terminal
9
+ (ConPTY on Windows, forkpty on POSIX) driven by `node-pty`; interactive REPLs,
10
+ full-screen programs and Ctrl-C all behave like a native terminal
11
+ - **Shell picker** — Windows: PowerShell (default) / pwsh 7 / CMD / Git Bash /
12
+ WSL (shells that are not installed are hidden automatically) + custom shells
13
+ from config; POSIX: `$SHELL` / bash / zsh / fish
14
+ - **Two drawer modes** — *Docked* pushes the page content up (no occlusion),
15
+ *Overlay* floats above it; drag the top edge to resize, the drawer remembers
16
+ mode and height
17
+ - **Keep-alive sessions** — terminals survive page refreshes and drawer
18
+ close/reopen; on reconnect the recent output is replayed from a ring buffer.
19
+ Opening the drawer with no terminal yet auto-creates one with the default
20
+ shell.
21
+ - **Bilingual UI** — follows the host interface language (中文 / English);
22
+ `Alt+C` toggles the drawer
23
+
24
+ [中文文档](README.zh.md)
25
+
26
+ ## Features
27
+
28
+ - **Header entry** (`conversation.session.header.utilities`): a panel-bottom
29
+ icon button in the session header's utilities row toggles
30
+ the drawer. Hovering shows a bubble tooltip (the host `Tooltip` component)
31
+ with the shortcut; `Alt+C` toggles from anywhere except while typing inside
32
+ the terminal (there `Alt+C` is passed to the shell as `ESC c`).
33
+ - **Drawer** (`shell.overlay`): a frame-level bottom drawer with
34
+ - a tab strip — one PTY session per tab, independent shells, close button
35
+ per tab (terminates the whole process tree; the pid is verified gone),
36
+ - a `+` button (new tab with the default shell) and a `▸` menu
37
+ (all shells found on this machine; unavailable ones are not listed),
38
+ - a mode switch (*Docked* / *Overlay*), a connection status dot and a
39
+ collapse button,
40
+ - a drag handle on the top edge (pointer-capture drag, min 140px).
41
+ - **Docked mode** pushes the app frame up with `padding-bottom` on the frame
42
+ root element (no host hook exists for bottom docks); when the anchor cannot
43
+ be found it silently falls back to overlay.
44
+ - **Model tools**: none — this plugin is UI-only by design.
45
+
46
+ ## Configuration
47
+
48
+ Schemastery `Config` (renders on the host Plugins settings page), and / or the
49
+ profile `cordis.patch.yml`:
50
+
51
+ ```yaml
52
+ - insert:
53
+ - id: dsh-single-terminal
54
+ name: dsh-single-terminal
55
+ config:
56
+ defaultShell: powershell # powershell | pwsh | cmd | gitbash | wsl | <custom id>
57
+ defaultCwd: home # home | workspace | absolute path
58
+ scrollbackLimit: 200000 # replay ring buffer, bytes per session
59
+ fontSize: 13
60
+ fontFamily: Consolas, "Cascadia Mono", "Courier New", monospace
61
+ customShells:
62
+ - id: nu
63
+ name: Nushell
64
+ command: nu # resolved through PATH
65
+ args: []
66
+ ```
67
+
68
+ - `defaultShell` — shell used by the `+` button; when unavailable it falls
69
+ back (`powershell` on Windows, `$SHELL`/`bash` on POSIX).
70
+ - `defaultCwd` — `home` (default) starts in the user home; `workspace` is
71
+ reserved (currently resolves to home); an absolute path must exist.
72
+ - `customShells` — extra launchers; `command` may be an absolute path or a
73
+ name resolved through `PATH` (with `PATHEXT` on Windows).
74
+
75
+ ## Installation
76
+
77
+ ```sh
78
+ # Local development
79
+ dsh plugin --profile web add ./dsh-single-terminal
80
+
81
+ # Published: npm / tarball / GitHub
82
+ dsh plugin --profile web add dsh-single-terminal
83
+ dsh plugin --profile web add ./dsh-single-terminal-0.1.0.tgz
84
+ dsh plugin --profile web add github:you/dsh-single-terminal#<sha>
85
+
86
+ dsh --profile web # start (restart required for the host half to load)
87
+ ```
88
+
89
+ > **node-pty** is a native dependency of the *host half* (`dependencies`, kept
90
+ > external and loaded via `createRequire`). It ships prebuilds for common
91
+ > platforms; on unusual platforms a C/C++ toolchain is needed for
92
+ > `pnpm install` to compile it. The browser half inlines xterm.js entirely —
93
+ > no runtime dependency there.
94
+
95
+ ## Development
96
+
97
+ Requirements: **Node ≥ 22.19 (or ≥ 24) + pnpm 10** (the `packageManager` field
98
+ pins the pnpm version).
99
+
100
+ ```sh
101
+ pnpm install # includes node-pty + ws (runtime) and @xterm/* (bundled into the client)
102
+ pnpm run check # whole-tree TypeScript type check (tsc -b)
103
+ pnpm run build # clean lib → tsc -b (declarations) → tsdown (both halves)
104
+ pnpm run watch # tsdown watch mode
105
+ pnpm run verify # simulate the host seed table to check lib/client.js loads
106
+ ```
107
+
108
+ ```
109
+ ├── src/host/ # Host half: index.ts (entry, ws route + config), hub.ts (session hub + frame protocol), shells.ts (registry + probing), types.ts
110
+ ├── src/client/ # Browser half: plugin.tsx (slots), drawer.tsx, term.tsx, controller.ts, ws.ts, styles.ts, i18n.ts ...
111
+ ├── lib/index.js # Host half build artifact (tsdown, ESM)
112
+ ├── lib/client.js # Browser half build artifact (tsdown → __ModuleLoader__ factory, xterm inlined)
113
+ ├── scripts/verify-client.mjs # host-seed simulation check
114
+ ├── scripts/gen-xterm-css.mjs # regenerates src/client/xterm-css.ts from the @xterm/xterm package
115
+ ├── cordis.patch.yml # Bundle patch: plugin row referenced by package name (no paths)
116
+ └── package.json # dsh.bundle + dsh.client(web) manifests + peerDependencies
117
+ ```
118
+
119
+ ## Implementation notes
120
+
121
+ - **Why the plugin ships its own node-pty**: the host `subprocess` terminal
122
+ primitive (`SubprocessTerminalHandle`) intentionally exposes no `resize`,
123
+ which a resize-following terminal needs; a plugin-owned `node-pty` gets the
124
+ full `write / resize / kill` control surface with the same ConPTY/forkpty
125
+ substrate the host uses.
126
+ - **Transport**: a dedicated WebSocket route (`/api/dsh-single-terminal.ws`)
127
+ registered through `ctx.webServer.registerUpgrade`, gated by
128
+ `ctx.connection.requestRejection` (same trusted-host fence as the host API
129
+ gateway). The client connects same-origin and rides the `dsh-auth` cookie.
130
+ - **Session model**: sessions live in a hub `Map` independent of sockets —
131
+ page refresh / reconnect re-`list`s, adopts live sessions and `attach`es
132
+ with a `replay` of the ring buffer. Exited sessions are pruned so dead tabs
133
+ never resurrect. Multiple browser tabs may attach to one session (output is
134
+ broadcast, input is merged).
135
+ - **Frame protocol**: JSON text frames; client → host `open / input / resize /
136
+ close / list / attach / ping`, host → client `hello / shells / opened / data
137
+ / replay / exit / error / pong`. `input`/`resize` are size-capped and
138
+ clamped server-side.
139
+ - **Windows process tree**: closing a tab runs `pty.kill()` and additionally
140
+ `taskkill /T /F` on the session pid — ConPTY closure alone can leave
141
+ PowerShell (+PSReadLine) alive; POSIX kills the foreground process group
142
+ (`kill(-pid)`).
143
+ - **The official `deepseek-harness` project is not modified**; all UI sits in
144
+ existing slots (`shell.overlay`, `conversation.session.header.utilities`).
package/README.zh.md ADDED
@@ -0,0 +1,129 @@
1
+ # dsh-single-terminal
2
+
3
+ **dsh-single-terminal** 是 DeepSeek Harness(DSH)宿主的真实终端抽屉插件。它在
4
+ Web 应用底部挂一条交互式 PTY 终端(xterm.js)——可以正常敲命令、Ctrl-C、拖拽
5
+ 改大小、开任意多个标签。
6
+
7
+ - **真 PTY,非模拟** —— 每个标签是一条真实伪终端(Windows 为 ConPTY,POSIX 为
8
+ forkpty),由 `node-pty` 驱动;交互式 REPL、全屏程序、Ctrl-C 与原生终端一致
9
+ - **Shell 选择** —— Windows:PowerShell(默认)/ pwsh 7 / CMD / Git Bash / WSL
10
+ (未安装的自动隐藏)+ config 自定义 shell;POSIX:`$SHELL` / bash / zsh / fish
11
+ - **两种抽屉模式** —— *占高度* 把页面内容顶起(无遮挡),*浮层* 悬浮于内容之上;
12
+ 顶边可拖拽调高度,模式与高度自动记忆
13
+ - **会话保活** —— 终端在页面刷新、抽屉开合后继续存活;重连后从环形缓冲回放
14
+ 近期输出。打开抽屉时若还没有任何终端,会自动用默认 shell 新建一个。
15
+ - **双语 UI** —— 跟随宿主界面语言(中文 / English);`Alt+C` 开关抽屉
16
+
17
+ [English](README.md)
18
+
19
+ ## 功能
20
+
21
+ - **会话头部入口**(`conversation.session.header.utilities`):会话头部
22
+ utilities 区的「底部面板」(panel-bottom) 图标按钮,点击开合抽屉;悬停显示
23
+ 宿主 `Tooltip`
24
+ 气泡(含快捷键提示)。`Alt+C` 全局开合抽屉;焦点在终端输入区内时放行
25
+ (`Alt+C` 作为 `ESC c` 发给 shell)。
26
+ - **抽屉**(`shell.overlay`):frame 级底部抽屉,包含
27
+ - 标签条 —— 每标签一条独立 PTY 会话,可独立选择 shell;每标签有关闭按钮
28
+ (终止整棵进程树,已实测 pid 消失);
29
+ - `+` 按钮(默认 shell 新建标签)与 `▸` 菜单(列出本机探测到的全部 shell,
30
+ 不可用的不显示);
31
+ - 模式切换(占高度 / 浮层)、连接状态点、收起按钮;
32
+ - 顶边拖拽条(pointer capture 拖拽,最小 140px)。
33
+ - **占高度模式** 通过对框架根元素设 `padding-bottom` 把内容顶起(宿主没有底部
34
+ 停靠钩子);找不到锚点元素时静默降级为浮层。
35
+ - **模型工具**:无——本插件刻意只做 UI。
36
+
37
+ ## 配置
38
+
39
+ Schemastery `Config`(宿主 Plugins 设置页自动渲染),和 / 或 profile 的
40
+ `cordis.patch.yml`:
41
+
42
+ ```yaml
43
+ - insert:
44
+ - id: dsh-single-terminal
45
+ name: dsh-single-terminal
46
+ config:
47
+ defaultShell: powershell # powershell | pwsh | cmd | gitbash | wsl | <自定义 id>
48
+ defaultCwd: home # home | workspace | 绝对路径
49
+ scrollbackLimit: 200000 # 每会话回放环形缓冲字节上限
50
+ fontSize: 13
51
+ fontFamily: Consolas, "Cascadia Mono", "Courier New", monospace
52
+ customShells:
53
+ - id: nu
54
+ name: Nushell
55
+ command: nu # 支持从 PATH 解析
56
+ args: []
57
+ ```
58
+
59
+ - `defaultShell` —— `+` 按钮使用的 shell;不可用时自动回退(Windows 回退
60
+ `powershell`,POSIX 回退 `$SHELL`/`bash`)。
61
+ - `defaultCwd` —— `home`(默认)从用户主目录启动;`workspace` 预留(当前等同
62
+ home);绝对路径必须存在。
63
+ - `customShells` —— 额外启动器;`command` 可为绝对路径或从 `PATH` 解析的名称
64
+ (Windows 上叠加 `PATHEXT`)。
65
+
66
+ ## 安装
67
+
68
+ ```sh
69
+ # 本地开发
70
+ dsh plugin --profile web add ./dsh-single-terminal
71
+
72
+ # 已发布:npm / tarball / GitHub
73
+ dsh plugin --profile web add dsh-single-terminal
74
+ dsh plugin --profile web add ./dsh-single-terminal-0.1.0.tgz
75
+ dsh plugin --profile web add github:you/dsh-single-terminal#<sha>
76
+
77
+ dsh --profile web # 启动(宿主半边需重启后生效)
78
+ ```
79
+
80
+ > **node-pty** 是宿主半边的原生依赖(`dependencies`,构建时保持 external,
81
+ > 运行时经 `createRequire` 加载)。常见平台有预编译产物;特殊平台
82
+ > `pnpm install` 时需要 C/C++ 工具链编译。浏览器半边完整内联 xterm.js,
83
+ > 无运行时依赖。
84
+
85
+ ## 开发
86
+
87
+ 环境要求:**Node ≥ 22.19(或 ≥ 24)+ pnpm 10**(`packageManager` 固定 pnpm 版本)。
88
+
89
+ ```sh
90
+ pnpm install # node-pty + ws(运行时)、@xterm/*(内联进 client)
91
+ pnpm run check # 全树 TypeScript 类型检查(tsc -b)
92
+ pnpm run build # 清空 lib → tsc -b(声明文件)→ tsdown(双半产物)
93
+ pnpm run watch # tsdown watch 模式
94
+ pnpm run verify # 模拟宿主 seed 表检查 lib/client.js 可加载
95
+ ```
96
+
97
+ ```
98
+ ├── src/host/ # 宿主半边:index.ts(入口,ws 路由 + 配置)、hub.ts(会话 Hub + 帧协议)、shells.ts(注册表 + 探测)、types.ts
99
+ ├── src/client/ # 浏览器半边:plugin.tsx(slots)、drawer.tsx、term.tsx、controller.ts、ws.ts、styles.ts、i18n.ts ...
100
+ ├── lib/index.js # 宿主半边产物(tsdown,ESM)
101
+ ├── lib/client.js # 浏览器半边产物(tsdown → __ModuleLoader__ 工厂,xterm 已内联)
102
+ ├── scripts/verify-client.mjs # 宿主 seed 表模拟检查
103
+ ├── scripts/gen-xterm-css.mjs # 从 @xterm/xterm 包重新生成 src/client/xterm-css.ts
104
+ ├── cordis.patch.yml # Bundle patch:按包名引用的插件行(无路径)
105
+ └── package.json # dsh.bundle + dsh.client(web) manifests + peerDependencies
106
+ ```
107
+
108
+ ## 实现说明
109
+
110
+ - **插件为何自带 node-pty**:宿主 `subprocess` 的终端原语
111
+ (`SubprocessTerminalHandle`)不暴露 `resize`,而尺寸跟随是终端抽屉的刚需;
112
+ 插件自持 `node-pty` 即可获得与宿主同底座(ConPTY/forkpty)的完整
113
+ `write / resize / kill` 控制。
114
+ - **传输**:经 `ctx.webServer.registerUpgrade` 注册独立 WebSocket 路由
115
+ (`/api/dsh-single-terminal.ws`),`ctx.connection.requestRejection`
116
+ 鉴权(与宿主 API gateway 同一信任围栏)。客户端同源连接,自动携带
117
+ `dsh-auth` cookie。
118
+ - **会话模型**:会话保存在 Hub 的 `Map` 中,与 socket 解耦——页面刷新 / 重连后
119
+ 重新 `list`、adopt 存活会话并 `attach` 回放环形缓冲。已退出的会话从快照中
120
+ 修剪,死标签不会复活。多个浏览器标签可同时 attach 同一会话(输出广播、
121
+ 输入合并)。
122
+ - **帧协议**:JSON 文本帧;客户端 → 宿主 `open / input / resize / close /
123
+ list / attach / ping`,宿主 → 客户端 `hello / shells / opened / data /
124
+ replay / exit / error / pong`。`input`/`resize` 在服务端限长并钳制尺寸。
125
+ - **Windows 进程树**:关闭标签执行 `pty.kill()` 后追加 `taskkill /T /F` ——
126
+ 仅关 ConPTY 时 PowerShell(+PSReadLine)可能存活;POSIX 杀前台进程组
127
+ (`kill(-pid)`)。
128
+ - **不修改官方 `deepseek-harness` 项目**;全部 UI 落在既有插槽
129
+ (`shell.overlay`、`conversation.session.header.utilities`)。
@@ -0,0 +1,11 @@
1
+ # dsh-single-terminal 静态插件 · 组合包 patch(docs/develop/basic/publish 形态)
2
+ #
3
+ # 作为 dsh.bundle 组合包的分发层:插件行按包名引用(Node 模块解析已安装代码),
4
+ # 而非相对源码路径。安装方式见 README.md。
5
+
6
+ - insert:
7
+ - id: dsh-single-terminal
8
+ name: dsh-single-terminal
9
+ config:
10
+ defaultShell: powershell
11
+ defaultCwd: workspace