@zhangzhian/dsh-devtools-terminal 0.0.0-stage → 0.3.1
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.
- package/LICENSE +21 -0
- package/README.en.md +89 -0
- package/README.md +160 -2
- package/client/chunk-terminal.js +8025 -0
- package/client/client.js +1380 -0
- package/client/client.js.map +1 -0
- package/lib/index.js +11 -0
- package/lib/link-target.js +73 -0
- package/lib/links.js +222 -0
- package/lib/routes.js +115 -0
- package/lib/types/index.d.ts +29 -0
- package/lib/types/link-target.d.ts +50 -0
- package/lib/types/links.d.ts +116 -0
- package/lib/types/routes.d.ts +10 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +62 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zhian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
English | [简体中文](./README.md)
|
|
2
|
+
|
|
3
|
+
# @zhangzhian/dsh-devtools-terminal
|
|
4
|
+
|
|
5
|
+
The right-sidebar terminal for DSH devtools: takes over the platform's built-in
|
|
6
|
+
`terminal` tab kind so URLs in terminal output open on **Ctrl/Cmd + click** in the
|
|
7
|
+
**DSH right-Sidebar browser tab** (a plain click still selects text — the same
|
|
8
|
+
semantics as the VS Code terminal).
|
|
9
|
+
|
|
10
|
+
Why it takes over instead of extending: the platform terminal keeps its xterm
|
|
11
|
+
instance and UI inside a private lazy chunk of
|
|
12
|
+
`@deepseek-ai/dsh-client-ui-sidebar-terminal`, so third-party plugins can neither
|
|
13
|
+
reach the instance nor replace that UI. The clean extension point the platform
|
|
14
|
+
does offer is the **tab-type registry**: an `extension` registration with the same
|
|
15
|
+
kind takes precedence over the built-in one. Only rendering is taken over; the
|
|
16
|
+
PTY still comes from the platform's `ctx.webTerminals` (concurrency limits, idle
|
|
17
|
+
reclaim, crash recovery and the close handler keep working).
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Do not install it directly. Install the manifest package — it pulls this in as a
|
|
22
|
+
dependency and gives you a switchable component row on the plugin page:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
dsh plugin --profile web add @zhangzhian/dsh-devtools
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The manifest package also enables the **right-Sidebar browser**
|
|
29
|
+
(`@deepseek-ai/dsh-client-ui-sidebar-browser`) that the platform ships disabled on
|
|
30
|
+
Web, through its `browser.patch.yml` — so a terminal link lands right there.
|
|
31
|
+
|
|
32
|
+
Local development loop of this repository:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm install
|
|
36
|
+
pnpm --filter @zhangzhian/dsh-devtools-terminal build
|
|
37
|
+
node scripts/profile-link.mjs # link every package declaring dsh.client into ~/.dsh/profiles/web
|
|
38
|
+
node scripts/smoke-terminal-links.mjs # real browser + real PTY smoke (link lands in the Sidebar browser)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
After installing or rebuilding, let the running `dsh web` rediscover the plugin
|
|
42
|
+
(restart it, or wait for dsh-hmr to reload). **No change to the DSH installation
|
|
43
|
+
itself is needed** — a new machine, a new version or a remote SSH environment
|
|
44
|
+
only needs the plugin installed once.
|
|
45
|
+
|
|
46
|
+
## What it provides
|
|
47
|
+
|
|
48
|
+
- Right-sidebar terminal (multiple tabs); hovering a URL shows an underline and
|
|
49
|
+
a pointer cursor;
|
|
50
|
+
- **Ctrl / Cmd + click** opens the link in the **right-Sidebar browser tab** —
|
|
51
|
+
`ctx.sidebarRight.openTab('browser', { params: { url } })`; the platform picks
|
|
52
|
+
the carrier: an iframe on Web and mobile, a native `<webview>` on Desktop
|
|
53
|
+
(dsh-electron's carrier). Address bar, Back/Forward/Reload and "Open in system
|
|
54
|
+
browser" all come from that panel;
|
|
55
|
+
- When the browser tab is **unavailable** (the profile disabled that row, or the
|
|
56
|
+
platform version has no such tab kind) it falls back to
|
|
57
|
+
`window.open(..., 'noopener,noreferrer')` — a new browser tab on the Web, the
|
|
58
|
+
system browser through the desktop carrier. The fallback never swallows the
|
|
59
|
+
click;
|
|
60
|
+
- Plain click does not open (selection and cursor behave as before);
|
|
61
|
+
- Wrapped URLs, wide characters, CJK punctuation and balanced brackets are all
|
|
62
|
+
handled from the real terminal buffer;
|
|
63
|
+
- OSC 8 hyperlinks follow the same rules (replacing xterm's default
|
|
64
|
+
"single click + confirm + blank page" fallback);
|
|
65
|
+
- If the terminal service is absent, the body shows a notice and the rest of the
|
|
66
|
+
plugin keeps working.
|
|
67
|
+
|
|
68
|
+
### Why the Sidebar browser comes first
|
|
69
|
+
|
|
70
|
+
Dev-server pages are exactly what the panel handles best: vite / next /
|
|
71
|
+
storybook and backend preview pages on a loopback port almost never refuse
|
|
72
|
+
framing. Start the server and watch it in the Sidebar instead of leaving DSH for
|
|
73
|
+
another browser tab. Public sites can still show a blank frame because of
|
|
74
|
+
`X-Frame-Options` / `CSP frame-ancestors` — that is the physical limit of an
|
|
75
|
+
iframe, and the panel's "Open in system browser" (↗) is the way out.
|
|
76
|
+
|
|
77
|
+
The destination rule is a pure function (`src/link-target.ts`) with unit tests
|
|
78
|
+
pinning "panel first / fall back when the panel throws / never open non-http(s)";
|
|
79
|
+
the real click semantics are checked in a real browser by
|
|
80
|
+
`scripts/smoke-terminal-links.mjs` (plain click opens nothing, Ctrl/Cmd+click
|
|
81
|
+
opens in the Sidebar browser with zero `window.open` calls).
|
|
82
|
+
|
|
83
|
+
## Requirements
|
|
84
|
+
|
|
85
|
+
- DSH `0.2.0-rc.2` or newer (peer range lives in `package.json`);
|
|
86
|
+
- Browser-side runtime: `dsh.client.platform` is `web`;
|
|
87
|
+
- The host's terminal service (`@deepseek-ai/dsh-api-terminal-controller`) ships
|
|
88
|
+
with `dsh web` by default; without it the body shows "unavailable" instead of
|
|
89
|
+
failing.
|
package/README.md
CHANGED
|
@@ -1,3 +1,161 @@
|
|
|
1
|
-
#
|
|
1
|
+
[English](#english) | 简体中文
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @zhangzhian/dsh-devtools-terminal
|
|
4
|
+
|
|
5
|
+
DSH 开发工具的右侧栏终端:接管平台内置的 `terminal` 页签,输出里的 URL 支持
|
|
6
|
+
**Ctrl/Cmd + 点击**在 **DSH 右栏的浏览器页签**里打开(普通点击仍然是选择/光标,
|
|
7
|
+
与 VSCode 终端同一套语义)。
|
|
8
|
+
|
|
9
|
+
为什么必须接管:平台终端把 xterm 实例和 UI 做进了 `@deepseek-ai/dsh-client-ui-sidebar-terminal`
|
|
10
|
+
的私有懒加载块,第三方插件拿不到实例、也换不掉那块 UI;平台自己提供的干净扩展点是
|
|
11
|
+
**页签类型注册表**——同 kind 的 `extension` 注册会顶掉内置类型。接管的是「怎么画」,
|
|
12
|
+
PTY 仍然是平台的 `ctx.webTerminals`(并发上限、空闲回收、崩溃恢复、关闭 handler 照旧)。
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
不要单独装它。装清单包——它会作为依赖自动拉下来,并在插件页上给你一个可开关的组件行:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
dsh plugin --profile web add @zhangzhian/dsh-devtools
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
清单包同时用 `browser.patch.yml` 打开了平台默认在 web 上关掉的**右栏浏览器**
|
|
23
|
+
(`@deepseek-ai/dsh-client-ui-sidebar-browser`),所以终端链接点下去就落在那里。
|
|
24
|
+
|
|
25
|
+
本仓库开发回路:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm install
|
|
29
|
+
pnpm --filter @zhangzhian/dsh-devtools-terminal build
|
|
30
|
+
node scripts/profile-link.mjs # 把声明了 dsh.client 的包接进 ~/.dsh/profiles/web
|
|
31
|
+
node scripts/smoke-terminal-links.mjs # 真浏览器 + 真 PTY 冒烟(链接落在右栏浏览器里)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
装完/改完都要让运行中的 dsh web 重新发现插件(重启 dsh web,或等 dsh-hmr 重载)。
|
|
35
|
+
**不需要**改 DSH 安装本身——换机器、换版本、远端 SSH 环境,装一次插件即可。
|
|
36
|
+
|
|
37
|
+
## 提供什么
|
|
38
|
+
|
|
39
|
+
- 右侧栏终端(多页签),悬停 URL 出现下划线 + 手型;
|
|
40
|
+
- **Ctrl / Cmd + 点击**在**右栏浏览器页签**里打开链接——
|
|
41
|
+
`ctx.sidebarRight.openTab('browser', { params: { url } })`,载体由平台决定:
|
|
42
|
+
web / 移动端是 iframe,桌面端(dsh-electron 的 carrier)是原生 `<webview>`;
|
|
43
|
+
地址栏、后退/前进/刷新和「在系统浏览器中打开」都由那个面板提供;
|
|
44
|
+
- 右栏浏览器页签**不可用**时(profile 关掉了那一行、或平台版本没有这个页签类型)
|
|
45
|
+
自动回退 `window.open(..., 'noopener,noreferrer')`:浏览器里是新标签页,
|
|
46
|
+
桌面端由 carrier 交给系统浏览器——**回退不会吞掉这次点击**;
|
|
47
|
+
- 普通点击不打开(选择/光标原样);
|
|
48
|
+
- 折行 URL、宽字符、中文标点、成对括号都按终端真实 buffer 处理;
|
|
49
|
+
- OSC 8 超链接走同一套逻辑(替掉 xterm 默认「单击 + confirm + 空白页」的兜底);
|
|
50
|
+
- 终端服务缺席时正文显示提示,插件其余部分不崩。
|
|
51
|
+
|
|
52
|
+
### 为什么优先右栏浏览器(而不是系统浏览器)
|
|
53
|
+
|
|
54
|
+
开发工具用户的日常恰好是面板能打开的那一类页面:自己起的 dev server(vite / next /
|
|
55
|
+
storybook、后端预览页……),本地回环端口几乎都不发反嵌头。起完服务直接在右栏看,
|
|
56
|
+
不用离开 DSH 再开一个浏览器标签页。公网站点仍可能因为 `X-Frame-Options` /
|
|
57
|
+
`CSP frame-ancestors` 白屏——那是 iframe 的物理上限,用面板工具栏右侧的
|
|
58
|
+
「在系统浏览器中打开」(↗)即可。
|
|
59
|
+
|
|
60
|
+
落点规则是纯函数(`src/link-target.ts`),单元测试钉住「面板优先 / 面板抛错回退 /
|
|
61
|
+
非 http(s) 一律不打开」;真浏览器里的点击语义由 `scripts/smoke-terminal-links.mjs`
|
|
62
|
+
核对(普通点击不开、Cmd/Ctrl+点击在右栏浏览器里打开且 `window.open` 零次)。
|
|
63
|
+
|
|
64
|
+
## 要求
|
|
65
|
+
|
|
66
|
+
- DSH `0.2.0-rc.2` 或更新(peer 区间写在 `package.json` 里);
|
|
67
|
+
- 浏览器侧运行时:`dsh.client.platform` 是 `web`;
|
|
68
|
+
- 宿主的终端服务(`@deepseek-ai/dsh-api-terminal-controller`)默认随 `dsh web` 提供;
|
|
69
|
+
没有它时正文显示「不可用」,不报错。
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## English
|
|
74
|
+
|
|
75
|
+
# @zhangzhian/dsh-devtools-terminal
|
|
76
|
+
|
|
77
|
+
The right-sidebar terminal for DSH devtools: takes over the platform's built-in
|
|
78
|
+
`terminal` tab kind so URLs in terminal output open on **Ctrl/Cmd + click** in the
|
|
79
|
+
**DSH right-Sidebar browser tab** (a plain click still selects text — the same
|
|
80
|
+
semantics as the VS Code terminal).
|
|
81
|
+
|
|
82
|
+
Why it takes over instead of extending: the platform terminal keeps its xterm
|
|
83
|
+
instance and UI inside a private lazy chunk of
|
|
84
|
+
`@deepseek-ai/dsh-client-ui-sidebar-terminal`, so third-party plugins can neither
|
|
85
|
+
reach the instance nor replace that UI. The clean extension point the platform
|
|
86
|
+
does offer is the **tab-type registry**: an `extension` registration with the same
|
|
87
|
+
kind takes precedence over the built-in one. Only rendering is taken over; the
|
|
88
|
+
PTY still comes from the platform's `ctx.webTerminals` (concurrency limits, idle
|
|
89
|
+
reclaim, crash recovery and the close handler keep working).
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
Do not install it directly. Install the manifest package — it pulls this in as a
|
|
94
|
+
dependency and gives you a switchable component row on the plugin page:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
dsh plugin --profile web add @zhangzhian/dsh-devtools
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The manifest package also enables the **right-Sidebar browser**
|
|
101
|
+
(`@deepseek-ai/dsh-client-ui-sidebar-browser`) that the platform ships disabled on
|
|
102
|
+
Web, through its `browser.patch.yml` — so a terminal link lands right there.
|
|
103
|
+
|
|
104
|
+
Local development loop of this repository:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pnpm install
|
|
108
|
+
pnpm --filter @zhangzhian/dsh-devtools-terminal build
|
|
109
|
+
node scripts/profile-link.mjs # link every package declaring dsh.client into ~/.dsh/profiles/web
|
|
110
|
+
node scripts/smoke-terminal-links.mjs # real browser + real PTY smoke (link lands in the Sidebar browser)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
After installing or rebuilding, let the running `dsh web` rediscover the plugin
|
|
114
|
+
(restart it, or wait for dsh-hmr to reload). **No change to the DSH installation
|
|
115
|
+
itself is needed** — a new machine, a new version or a remote SSH environment
|
|
116
|
+
only needs the plugin installed once.
|
|
117
|
+
|
|
118
|
+
## What it provides
|
|
119
|
+
|
|
120
|
+
- Right-sidebar terminal (multiple tabs); hovering a URL shows an underline and
|
|
121
|
+
a pointer cursor;
|
|
122
|
+
- **Ctrl / Cmd + click** opens the link in the **right-Sidebar browser tab** —
|
|
123
|
+
`ctx.sidebarRight.openTab('browser', { params: { url } })`; the platform picks
|
|
124
|
+
the carrier: an iframe on Web and mobile, a native `<webview>` on Desktop
|
|
125
|
+
(dsh-electron's carrier). Address bar, Back/Forward/Reload and "Open in system
|
|
126
|
+
browser" all come from that panel;
|
|
127
|
+
- When the browser tab is **unavailable** (the profile disabled that row, or the
|
|
128
|
+
platform version has no such tab kind) it falls back to
|
|
129
|
+
`window.open(..., 'noopener,noreferrer')` — a new browser tab on the Web, the
|
|
130
|
+
system browser through the desktop carrier. The fallback never swallows the
|
|
131
|
+
click;
|
|
132
|
+
- Plain click does not open (selection and cursor behave as before);
|
|
133
|
+
- Wrapped URLs, wide characters, CJK punctuation and balanced brackets are all
|
|
134
|
+
handled from the real terminal buffer;
|
|
135
|
+
- OSC 8 hyperlinks follow the same rules (replacing xterm's default
|
|
136
|
+
"single click + confirm + blank page" fallback);
|
|
137
|
+
- If the terminal service is absent, the body shows a notice and the rest of the
|
|
138
|
+
plugin keeps working.
|
|
139
|
+
|
|
140
|
+
### Why the Sidebar browser comes first
|
|
141
|
+
|
|
142
|
+
Dev-server pages are exactly what the panel handles best: vite / next /
|
|
143
|
+
storybook and backend preview pages on a loopback port almost never refuse
|
|
144
|
+
framing. Start the server and watch it in the Sidebar instead of leaving DSH for
|
|
145
|
+
another browser tab. Public sites can still show a blank frame because of
|
|
146
|
+
`X-Frame-Options` / `CSP frame-ancestors` — that is the physical limit of an
|
|
147
|
+
iframe, and the panel's "Open in system browser" (↗) is the way out.
|
|
148
|
+
|
|
149
|
+
The destination rule is a pure function (`src/link-target.ts`) with unit tests
|
|
150
|
+
pinning "panel first / fall back when the panel throws / never open non-http(s)";
|
|
151
|
+
the real click semantics are checked in a real browser by
|
|
152
|
+
`scripts/smoke-terminal-links.mjs` (plain click opens nothing, Ctrl/Cmd+click
|
|
153
|
+
opens in the Sidebar browser with zero `window.open` calls).
|
|
154
|
+
|
|
155
|
+
## Requirements
|
|
156
|
+
|
|
157
|
+
- DSH `0.2.0-rc.2` or newer (peer range lives in `package.json`);
|
|
158
|
+
- Browser-side runtime: `dsh.client.platform` is `web`;
|
|
159
|
+
- The host's terminal service (`@deepseek-ai/dsh-api-terminal-controller`) ships
|
|
160
|
+
with `dsh web` by default; without it the body shows "unavailable" instead of
|
|
161
|
+
failing.
|