dshost-plugin 0.1.9 → 0.1.11

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 (3) hide show
  1. package/README.md +7 -3
  2. package/lib/core.js +17 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![GitHub](https://img.shields.io/badge/GitHub-NoelJudeNoel%2Fdshost--plugin-blue)](https://github.com/NoelJudeNoel/dshost-plugin)
7
7
 
8
8
  **DSHost 官方 DSH 远程中继插件** — 在你的 dsh(DeepSeek Harness)实例上运行一个 Agent,
9
- 通过 `wss` 主动外连 DHost 中继,让你在世界任何地方用浏览器安全访问自己的 dsh Web UI,
9
+ 通过 `wss` 主动外连 DSHost 中继,让你在世界任何地方用浏览器安全访问自己的 dsh Web UI,
10
10
  无需公网 IP、无需端口映射。
11
11
 
12
12
  *Official remote cloud relay plugin for DSHost (dshost.me): securely access your
@@ -15,7 +15,7 @@ dsh Web UI from anywhere.*
15
15
  ## 特性
16
16
 
17
17
  - **零公网 IP**:Agent 主动外连中继(`wss://dshost.me/agent`),本机不开任何入站端口
18
- - **零破坏性多版本兼容**:同时支持 dsh `0.0.1-rc.*` / `0.1.0-rc.*` / `0.1.1-*` / `0.1.2-*`
18
+ - **零破坏性多版本兼容**:同时支持 dsh `0.0.1-rc.*` / `0.1.0-rc.*` / `0.1.1-*` ~ `0.1.5-*`
19
19
  - **安全**:中继层 Host/Origin 重写遵守 dsh 信任栅栏;`settings.describe` 密钥脱敏下发;
20
20
  生产环境强制 `wss://`
21
21
  - **随 dsh 启动**:以 cordis 插件身份随 `dsh web` 加载,自动重连、休眠省流
@@ -30,7 +30,10 @@ dsh Web UI from anywhere.*
30
30
  ### 2. 一键安装(推荐)
31
31
 
32
32
  ```bash
33
+ # macOS / Linux
33
34
  curl -fsSL https://dshost.me/install.sh | bash
35
+ # Windows (PowerShell)
36
+ $env:RELAY_HOST='dshost.me'; irm https://dshost.me/install.ps1 | iex
34
37
  ```
35
38
 
36
39
  脚本会安装 pnpm、通过 `dsh plugin add dshost-plugin` 把插件装入当前 profile,
@@ -47,7 +50,7 @@ dsh plugin add dshost-plugin
47
50
 
48
51
  ```yaml
49
52
  - insert:
50
- - id: dsh-remote-agent
53
+ - id: dshost-agent
51
54
  name: 'dshost-plugin'
52
55
  config:
53
56
  token: dsh_your_token_here
@@ -76,6 +79,7 @@ sudo systemctl restart dsh # 或你的启动方式
76
79
 
77
80
  | dsh 版本 | 支持 |
78
81
  |---|---|
82
+ | `0.1.5-*`(已实证 `0.1.5-rc.1`) / `0.1.4-*` / `0.1.3-*` | ✔ |
79
83
  | `0.1.2-*`(含 `--trusted-host`、BrowserAuth、remote.mux) | ✔ |
80
84
  | `0.1.1-*` / `0.1.0-rc.7+`(insert 块 patch 格式) | ✔ |
81
85
  | `0.1.0-rc.2 ~ rc.6` / `0.0.1-rc.*` | ✔(旧包名 `@noeljude/dsh-remote-plugin` 亦可解析) |
package/lib/core.js CHANGED
@@ -267,6 +267,9 @@ export function collectSystemInfo(defaultVersion) {
267
267
  diskFree,
268
268
  dshVersion: defaultVersion || meta.dshVersion,
269
269
  plugins: meta.plugins,
270
+ // 服务旁挂:独立 services agent(DSH_SERVICES_ONLY=1,无本地 dsh 承载)
271
+ // 上报 role=services,relay 不将其注册为主实例,只挂到同 hostname 的主实例下
272
+ role: process.env.DSH_SERVICES_ONLY === '1' ? 'services' : 'dsh',
270
273
  // 无头检测:供 relay 注入脚本决定产物点击行为(新窗口HTTP直出 vs 本地打开)
271
274
  headless: !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY,
272
275
  };
@@ -334,6 +337,7 @@ export function normalizeServices(raw, log) {
334
337
  auth: s.auth === 'sso' ? 'sso' : 'open',
335
338
  entry: typeof s.entry === 'string' && s.entry.startsWith('/') ? s.entry : '/',
336
339
  ssoSecret: typeof s.ssoSecret === 'string' && s.ssoSecret ? s.ssoSecret : '',
340
+ spa: s.spa === true,
337
341
  basicUser: typeof s.basicUser === 'string' ? s.basicUser : '',
338
342
  basicPassword: typeof s.basicPassword === 'string' ? s.basicPassword : '',
339
343
  host: up.host,
@@ -470,9 +474,11 @@ export function startAgent(opts) {
470
474
  log.log?.(`[agent] Registered as ${msg.username} (session ${msg.sessionId || ''})`);
471
475
  send(ws, { type: 'system-info', info: collectSystemInfo(dshVersion) });
472
476
  // 插件工作区:上报本实例声明的服务清单(relay 存实例维度,供 /p 路由校验)
477
+ // DSH_SERVICES_ONLY=1:独立 services agent,relay 不注册主实例(服务旁挂到同机 dsh 实例)
473
478
  send(ws, {
474
479
  type: 'services',
475
- services: svcList.map(({ id, name, desc, icon, auth, entry }) => ({ id, name, desc, icon, auth, entry })),
480
+ servicesOnly: process.env.DSH_SERVICES_ONLY === '1' || undefined,
481
+ services: svcList.map(({ id, name, desc, icon, auth, entry, spa }) => ({ id, name, desc, icon, auth, entry, spa })),
476
482
  });
477
483
  startHeartbeat(ws);
478
484
  return;
@@ -561,9 +567,17 @@ export function startAgent(opts) {
561
567
 
562
568
  function startHeartbeat(ws) {
563
569
  if (heartbeatInterval) clearInterval(heartbeatInterval);
570
+ // 半开死链看门狗:只发不收时 TCP 仍 ESTAB(FIN 被代理链路吞掉的场景),
571
+ // close 事件永远不来,agent 变僵尸。每次 ping 记账,收到任意下行帧清零;
572
+ // 连续 3 个周期(45s)无下行则主动 terminate() 触发重连。
573
+ let lastRx = Date.now();
574
+ ws.on('message', () => { lastRx = Date.now(); });
564
575
  heartbeatInterval = setInterval(() => {
565
- if (ws.readyState === WebSocket.OPEN) {
566
- send(ws, { type: 'heartbeat', ts: Date.now() });
576
+ if (ws.readyState !== WebSocket.OPEN) return;
577
+ send(ws, { type: 'heartbeat', ts: Date.now() });
578
+ if (Date.now() - lastRx > 45000) {
579
+ log.log?.('[agent] heartbeat watchdog: no inbound for 45s, forcing reconnect');
580
+ try { ws.terminate(); } catch (eT) {}
567
581
  }
568
582
  }, 15000);
569
583
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dshost-plugin",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Official remote cloud relay plugin for DSHost (dshost.me): securely access your dsh Web UI from anywhere",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",