dsh-zen-remote 1.1.11 → 1.1.12
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/AGENTS.md +24 -0
- package/README.md +7 -3
- package/README.zh-CN.md +7 -3
- package/docs/interface.md +2 -2
- package/dsh-push.mjs +25 -1
- package/lan-gate.mjs +16 -1
- package/lib/client.js +350 -36
- package/lib/lan-gate-server.cjs +107 -4
- package/lib/types/client/MobileHome.d.ts +7 -2
- package/lib/types/client/MobileHome.d.ts.map +1 -1
- package/lib/types/client/MobileSessionInfo.d.ts +2 -2
- package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
- package/lib/types/client/compat/store.d.ts +62 -0
- package/lib/types/client/compat/store.d.ts.map +1 -0
- package/lib/types/client/compat/types.d.ts +84 -0
- package/lib/types/client/compat/types.d.ts.map +1 -0
- package/lib/types/client/debug.d.ts +1 -1
- package/lib/types/client/debug.d.ts.map +1 -1
- package/lib/types/client/effects/aionui-compat.d.ts +1 -1
- package/lib/types/client/effects/aionui-compat.d.ts.map +1 -1
- package/lib/types/client/effects/gestures.d.ts +1 -1
- package/lib/types/client/effects/gestures.d.ts.map +1 -1
- package/lib/types/client/effects/header-status.d.ts +1 -1
- package/lib/types/client/effects/header-status.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-avoid.d.ts +1 -1
- package/lib/types/client/effects/keyboard-avoid.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
- package/lib/types/client/effects/modal-back.d.ts +1 -1
- package/lib/types/client/effects/modal-back.d.ts.map +1 -1
- package/lib/types/client/effects/native-trigger-overlay.d.ts +1 -1
- package/lib/types/client/effects/native-trigger-overlay.d.ts.map +1 -1
- package/lib/types/client/effects/phone-chrome.d.ts +1 -1
- package/lib/types/client/effects/phone-chrome.d.ts.map +1 -1
- package/lib/types/client/effects/turn-fold.d.ts +1 -1
- package/lib/types/client/effects/turn-fold.d.ts.map +1 -1
- package/lib/types/client/effects/welcome-notice.d.ts +1 -1
- package/lib/types/client/effects/welcome-notice.d.ts.map +1 -1
- package/lib/types/client/effects/workbench-ref-close.d.ts +1 -1
- package/lib/types/client/effects/workbench-ref-close.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/nav-store.d.ts +2 -2
- package/lib/types/client/nav-store.d.ts.map +1 -1
- package/lib/types/client/session-dot.d.ts +11 -3
- package/lib/types/client/session-dot.d.ts.map +1 -1
- package/lib/types/client/styles/compat.css.d.ts +1 -1
- package/lib/types/client/styles/compat.css.d.ts.map +1 -1
- package/lib/types/client/styles/composer.css.d.ts +1 -1
- package/lib/types/client/styles/composer.css.d.ts.map +1 -1
- package/lib/types/client/styles/info.css.d.ts +1 -1
- package/lib/types/client/styles/info.css.d.ts.map +1 -1
- package/package.json +49 -26
- package/scripts/check-client-externals.mjs +48 -0
- package/scripts/check-compat-store.mjs +113 -0
- package/scripts/check-host-shadow.mjs +145 -0
- package/scripts/check-info-sheet-stacking.mjs +55 -0
- package/src/client/MobileAttachButton.tsx +1 -1
- package/src/client/MobileHome.tsx +33 -7
- package/src/client/MobileSessionInfo.tsx +6 -4
- package/src/client/chips-store.ts +1 -1
- package/src/client/compat/store.ts +205 -0
- package/src/client/compat/types.ts +115 -0
- package/src/client/debug.ts +1 -1
- package/src/client/effects/aionui-compat.ts +1 -1
- package/src/client/effects/gestures.ts +1 -1
- package/src/client/effects/header-status.ts +22 -3
- package/src/client/effects/keyboard-avoid.ts +1 -1
- package/src/client/effects/keyboard-guard.ts +1 -1
- package/src/client/effects/modal-back.ts +1 -1
- package/src/client/effects/native-trigger-overlay.ts +1 -1
- package/src/client/effects/phone-chrome.ts +1 -1
- package/src/client/effects/turn-fold.ts +1 -1
- package/src/client/effects/welcome-notice.ts +1 -1
- package/src/client/effects/workbench-ref-close.ts +1 -1
- package/src/client/index.tsx +66 -6
- package/src/client/nav-store.ts +2 -2
- package/src/client/session-dot.ts +13 -4
- package/src/client/styles/compat.css.ts +43 -11
- package/src/client/styles/composer.css.ts +14 -2
- package/src/client/styles/info.css.ts +21 -0
package/AGENTS.md
CHANGED
|
@@ -40,6 +40,30 @@ release 徽章和 profile 依赖示例由 `scripts/sync-doc-version.mjs` 按 `pa
|
|
|
40
40
|
把测试挂掉。文档里的锚点变了就更新那个脚本:找不到标记它直接非零退出,不会
|
|
41
41
|
默默通过。
|
|
42
42
|
|
|
43
|
+
**发版**:全部由 tag 驱动,本地只做一步。
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm version patch # 改 package.json + 同步两份 README + 建 commit 和 v* tag
|
|
47
|
+
git push --follow-tags # 推 tag 才是真正的触发器
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
推上去之后 `.github/workflows/publish.yml` 依次做:装依赖 → `pnpm build` →
|
|
51
|
+
**`git diff --exit-code -- lib`**(入库产物必须与重新构建的结果一致,挡住
|
|
52
|
+
「改了 src 忘了 build 就打 tag」)→ `pnpm verify` → `pnpm test` →
|
|
53
|
+
tag 名与 `package.json` 版本一致性 → `pnpm publish`(npm Trusted Publishing,
|
|
54
|
+
OIDC 无令牌,provenance 自动生成)→ **建 GitHub Release**。
|
|
55
|
+
|
|
56
|
+
Release 那步刻意排在 npm 之后:它宣告的是「这个版本已经发出去了」,npm 失败就
|
|
57
|
+
不该留下一个指向不存在版本的发布页。发布说明用 `--generate-notes` 按上一个 tag
|
|
58
|
+
以来的提交自动生成,所以**提交信息就是 changelog**,不另外维护文件。这一步可重入
|
|
59
|
+
(先 `gh release view` 查在不在,在就跳过),重跑失败的 workflow 不会因为
|
|
60
|
+
Release 已存在而挂掉。
|
|
61
|
+
|
|
62
|
+
需要人工配置的只有一处:npmjs.com 的包设置里登记可信发布者
|
|
63
|
+
`KyoMio/dsh-zen-remote` + 文件名 `publish.yml`。GitHub Release 那步用的是
|
|
64
|
+
workflow 自带的 `GITHUB_TOKEN`,不需要额外密钥——但 job 的 `permissions` 里
|
|
65
|
+
`contents` 必须是 `write`(原来是 `read`)。
|
|
66
|
+
|
|
43
67
|
## 深度文档
|
|
44
68
|
|
|
45
69
|
| 文件 | 内容 |
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
<p align="center">
|
|
5
5
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0B7285?style=flat-square" alt="MIT"></a>
|
|
6
|
-
<img src="https://img.shields.io/badge/release-v1.1.
|
|
6
|
+
<img src="https://img.shields.io/badge/release-v1.1.12-5B4CF0?style=flat-square" alt="v1.1.12">
|
|
7
7
|
<img src="https://img.shields.io/badge/DSH-Web%20Profile-5B4CF0?style=flat-square" alt="DSH Web Profile">
|
|
8
8
|
</p>
|
|
9
9
|
|
|
@@ -29,7 +29,11 @@ dsh plugin add dsh-zen-remote
|
|
|
29
29
|
|
|
30
30
|
Restart `dsh web` afterwards. The mobile UI and the gateway both come up — there is no config line to hand-write.
|
|
31
31
|
|
|
32
|
-
> Compatibility
|
|
32
|
+
> **Compatibility — one build, both runtimes.** Verified live on DSH `0.1.1-rc.2` and `0.1.2-rc.1` (web profile), 2026-09-04.
|
|
33
|
+
>
|
|
34
|
+
> 0.1.2 removed `@deepseek-ai/dsh-client-runtime` and put the web UI behind a signed cookie, which would have broken the mobile UI and locked the phone out of the gateway. The plugin carries its own store engine instead of importing that package, probes for the services 0.1.2 moved (`uiWorkspace`, `uiSession`) and falls back to the 0.1.1 shapes when they are absent, reads a turn's events through either `session.events` or `session.snapshotEvents()`, and lets the gateway do the browser-token handshake on the phone's behalf — all of it inert on 0.1.1, where the token endpoint does not exist.
|
|
35
|
+
>
|
|
36
|
+
> One thing to know on 0.1.2: the web UI now rejects requests whose `Host` is not trusted. Reaching DSH through this plugin's gateway is unaffected (the gateway presents every request as `127.0.0.1`), but pointing a browser straight at `http://<LAN-IP>:3080` returns 403 unless you start `dsh web --trusted-host <host>`.
|
|
33
37
|
|
|
34
38
|
To uninstall: `dsh plugin remove dsh-zen-remote` (or delete the two lines from your profile's `dependencies` and `bundles`) and restart `dsh web`. To also wipe the pairing data, delete `~/.dsh/lan-gate-state.json` and `~/.dsh/lan-gate.config.json`.
|
|
35
39
|
|
|
@@ -41,7 +45,7 @@ Edit `~/.dsh/profiles/web/package.json` by hand — one line under `dependencies
|
|
|
41
45
|
```jsonc
|
|
42
46
|
{
|
|
43
47
|
"dependencies": {
|
|
44
|
-
"dsh-zen-remote": "^1.1.
|
|
48
|
+
"dsh-zen-remote": "^1.1.12" // for local development: "link:/path/to/dsh-zen-remote"
|
|
45
49
|
},
|
|
46
50
|
"dsh": { "profile": { "bundles": [
|
|
47
51
|
"@deepseek-ai/dsh-base",
|
package/README.zh-CN.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
<p align="center">
|
|
5
5
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0B7285?style=flat-square" alt="MIT"></a>
|
|
6
|
-
<img src="https://img.shields.io/badge/release-v1.1.
|
|
6
|
+
<img src="https://img.shields.io/badge/release-v1.1.12-5B4CF0?style=flat-square" alt="v1.1.12">
|
|
7
7
|
<img src="https://img.shields.io/badge/DSH-Web%20Profile-5B4CF0?style=flat-square" alt="DSH Web Profile">
|
|
8
8
|
</p>
|
|
9
9
|
|
|
@@ -29,7 +29,11 @@ dsh plugin add dsh-zen-remote
|
|
|
29
29
|
|
|
30
30
|
装完重启 `dsh web`,手机界面与网关一起生效,不需要再手写任何配置行。
|
|
31
31
|
|
|
32
|
-
>
|
|
32
|
+
> **兼容性——同一份产物,两个运行时。** 在 DSH `0.1.1-rc.2` 与 `0.1.2-rc.1`(web profile)上均实机验证,2026-09-04。
|
|
33
|
+
>
|
|
34
|
+
> 0.1.2 删掉了 `@deepseek-ai/dsh-client-runtime`,并把网页界面挪到签名 cookie 之后——照原样会让手机界面加载失败、手机经网关也进不来。本插件改为自带 store 实现而不 import 那个包;对 0.1.2 搬了家的服务(`uiWorkspace`、`uiSession`)按存在探测、取不到就走 0.1.1 的老路;回合事件 `session.events` 和 `session.snapshotEvents()` 两种读法都认;浏览器 token 交换由网关代手机完成——这些在 0.1.1 上全部惰性,因为那边根本没有 token 端点。
|
|
35
|
+
>
|
|
36
|
+
> 0.1.2 上有一点要知道:网页界面现在会拒绝 `Host` 不受信的请求。经本插件网关访问不受影响(网关把每个请求都以 `127.0.0.1` 的身份递上去),但拿浏览器直接开 `http://<局域网IP>:3080` 会得到 403,除非启动时加 `dsh web --trusted-host <host>`。
|
|
33
37
|
|
|
34
38
|
卸载:`dsh plugin remove dsh-zen-remote`(或从 profile 的 `dependencies` 与 `bundles` 里删掉那两行),重启 `dsh web` 即恢复原状;要清掉配对数据再删 `~/.dsh/lan-gate-state.json` 与 `~/.dsh/lan-gate.config.json`。
|
|
35
39
|
|
|
@@ -41,7 +45,7 @@ dsh plugin add dsh-zen-remote
|
|
|
41
45
|
```jsonc
|
|
42
46
|
{
|
|
43
47
|
"dependencies": {
|
|
44
|
-
"dsh-zen-remote": "^1.1.
|
|
48
|
+
"dsh-zen-remote": "^1.1.12" // 本地开发换成 "link:/path/to/dsh-zen-remote"
|
|
45
49
|
},
|
|
46
50
|
"dsh": { "profile": { "bundles": [
|
|
47
51
|
"@deepseek-ai/dsh-base",
|
package/docs/interface.md
CHANGED
|
@@ -119,7 +119,7 @@ composer 最左的回形针打开的是**手机本地**的文件选择器(iOS
|
|
|
119
119
|
|
|
120
120
|
**修复**
|
|
121
121
|
|
|
122
|
-
- 适配 dsh-vision-router(2.0.1):composer 识图开关在手机端压成 28px 圆形
|
|
122
|
+
- 适配 dsh-vision-router(2.0.1 / 2.1.1):composer 识图开关在手机端压成 28px 圆形
|
|
123
123
|
图标钮(眼睛为 CSS mask 图标,aria-label / aria-pressed 照旧),不再把
|
|
124
124
|
模型名挤出 composer 行;桌面端保持插件原样(见兼容插件清单)。
|
|
125
125
|
- 适配 DSH `0.1.1`:活动 chip 点击失效(点了退回信息卡)。三处上游变化同时命中
|
|
@@ -248,7 +248,7 @@ composer 最左的回形针打开的是**手机本地**的文件选择器(iOS
|
|
|
248
248
|
- [@opendsh/dsh-plugin-scheduled-tasks](https://github.com/Ceelog/dsh-plugins)(定时任务,主屏 chips 行自动收割入口)——本机实测 **0.2.3**
|
|
249
249
|
- dsh-at-file(@文件引用;它和本插件的附件 chip 读的是同一份草稿 token,手机端会为一个上传文件同时画出缩略图和文件名两条,故隐藏它 `.dsh-uploads/` 下那几行,其余 @ 引用不动;桌面端不隐藏——那边本插件的 chip 是关掉的,它是唯一的呈现)——本机实测 **0.6.7**
|
|
250
250
|
- [@ace-zone/dsh-market](https://www.npmjs.com/package/@ace-zone/dsh-market)(插件市场;它的弹窗顶栏在手机上放不下,关闭的 × 被挤出面板外,故隐藏标语/版本号/官网链接三个装饰位并让标题省略号收缩,语言切换和 × 保留;认插件自己渲染的 `.dshm-ver[title="@ace-zone/dsh-market"]` 版本片,同名的其他"市场"插件不会被误伤)——本机实测 **0.1.66**
|
|
251
|
-
- [dsh-vision-router](https://github.com/ysr666/dsh-vision-router)(视觉桥,composer 行内的识图开关胶囊;手机端压成 28px 圆形图标钮——原胶囊 👁+文字+激活 ✓ 约 90px 定宽,而手机 composer
|
|
251
|
+
- [dsh-vision-router](https://github.com/ysr666/dsh-vision-router)(视觉桥,composer 行内的识图开关胶囊;手机端压成 28px 圆形图标钮——原胶囊 👁+文字+激活 ✓ 约 90px 定宽,而手机 composer 行不换行、模型座位是唯一可收缩项,会被它挤没;按钮里只留一只 16px 眼睛:span 一律隐藏;2.1.x 起插件自带 svg 图标,只保留第一个 svg、用兄弟选择器隐掉其后的(当前是激活态的对钩),我们自己的 `::before` mask 眼睛降级为 `:has(svg)` 兜底、只给 2.0.x 的文字写法用;开合状态仍走插件自己的品牌描边/着色与 `aria-pressed`,可访问名走按钮自带的 aria-label)——本机实测 **2.0.1** 与 **2.1.1**。2.1.1 把 👁/✓ 从文字 span 换成 svg,只按 2.0.x 写的规则会渲染出**两只眼**且对钩无人隐藏(2026-09-04 用户报);回归由 `test/vision-router-compat-css.test.cjs` 守着
|
|
252
252
|
- [dsh-web-ui 全家桶](https://www.npmjs.com/package/@linxin666/dsh-web-ui-all)(文件树 / 预览 / 任务看板 / SSH / 宠物 / 会话统计 / 远程配对 / 设置)——沿用上游兼容规则,本次未扩展
|
|
253
253
|
|
|
254
254
|
## 安装
|
package/dsh-push.mjs
CHANGED
|
@@ -180,6 +180,30 @@ export function pendingQuestionText(rawArguments) {
|
|
|
180
180
|
} catch { return '' }
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Session event log, read compatibly across both DSH versions: 0.1.1 exposes
|
|
185
|
+
* `session.events` as an array getter; 0.1.2 replaced it with the
|
|
186
|
+
* `session.snapshotEvents()` method. When neither is available, return [] so
|
|
187
|
+
* turnSummary walks its own "not an array → ''" path.
|
|
188
|
+
* @param session - the session object, possibly undefined.
|
|
189
|
+
* @returns the event array.
|
|
190
|
+
*/
|
|
191
|
+
export function sessionEvents(session) {
|
|
192
|
+
if (session && Array.isArray(session.events)) return session.events
|
|
193
|
+
if (session && typeof session.snapshotEvents === 'function') {
|
|
194
|
+
// ponytail: snapshotEvents() with no argument copies the WHOLE event log
|
|
195
|
+
// on every call. That is acceptable here — this branch only runs when
|
|
196
|
+
// INCLUDE_SUMMARY is on (dsh-push.mjs:53, off by default) and at most once
|
|
197
|
+
// per turn end. Slicing would need the turn's start seq, and the
|
|
198
|
+
// agent/turn-stopping payload carries none: its emitter (0.1.2
|
|
199
|
+
// dsh-agent-loop) sends only `{ turn, signal }` plus the injected
|
|
200
|
+
// `agent` — a turn NUMBER, not an event-log seq, and the two are not the
|
|
201
|
+
// same thing. If a future payload adds a start seq, pass it as fromSeq.
|
|
202
|
+
return session.snapshotEvents()
|
|
203
|
+
}
|
|
204
|
+
return []
|
|
205
|
+
}
|
|
206
|
+
|
|
183
207
|
const skip = (reason) => ({ shouldNotify: false, title: '', body: '', reason })
|
|
184
208
|
|
|
185
209
|
/**
|
|
@@ -420,7 +444,7 @@ export function apply(ctx) {
|
|
|
420
444
|
fire({
|
|
421
445
|
kind: 'turn-end',
|
|
422
446
|
delegationDepth: header && header.delegationDepth,
|
|
423
|
-
summary: INCLUDE_SUMMARY ? turnSummary(session
|
|
447
|
+
summary: INCLUDE_SUMMARY ? turnSummary(sessionEvents(session), payload && payload.turn) : ''
|
|
424
448
|
})
|
|
425
449
|
}
|
|
426
450
|
for (const event of EVENTS) {
|
package/lan-gate.mjs
CHANGED
|
@@ -9,7 +9,10 @@ import { fileURLToPath } from 'node:url'
|
|
|
9
9
|
import { dirname, join } from 'node:path'
|
|
10
10
|
|
|
11
11
|
export const name = 'dsh-zen-remote-gateway'
|
|
12
|
-
|
|
12
|
+
// `connection` (both DSH versions provide it — unlike 0.1.2-only services such
|
|
13
|
+
// as uiWorkspace) lets the host side read the browser-auth token URL, so
|
|
14
|
+
// adding it here does not stop the plugin activating on 0.1.1.
|
|
15
|
+
export const inject = ['subprocess', 'connection']
|
|
13
16
|
|
|
14
17
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
15
18
|
const serverFile = join(here, 'lib', 'lan-gate-server.cjs')
|
|
@@ -39,10 +42,22 @@ export function apply(ctx, config) {
|
|
|
39
42
|
|
|
40
43
|
const start = async () => {
|
|
41
44
|
try {
|
|
45
|
+
// 0.1.2 起浏览器要签名 cookie 才能进;token 只有 `GET /?token=` 一处收。
|
|
46
|
+
// authenticatedUrl 是 connection 服务的公开方法,0.1.1 没有它——用它是不是
|
|
47
|
+
// 函数来判断跑在哪一版,比看版本号可靠。只把这个 URL 交给子进程,密钥一律
|
|
48
|
+
// 不传。目标端口与网关子进程的解析一致:显式 env > cordis config > 3080。
|
|
49
|
+
const targetPort = Number(process.env.LAN_GATE_TARGET_PORT || 3080)
|
|
50
|
+
const tokenUrl = ctx.connection && typeof ctx.connection.authenticatedUrl === 'function'
|
|
51
|
+
? ctx.connection.authenticatedUrl('http://127.0.0.1:' + targetPort)
|
|
52
|
+
: undefined
|
|
42
53
|
const nodePath = await ctx.subprocess.resolveExecutable('node')
|
|
54
|
+
const env = { ...process.env }
|
|
55
|
+
if (tokenUrl !== undefined) env['LAN_GATE_UPSTREAM_TOKEN_URL'] = tokenUrl
|
|
56
|
+
else delete env['LAN_GATE_UPSTREAM_TOKEN_URL'] // 0.1.1 模式:变量不能残留
|
|
43
57
|
handle = ctx.subprocess.spawn({
|
|
44
58
|
argv: [nodePath, serverFile],
|
|
45
59
|
cwd: here,
|
|
60
|
+
env,
|
|
46
61
|
stdio: {
|
|
47
62
|
stdin: 'ignore',
|
|
48
63
|
stdout: { maxBytes: 131072 },
|