dsh-mini-remote 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  本文件记录每个版本改了什么。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.2.1] - 2026-10-17
6
+
7
+ 这一版跨了十天、46 笔改动,主体是**「远程窗口」真的能跨电脑了** —— 在另一台电脑的 DSH 桌面端里,打开这台电脑的界面。它前面压着一件必须先做的事:**多设备身份**(原来一个口令管所有设备,撤销一台等于全撤)。后面跟着一串"让它用起来不别扭"的修补,以及一件拖了很久的工程账:**这个仓库终于有 CI 了**。
8
+
9
+ ### 新加的
10
+
11
+ - **跨电脑「远程窗口」。** 在 B 电脑的 DSH 桌面端里,打开 A 电脑的界面——不用切窗口、不用远程桌面。做法是"一次性票据过门":A 发一张 30 秒、只能兑一次的票,B 的浏览器拿着它进门,进门那一刻换成窗口会话;**访问口令和长期凭据一个字节都不进浏览器**。跨站嵌入默认只许同源,带票那一次才放开。
12
+ - **地址怎么填**:填那台电脑「手机遥控」页里那条,**必须 https**(明文能配对、能取票,但框里是白的——通行凭据在非 https 的地址上会被浏览器丢掉,这是实测出来的)。推荐 Tailscale:地址固定,设一次就好。
13
+ - **A 侧有一个默认关的总开关「允许别的电脑连接」**。关着的时候,配对和取票两条路一条都不接——"关"是一个用户能读懂的整体状态。
14
+
15
+ - **多设备身份。** 每台设备一枚自己的凭据,可以单独撤销(撤销是即时的,连已经开着的窗口下次请求也会 401)。**手机页的地址栏不再带着访问口令**——口令退回它本来的角色:入场邀请函,扫一次码就发一张凭据。
16
+ - 电脑端设置页多了设备列表:看得到谁连过、能改名、能撤销。
17
+
18
+ - **自检。** 设置页最末多了一块,回答三个问题:**这台跑的是哪一版**、**哪些接口现在真的在**、**开关什么状态**。它还会说一句"进程比代码旧"——那是真机上真出过的事:桌面端连开一天,装是新版,跑的却是旧的。
19
+
20
+ - **出错的时候,看得见了。** 原来错误只打在终端里,用户看着图形界面一个字也看不到;跨机那条路连状态都不留,退出面板就再也查不到。现在有一圈"最近 20 条错误"进自检,**进去之前先脱敏**(口令、飞书密钥、地址里的凭据参数、设备凭据形状,四类都换成 `***`)。
21
+
22
+ - **电脑端界面的顶栏改成鼠标碰顶才滑出**,感应带从 6 像素加高到 16(原来几乎要精确放到那条线上)。
23
+
24
+ ### 改了的
25
+
26
+ - **侧栏那枚「远程窗口」点开是「其他电脑」名单,不再显示本机界面。** 人坐在电脑前,为什么还要在面板里再看一遍自己的界面——"看本机"是跨机做不出来时的中间验证,跨机做完了它就退休了。底层那套取票、嵌框、过门的零件保留(跨机在复用)。
27
+ - 手机侧栏的会话条目补齐了执行功能:重命名、置顶、归档、分叉。归档相关的两个按钮先藏起来(代码不删)。
28
+ - 「完整」模式回答落定后,停在这一轮内容的开头,不再停在总结正文的开头。
29
+
30
+ ### 修了的
31
+
32
+ - **远程窗口每约 25 秒整屏重载一次。** 根因是面板自己在定时换票(票一变,框的地址就变)。那个凭据本来就不会按时间过期——它只在 DSH 重启或对面撤销时失效——所以定时换票纯属多余,拆掉。
33
+ - **取票请求没有超时。** 对面不回话时,那一屏会永远停在"正在向那台电脑换一张通行证…"。现在 15 秒上限(比宿主自己那条 8 秒长,不会把"慢但会成"的请求掐掉),超时给一句人话 + 「再试一次」。
34
+ - **那个 20 秒兜底在框加载成功之后不取消**,会在加载好 19 秒后把正常界面换成"一直没打开"。现在框一加载好就掐钟。
35
+ - **框没打开时自动重取一次票。** 上一版拆掉定时换票之后只剩人手动重试,而"第一次加载被拖过 30 秒"本来能救回来——补上这条约束:自动重取永远跟着一次人的动作,最多一次,不会变成每 20 秒自己转。
36
+ - **「再点一下退出远程窗口」失效**:退出入口只挂在 16×16 的图标上,人点的是 252×36 那一行。改成整行都认。
37
+
38
+ ### 工程
39
+
40
+ - **加了 CI(GitHub Actions)。** 两个 job:`gate` 在 Windows 上跑 Node 22 与 24(红了就是真红),`probe` 在 Linux 上跑一遍(允许红,但要看得见——它红一般是"某条测试只在 Windows 上成立")。加载探针、活体检查、真机这三层仍然手跑:它们要活的 DSH,塞进 CI 只会长期红着然后没人看。
41
+ - **版本号与 CHANGELOG 改成互证。** 原来测试里钉着一个字面量版本,发一次版要改三个地方,其中一个纯粹是为了让测试继续绿。现在断言"`package.json` 的 version 必须等于 CHANGELOG 最顶上那条",忘一处必红。
42
+ - **体量守门**:手机页不超过 8,700 行 / 480 KB,发布包不超过 3 MB(问 `npm pack` 要真实数字,不自己遍历目录)。
43
+ - **发版清单入仓**(`docs/发版清单.md`):七步,从改版本到 publish 之后的核对。
44
+ - CI 首跑红了两次,抓到的都是**本机永远发现不了**的问题:一条测试要 `numpy` 而 skip 条件只探了 python;三条测试把时间钉死在 `+08:00`,而界面按本地时区显示(本机是 UTC+8 所以一直绿)。顺带记下一个能在本地预演 CI 的办法:`$env:TZ="UTC"` 之后再跑。
45
+
5
46
  ## [0.2.0] - 2026-10-08
6
47
 
7
48
  这一版跨了三天、50 笔改动,主体是**「进阶设置」——把电脑端那整套界面搬到手机上**,加上一颗「回到底部」的浮标,以及它俩连着带出来的一批手机端修补。
package/README.en.md CHANGED
@@ -1,248 +1,299 @@
1
+ <div align="center">
2
+
1
3
  # Minimal Remote · dsh-mini-remote
2
4
 
3
- [![npm](https://img.shields.io/npm/v/dsh-mini-remote)](https://www.npmjs.com/package/dsh-mini-remote)
4
- ![DSH plugin](https://img.shields.io/badge/DSH_plugin-dsh--plugin-blue)
5
- ![License](https://img.shields.io/badge/license-MIT-green)
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/promo.webp" alt="Minimal Remote: the phone keeps your instruction and its conclusion, and shows you the process only when you ask for it" width="720" />
7
+ </p>
6
8
 
7
- [中文说明](README.md)
9
+ **A lightweight mobile remote plugin crafted for DeepSeek Harness (DSH) users, resolving screen clutter and process fatigue when checking Agent status and dispatching instructions away from the desk.**
8
10
 
9
- ![Minimal Remote: only your instruction and the AI's conclusion reach the phone; everything in between stays on the computer](https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/promo.webp)
11
+ [![npm](https://img.shields.io/npm/v/dsh-mini-remote)](https://www.npmjs.com/package/dsh-mini-remote)
12
+ [![Node.js](https://img.shields.io/badge/node-%5E22.19.0%20%7C%7C%20%3E%3D24.0.0-brightgreen)](https://nodejs.org/)
13
+ [![DSH](https://img.shields.io/badge/DSH-%3E%3D0.1.5--rc.2%20%3C0.3.0-blue)](https://github.com/deepseek-ai/DeepSeek-Harness)
14
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
15
 
11
- **You send one line; the phone gets one conclusion.**
16
+ [English](README.en.md) · [简体中文](README.md)
12
17
 
13
- Tool calls, file reads and writes, sub-agent dispatch, and the body of the reasoning trace never reach the phone. This plugin exists for one situation: you're out, and all you want to do is send an instruction and read the result — a phone, one input box, the latest reply.
18
+ </div>
14
19
 
15
- [What it is](#what-it-is) ・ [When you'd use it](#when-youd-use-it) ・ [Install](#install) ・ [Connecting your phone](#connecting-your-phone-three-routes-pick-one) ・ [What the phone can do](#what-the-phone-can-do) ・ [Remote control from Feishu](#remote-control-from-feishu) ・ [FAQ](#faq) ・ [Security](#security) ・ [Why I built this](#why-i-built-this-plugin)
20
+ <p align="center">
21
+ <a href="#background--pain-points">Background & Pain Points</a> ·
22
+ <a href="#core-features">Core Features</a> ·
23
+ <a href="#ui-preview">UI Preview</a> ·
24
+ <a href="#desktop-remote-window">Remote Window</a> ·
25
+ <a href="#quick-start">Quick Start</a> ·
26
+ <a href="#usage--configuration">Usage & Configuration</a> ·
27
+ <a href="#license">License</a>
28
+ </p>
16
29
 
17
30
  ---
18
31
 
19
- ## What it is
32
+ ## Background & Pain Points
20
33
 
21
- A plugin for [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness) (DSH, a plugin-extensible AI agent framework). Once installed:
34
+ When running complex engineering tasks with desktop or web AI agents, a single turn often involves several minutes of deep reasoning, dozens of file operations, and intensive tool executions. Existing mobile remote setups typically mirror the full desktop workspace onto the phone screen, causing practical friction:
22
35
 
23
- - a web page opens on your phone with exactly one input box and the latest reply;
24
- - instructions you send from the phone go straight to the session already running on your computer;
25
- - everything in between — tool calls, files read and written, sub-agents, the reasoning trace itself — **is never pushed to the phone**;
26
- - the only thing that "talks" is the whale girl: the line the model mutters between steps, spoken in her speech bubble.
36
+ - **Imbalanced Information Density**: Raw reasoning traces, verbose tool parameters, and large unified diffs overwhelm small displays, burying the primary conclusion.
37
+ - **Attention Overload**: During commutes, meals, or brief breaks away from the keyboard, the primary goal is simply checking whether a round finished and dispatching the next instruction, without dissecting every intermediate step.
38
+ - **Inflexible Connectivity**: Pure LAN routes disconnect as soon as you step outside, while centralised cloud relays introduce external credential custody risks.
27
39
 
28
- Here is what the interface looks like — dark and light, switchable in settings (rendered at a phone size of 390×844):
40
+ **Minimal Remote** was built to solve this: by default, the mobile view presents only your input and the AI's final answer, filtering out execution noise while allowing you to drill down into the full trace on demand.
29
41
 
30
- <img width="290" alt="Dark: one conversation, carrying only your instruction and the conclusion" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/screen-dark.png" /> <img width="290" alt="Light: the same conversation, in the palette taken from the promo artwork" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/screen-light.png" />
31
-
32
- It is **not** a second screen for the desktop interface. Approval dialogs, file diffs and tool-call chains exist on the computer and nowhere on the default page — deliberately. It does very little. (If you want the **whole** desktop interface, there is an off-by-default entry in settings — see the last paragraph of [What the phone can do](#what-the-phone-can-do).)
33
-
34
- Other phone clients copy the computer's execution process over to the phone in full. This one does the opposite: **it sends only the two lines you asked for.** That is the single biggest difference between it and them.
42
+ ---
35
43
 
36
- ## When you'd use it
44
+ ## Core Features
37
45
 
38
- - **You're out and a task is still running.** The computer is at your desk mid-round; you just want to glance at the phone to see whether it finished, and hand it the next line while you're at it.
39
- - **You're with your kid, eating, or out for a walk.** You don't want to touch the computer, but an idea shows up and you'd like it working on that already.
40
- - **The computer is in the study and you're in the living room.** Not worth walking back, and not worth pulling that whole screen of process onto the phone.
46
+ - 🎛️ **Three On-Demand Presentation Modes**: Switch instantly between "Single frame" (the cleanest view, keeping only the latest conclusion), "Chat" (standard conversation bubbles), and "Full" (inline tool calls and file diffs with keyword search).
47
+ - 📱 **Zero-Install Mobile Client**: the phone side is simply a web page — scan, open it in a browser, and that is the whole setup. No app to install, no account to create, no third-party server in between; you can add it to the home screen and it opens full-screen from there.
48
+ - 🌐 **Multi-Route Secure Connectivity**: Connect via LAN, Tailscale private network (supporting MagicDNS and HTTPS certificates), or Cloudflare Tunnel (for environments without public IPs). All routes coexist with dedicated QR codes and tokens.
49
+ - 🐬 **Lightweight Anthropomorphic Feedback**: Inter-step narrations are spoken aloud by the whale girl sprite in speech bubbles; execution progress and queued instructions are visualized on an exact scale, filtering out raw reasoning blocks.
50
+ - 💬 **Feishu Long-Connection Remote**: Direct bidirectional communication through the Feishu Open Platform WebSocket long connection without public ports, supporting text dialogue, multiple-choice responses, and the `/会话` switch command.
51
+ - 🗂️ **In-Place Mobile Session Management**: Rename, pin, archive, or fork sessions from the most recent completed turn directly on your phone, with clear indicators for pending approvals and questions.
52
+ - 💻 **Desktop Embedded "Remote Window"**: Adds a "Remote Window" shortcut to the left sidebar of the DSH desktop app: it lists the other computers you have paired, and clicking a row embeds that computer's DSH desktop interface in the main view; click the row again to exit and return to where you were. Cross-machine access is supported; see "Desktop \"Remote Window\"" below for the pairing steps.
53
+ - 🔒 **Rigorous Security Boundaries**: All API routes enforce constant-time token comparison to prevent timing side-channel attacks; built-in rate limiting locks out sources after 5 failed attempts in 1 minute; pairing data is accessible solely from the host loopback interface.
41
54
 
42
55
  ---
43
56
 
44
- ## Install
57
+ ## UI Preview
45
58
 
46
- ```powershell
47
- dsh plugin --profile web add dsh-mini-remote
48
- ```
59
+ ### Conversation Screen (Single Frame / Chat / Full)
49
60
 
50
- **You must restart DSH once after installing** (close the `dsh web` window and start it again), or "Phone Remote" will not appear in the left column. The startup log then prints the phone URL and password.
61
+ The mobile client is built with zero-dependency vanilla JavaScript and supports both high-contrast Dark and Light themes. One conversation has three readings: **Single Frame** keeps only the latest conclusion on screen, **Chat** lays the history out as back-and-forth bubbles, and **Full** puts every turn's execution trail back where it happened:
51
62
 
52
- The `web` in that command is a DSH **profile name** — the folder under `~/.dsh/profiles/`. Most people's default profile is called `web`; if yours isn't, use your own name instead.
63
+ <div align="center">
64
+ <img width="290" alt="Chat (dark): several turns of history laid out as back-and-forth bubbles" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/screen-chat-dark.png" />
65
+ <img width="290" alt="Chat (light): the same conversation in the light theme" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/screen-chat-light.png" />
66
+ </div>
53
67
 
54
- <details>
55
- <summary>Installing from GitHub source, from a local folder, and which DSH versions it fits</summary>
68
+ ### Settings Panel & Appearance
56
69
 
57
- Or straight from GitHub, if you would rather pin the source:
70
+ Switch presentation modes, color themes, or trigger manual reconnects from the settings overlay:
58
71
 
59
- ```powershell
60
- dsh plugin --profile web add github:xingzhen199186/dsh-mini-remote
61
- ```
72
+ <div align="center">
73
+ <img width="290" alt="Settings (dark): three display modes, appearance set to dark" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/settings-dark.png" />
74
+ <img width="290" alt="Settings (light): the selected states and the primary button turn royal blue too" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/settings-light.png" />
75
+ </div>
62
76
 
63
- If you already have the source on disk, you can point it at the folder:
77
+ ### Execution Animation
64
78
 
65
- ```powershell
66
- dsh plugin --profile web add <the folder you put the source in>
67
- ```
79
+ During task execution, the view presents an animated running state, elapsed timer, and queued task scale without unverified progress guesses:
68
80
 
69
- **Which DSH versions it fits.** This plugin was developed on DSH **0.1.5-rc.2** and re-checked item by item on **0.1.7-rc.2**; **0.2.0 itself was built on 0.2.0-rc.1 / 0.2.0-rc.2** (every interface it uses was unchanged, and the full check suite ran on both sides). **Versions below 0.1.5 have not been tried**, and the declared ceiling is **0.3.0**. `rc` is the tag the project puts on preview builds, and DSH as a whole is still a developer preview — minor versions may break things, so versions newer than 0.2.0 are not guaranteed either. If it ever does hit an incompatibility, the usual symptom is one entry point going missing (the model line at the top, say) while everything else keeps working: the plugin is written so that a missing service switches off that one feature rather than the whole thing. The phone-side interface adaptations also come with a dependency manifest and an **upgrade self-check** (`tools/structure-check.mjs`): run it against the live page after an upgrade and it walks every dependency entry by entry.
81
+ <div align="center">
82
+ <img width="290" alt="Running (dark): the whale girl running, 14s elapsed, one instruction on the queue scale" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/running-dark-phone.jpg" />
83
+ <img width="290" alt="Running (light): the same run in the light theme, 14s elapsed, one instruction queued" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/running-light-phone.jpg" />
84
+ </div>
70
85
 
71
- Settings follow the same rule: the settings are declared the standard DSH way, and on the 0.1.5-era library that ability does not exist yet — the plugin **still installs and works exactly as before**, it just loses the "applies immediately" behaviour mentioned below. On the **0.1.7 generation** that ability is fully there.
86
+ ### Remote Window (Desktop)
72
87
 
73
- </details>
88
+ No window switching and no remote desktop: click "Remote Window" in the DSH desktop left sidebar and the other computer's DSH interface is embedded right in the main panel. The bar on top holds "← Back to list / which computer this is / Try again"; while the interface displays normally it auto-hides, sliding out only when the mouse reaches the top edge.
74
89
 
75
- ---
90
+ <div align="center">
91
+ <img width="720" alt="Remote Window: another computer's DSH interface embedded in the main panel, with Remote Window selected in the left sidebar" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/remote-window.png" />
92
+ </div>
76
93
 
77
- ## Connecting your phone: three routes, pick one
94
+ ---
78
95
 
79
- All three connection methods **exist at the same time**. Pick one, or leave several on.
96
+ ## Quick Start
80
97
 
81
- | Route | When to use it | What you install | What it costs |
82
- | --- | --- | --- | --- |
83
- | **LAN** | Phone and computer on the same Wi-Fi — at home only | Nothing at all | It stops the moment you leave the house |
84
- | **Tailscale** | You need it outside, and you want the address to stay fixed | Tailscale on the computer and on the phone | An app on both sides |
85
- | **Public tunnel** | Nothing installed, reachable on any network | Nothing at all | The address changes on every restart; the first run downloads a ~50 MB component |
98
+ ### Prerequisites
86
99
 
87
- There is one more route, and it isn't the phone: **Feishu** (see [Remote control from Feishu](#remote-control-from-feishu)). It never touches the browser, and none of the three routes above need to be on.
100
+ Before installing, make sure this computer meets the following requirements:
88
101
 
89
- Open DSH settings (bottom of the sidebar) → "Phone Remote" in the left column. Every route on that page has a QR code and a link, and the small text under each QR code says **when to use that route**. That's all you need to read.
102
+ - **Node.js**: `^22.19.0 || >=24.0.0`
103
+ - **DSH (DeepSeek Harness)**: `>=0.1.5-rc.2 <0.3.0`
104
+ - **OS**: Windows, macOS, or Linux
90
105
 
91
- The plugin's own settings (default mode, external notifications, port, password and so on) also have a standard declaration, so writing them in DSH's standard configuration works too. If the same item is set in both places, **the standard configuration wins**. One difference worth knowing: **"default mode" and "external notifications" apply immediately, with no plugin restart**; port, bind address, tunnel, password and history length make the plugin restart and the phone reconnect once — those genuinely need to re-bind or rebuild, and the plugin says so instead of pretending they can be changed live.
106
+ > ⚠️ **Notice**: DSH is in active development. This plugin is verified across `0.1.5-rc.2`, `0.1.7-rc.2`, `0.2.0-rc.1`, and `0.2.0-rc.2`. Versions below `0.1.5` are untested, and versions above `0.3.0` risk breaking changes in upstream host interfaces — **`0.3.0` is the upper bound this release declares**. Once DSH moves past it, wait for the plugin to catch up instead of upgrading straight away.
92
107
 
93
- ### 1. LAN: at home only
108
+ ### Installation
94
109
 
95
- When the phone and the computer are on the same Wi-Fi, scan the "LAN" code and you're in. **Nothing extra to install** — the least fuss of the three. The cost is that it stops working the moment you leave: the phone switches to mobile data and this route is gone.
110
+ #### Option 1: Install via DSH Desktop UI (Recommended)
96
111
 
97
- ### 2. Tailscale: works outside, and the address stays fixed
112
+ 1. Click the "Plugins" button on the top navigation bar of DSH to open the plugin manager.
113
+ 2. Click the "Add Plugin" button in the upper-right corner to open the installation dialog.
114
+ 3. Enter the package name `dsh-mini-remote` into the input field (GitHub repository URL `github:xingzhen199186/dsh-mini-remote` or local directory path is also supported). Keep the default registry ("npm official registry").
115
+ 4. Click the "Install" button at the bottom of the dialog.
98
116
 
99
- Install [Tailscale](https://tailscale.com) on both the computer and the phone, sign in to the same account, and this route appears on the pairing page by itself. The address is fixed — set it up once and forget it. The cost is an app on each side; if you don't mind installing it, **this is the steadiest route when you're out**.
117
+ > ⚠️ **Notice**:
118
+ > 1. **Verify trusted source**: Plugins run on your machine with your current user privileges. Plugins from untrusted sources may damage DeepSeek Harness or read and leak sensitive data.
119
+ > 2. **No automatic updates yet**: Installed plugins currently do not support automatic updates. To upgrade to a newer version, uninstall the existing version before installing the new one.
100
120
 
101
- There's a switch on the pairing page that gets you an encrypted address as well (shaped like `https://your-machine.your-tailnet.ts.net/`). It is **the same computer over the same tunnel** as the entry above; the only difference is that the connection is encrypted. It is not a fourth route — the plain `http://` entry keeps working and keeps showing.
121
+ #### Option 2: Install from npm (Command Line)
102
122
 
103
- The first time, you have to confirm it in Tailscale's admin console: it is a tailnet-wide switch, and the plugin cannot click it for you. So the pairing page puts the exact link Tailscale hands out right in front of you — one click and you're there. If this computer isn't signed in to Tailscale yet, it says so and gives you a sign-in link instead.
123
+ Execute the installation command in your terminal. Replace `web` with your custom profile name if you are not using the default profile:
104
124
 
105
- ### 3. Public tunnel: nothing to install
125
+ ```powershell
126
+ dsh plugin --profile web add dsh-mini-remote
127
+ ```
106
128
 
107
- There's a switch at the bottom of the pairing page. Turn it on and Cloudflare hands you a public URL (shaped like `https://random-words.trycloudflare.com/`). The phone can reach it on any network, **with nothing installed**.
129
+ #### Option 3: Install from GitHub
108
130
 
109
- Two costs, worth knowing before you decide:
131
+ ```powershell
132
+ dsh plugin --profile web add github:xingzhen199186/dsh-mini-remote
133
+ ```
110
134
 
111
- - **The address changes every time you restart DSH.** When it does, come back and scan the new code.
112
- - **The first time is slow** — it's downloading a component of about 50 MB, and only that once. While it does, the status line reads "opening…", which is normal, not a hang. Registration occasionally fails; the plugin retries three times on its own.
135
+ #### Option 4: Install from Local Directory
113
136
 
114
- Once it's on, **wait half a minute before scanning.** Cloudflare needs a moment to publish the address. Scanning too early reports that it can't be opened — that's not breakage, it's just too soon.
137
+ ```powershell
138
+ dsh plugin --profile web add C:\path\to\dsh-mini-remote
139
+ ```
115
140
 
116
- ### About that "encrypted address"
141
+ ### Starting the Service
117
142
 
118
- Two of the routes above can hand you an `https://` address, and what encryption covers is **the connection itself**: the address bar shows the https padlock, and what travels the wire is encrypted. That does not depend on which route you pick — both give the same thing.
143
+ 1. Restart the DSH service (close the active `dsh web` window and launch it again).
144
+ 2. Check the console log for the listening port and pairing token:
145
+ ```text
146
+ [dsh-mini-remote] 已启动:http://127.0.0.1:3090/mini?token=xxxxxxxxxxxx
147
+ ```
148
+ 3. Open the DSH desktop UI, navigate to "Settings" → "Phone Remote" in the left sidebar, and view the pairing QR codes and links.
119
149
 
120
- The difference is who can resolve the name. The Tailscale one uses a name shaped like `your-machine.your-tailnet.ts.net`, and **that name only resolves inside your Tailscale network**, via MagicDNS on the phone's client. **But some clients don't have that capability** — MeshArc, the third-party client for HarmonyOS, states in its own README that you should use Tailscale IP addresses instead; on such a phone this encrypted route simply won't work, and it isn't a matter of a setting being switched off. The tunnel route uses a Cloudflare name that resolves for anyone and doesn't care about the phone; its cost is that the address changes on every restart.
150
+ > **The phone side is browser-only.** Scanning and opening it in a browser is the entire client — there is no standalone app and no mini-program. You can add the page to your home screen: the resulting icon opens full-screen and looks much like an app, but it is still the browser running the page. Switch phones or clear browser data, and you are back to scanning the code again.
151
+ >
152
+ > Conversely, this page **is not picky about the device either**: open the same address in a PC browser and it works just as well — and from there you can open the complete DSH desktop interface. See "Advanced Settings: Embedded Desktop Interface".
121
153
 
122
154
  ---
123
155
 
124
- ## What the phone can do
125
-
126
- Open the link and that's the whole interface: one input box, and the latest reply.
127
-
128
- **Send instructions.** Type and send; the AI starts working on the computer.
129
-
130
- **Wait for the conclusion.** While it runs, the page shows "running…". You can keep sending during that time — instructions queue up. When the task ends, the conclusion appears on the page, and the phone chimes and buzzes.
131
-
132
- **She speaks up while she works.** On the computer, the model often mutters a line between steps ("let me look at this file first"). That line is now spoken by the whale girl through her speech bubble — the talking pose is a newly drawn sprite, the rotation pauses for it, and afterwards picks up from where it stopped. It stays **in the bubble** and never bleeds into the answer area below. Only the line it deliberately writes *for a human reader* is spoken; its own working thoughts — often English, often a whole paragraph — never reach the phone at all. Should that one narration line itself be in English, it is shown as-is, untranslated (translating would mean putting words in its mouth).
133
-
134
- **Two appearances, switchable anytime.** Settings has an "Appearance" row: **Dark**, **Light** (the default), and **Follow system**. Dark is deep-sea navy; the light palette is taken from the promo artwork — near-white ice blue for the ground, deep royal blue for the text, and the same royal blue on primary buttons. Your choice is stored on the phone, so it is still there next time you open the page.
135
-
136
- <img width="290" alt="Settings (dark): display mode and appearance" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/settings-dark.png" /> <img width="290" alt="Settings (light): the selected states and the primary button turn royal blue too" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/settings-light.png" />
137
-
138
- **The screen while a task is running.** She is mid-stride, the progress bar is moving, and the queue lists what goes next once this round ends. No tool calls and no file diffs on this screen — only the fact that something is running.
139
-
140
- <img width="290" alt="Running (dark, photographed on a phone): the whale girl running, 15s elapsed" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/running-dark-phone.jpg" /> <img width="290" alt="Running (light, photographed on a phone): the whale girl running, 7m43s elapsed, one instruction queued" src="https://raw.githubusercontent.com/xingzhen199186/dsh-mini-remote/main/docs/running-light-phone.jpg" />
141
-
142
- **Three display modes.** Tap the ⚙ in the top right to switch. "Single frame" (the default) keeps only the newest reply on screen — good for "I just want to see how this one turned out". "Chat" is a back-and-forth bubble list — good for several rounds of follow-up questions. "Full" takes that same list and **puts each step's process back in its original place** (the same shape the desktop app uses), with layers you can open one by one to see what that step read — and it is searchable. Use it for a while and you'll know which you prefer.
156
+ ## Usage & Configuration
143
157
 
144
- **Open a session and you see what was said in it before.** Switch to a session that has existed for a while and Chat mode lists every earlier round (the instructions you sent, the conclusion of each round); Single frame shows only the last conclusion. **Very large sessions show only the most recent stretch**: reading one of those in full — tens of thousands of events — would drag the DSH process on your computer down, so the plugin reads just the tail and says so at the top ("this is not everything, only the most recent stretch"). That line is not boilerplate; it is the truth.
158
+ ### Connection Route Matrix
145
159
 
146
- **Slash commands work from the phone too.** Type a `/` in the input box and the commands available in this session appear above it; keep typing to filter by name, tap one to run it, and commands that take arguments get filled in for you along with a note on what they expect. The list is DSH's own on your computer (whatever plugins are installed), and a command's result gets its own row in the chat, visually distinct from what the AI said. A mistyped or unknown command is refused with an explanation — it is **not** sent as a message. When the session is not running there are no commands to list, and the page says so. **Commands cannot carry attachments** in this version: files you have attached stay put and go out with your next ordinary message.
160
+ Select the route that matches your current networking environment:
147
161
 
148
- **Answer questions from the phone.** When the AI asks you to pick something (choose one of several plans, say), the question is pushed to the phone and a tap answers it — **one at a time, revisable if you change your mind, and you can type your own answer** when none of the options fit. If nobody is at the phone (locked, page closed, network gone), the question goes straight back to the computer and the dialog pops up there as usual.
162
+ | Route | Scenario | Prerequisites | Trade-offs |
163
+ | :--- | :--- | :--- | :--- |
164
+ | **LAN** | Phone and computer on the same Wi-Fi subnet | None | Ready immediately; disconnects upon leaving Wi-Fi |
165
+ | **Tailscale** | Stable remote access across locations | Tailscale installed and logged in on both devices | Fixed private IP; optional HTTPS certificate support |
166
+ | **Public Tunnel** | No public IP and no third-party client installation | Enable Cloudflare Tunnel in settings | Temporary URL rotates on each DSH restart; initial setup downloads ~50 MB binary |
167
+ | **Feishu Long Connection** | Direct enterprise IM messaging without browser | Feishu custom bot credentials configured | No inbound ports required; bidirectional mobile approvals |
149
168
 
150
- **Three things you can change in passing.** Tap the line at the top to switch the current session's model and reasoning effort; switch the permission preset (View Only / Workspace Write / Full Access); browse the computer's folders to register a new workspace and start a session in it.
169
+ ### Mobile Interface Guide
151
170
 
152
- **By default you're reading conclusions, not the process.** In Single frame and Chat there is no tool-call chain and no file diff; the one exception is the line the whale girl says out loud — it goes into her bubble, never into the answer area (see above). To read the process you switch to "Full" yourself. **System-level confirmation dialogs cannot be answered from the phone** (approving a dangerous command, for instance) — those still need the computer. What the phone can answer is the multiple-choice question the AI puts to you; the two are not the same thing. It's a remote control: the TV still has to be on for the remote to be any use.
171
+ - **Sending & Queuing**: Enter instructions in the bottom input box. When an agent is busy, subsequent messages queue up sequentially and appear on the scale.
172
+ - **Slash Commands**: Type `/` to bring up available session commands with parameter guidance and search filtering.
173
+ - **Interactive Questions**: When the agent requests clarification or user choice, an interactive card pops up for one-tap answers or custom replies.
174
+ - **Back to Bottom**: When scrolling through long message histories, a floating "Back to bottom" button appears in the lower-right corner (disabled in Single frame mode).
175
+ - **Permission Switching**: Tap the top status bar to cycle between View Only (`read-only`), Workspace Write (`workspace-write`), and Full Access (`danger-full-access`).
153
176
 
154
- **The whole desktop interface can be brought over too ("Advanced settings").** Settings has an **off-by-default** "Advanced settings" entry: turn it on and a "Desktop interface" row appears below it; tap "Open" and the computer's full DSH page is embedded right there on the phone — no jump, no new tab — so model configuration, plugin install and removal, session records and anything else the remote page doesn't have can be done from here. **It is the exact opposite of the positioning above** (switch it on and the whole process is on screen), which is why it starts off: turning it on spells the consequence out (the password's reach extends to the entire desktop settings surface) and takes two taps to confirm. When the plugin cannot learn the desktop address, the entry does not appear at all.
177
+ > ⚠️ **Notice**:
178
+ > 1. Elevating permissions to "Full Access" permits the agent to run arbitrary system commands and modify files across the machine. Proceed with caution.
179
+ > 2. System-level confirmation dialogs for dangerous commands belong to the DSH on your computer itself — the phone cannot approve them, so you will need to handle those on the computer.
155
180
 
156
- ---
157
-
158
- ## Remote control from Feishu
159
-
160
- **Talk to the session on your computer from inside Feishu.** You send a line, the session runs a round, and the answer comes back under your message — with one more line underneath saying which session it came from (`会话:deploy script`, and `未命名会话` when the session has no name yet). Those two labels are Chinese and stay as they are.
181
+ ### Advanced Settings: Embedded Desktop Interface (Phone or PC Browser)
161
182
 
162
- It runs over Feishu's **long connection**: the plugin dials out to Feishu and keeps the line open, so there is no public address and no domain to arrange. It shares one session binding with the phone page.
183
+ **The remote page is not phone-only.** Open the same address (the one the QR code points at) in a PC browser and it works just the same — the layout is simply tuned for a phone screen. What makes this route genuinely useful on a PC is "Advanced settings": it embeds the complete DSH desktop interface, so you do not have to spin up a separate `dsh web`.
163
184
 
164
- ### Setup
185
+ How to open it:
165
186
 
166
- Create an app in the [Feishu open platform](https://open.feishu.cn/) — the "custom app" type, which is also what you would use for yourself alone. Copy the App ID and App Secret from Credentials & Basic Info. **Then add a Bot capability and publish a version** — skip that step and the bot will not show up in Feishu search. Set the event subscription mode to "receive events over a long connection", and add the event `im.message.receive_v1`. Under permissions, search for just `im.message` (typing the rest of the name returns nothing) and tick three: receive messages, send messages as the app, get and send single-chat and group messages — **the count going from 0 to 3 is your proof you got it**. Any change to the capability, the permissions or the events needs another published version. Then back in DSH settings, fill the App ID and App Secret into "Phone Remote" → "Feishu" and turn the switch on.
187
+ 1. Click the gear in the top-right corner, find the "Advanced settings" row (its hint reads "Open the DSH interface on the computer and change the settings the phone does not have"), and switch it to on.
188
+ 2. It asks once more — **you must confirm a second time**.
189
+ 3. A "Desktop interface" row appears right below (hint: "the complete desktop DSH page"). Click "Open".
190
+ 4. A full-screen copy of the DSH desktop interface is embedded right in this page: plugin management, model configuration, session history, and full logs. The bar on top exits back to the remote page.
167
191
 
168
- Every menu and the sign of a successful publish are in the "配置指引(飞书后台六步)" guide inside that settings block. It is **collapsed by default**. The paragraph above only tells you how many things there are to do; it does not repeat the guide.
192
+ **It moves this computer's own interface over — it does not start a second one.** Whatever you change or send here happens **on this DSH**; the desktop app and this view share one state. Nor is it "spinning up another web instance": the plugin's server authenticates once through the official door, then **proxies every request** to the local interface in real time (even live UI refreshes are forwarded as they come, never buffered). The phone never touches any official credential.
169
193
 
170
- ### The first message is refused, and that's expected
194
+ > ⚠️ **Notice**:
195
+ > 1. **This is a permission switch, not an ordinary preference.** Turning it on extends the token's reach from "what the phone page exposes" to the **entire desktop management plane** — model configuration, credentials, plugin install/uninstall, session history. It is therefore off by default and takes two confirmations to enable.
196
+ > 2. What gets embedded is the desktop interface as-is — on a narrow phone screen it adapts to its mobile layout; in a PC browser you get the original.
171
197
 
172
- Both allow-lists start empty, and **with both empty nobody is recognised**. So your first message to the bot does nothing. The plugin **answers you inside Feishu** instead: it hands you your own id (`open_id`, the internal number Feishu knows you by) and tells you which field it goes in. Paste it into "允许的 open_id", save, and send again — that one works.
198
+ ### Desktop "Remote Window"
173
199
 
174
- Only **direct messages** are handled (you and the bot, one to one). Group messages are not read in this version.
200
+ **In one sentence**: open computer A's DSH interface directly inside computer B's DSH desktop window.
175
201
 
176
- ### What you can do from Feishu
202
+ **What it replaces**: when both machines run their own DSH, looking at the other one used to take one of two detours — an extra browser window (so you keep switching between two sets of windows), or full remote desktop (the entire screen comes over, with all the resolution and shortcut friction). This entry turns "that machine" into one panel: click and it is there, click again and you are back where you were.
177
203
 
178
- **Plain text is you talking to the current session** — the same as sending it from the phone.
204
+ #### What it looks like in use
179
205
 
180
- **When the session stops to ask you something, an ordinary text message arrives in Feishu.** A multiple-choice question lists its options as `1.` `2.`; an approval spells out which tool and which command it wants to run. Reply with a number, or with 「同意」 (agree) or 「拒绝」 (refuse) — `y`, `yes` and `ok` count as agree, `n` and `no` as refuse. Reply 「取消」 to decline to decide: the question goes back to the computer. That word has to be 「取消」; the English "cancel" is not read.
206
+ 1. Click "Remote Window" in the left sidebar; the main view lists the computers you have paired — one row each, with name, address, and when it last connected.
207
+ 2. Click a row and that computer's interface is embedded in the panel.
208
+ 3. Click the sidebar row again (icon, label, or any blank part of the row) to leave and return to the panel you were on.
181
209
 
182
- **`/会话` lists the sessions you can switch to**, marking the current one 「(当前)」. **`/会话 3`** switches to the third, and the phone page follows — the two sides share one binding. Anything starting with `/` is treated as a command and never as an answer to a pending question. It is the only command here, and it is Chinese; send those characters as they are.
210
+ While the interface displays normally, the bar at the top **auto-hides** — move the mouse to the top edge and it slides out. The bar carries "← Back to list", which computer this is, and "Try again": that is the only way out (and the way to retry) when something goes wrong, so in the connecting, failed, and never-loaded states **it stays visible and never hides**.
183
211
 
184
- **Not there yet.** Cards with buttons; images and files; group chats; streaming — the answer arrives in one piece, after a wait; one round at a time.
212
+ #### What was done for security
185
213
 
186
- ---
214
+ - **The pass never changes hands**: opening a window makes the server sign a one-time ticket (valid for 30 seconds, redeemable once). The browser receives that ticket only — **your access pass and long-lived credentials never enter the browser**, so they cannot end up in browsing history or inside the embedded page.
215
+ - **Only a page carrying a valid ticket may embed**: cross-site embedding is denied by default and allowed only for that one ticket-bearing load. An outside page that learns the address still cannot get in.
216
+ - **Revocation is immediate**: once you revoke device B on A, B's already-open window fails on its next request — no waiting for it to disconnect on its own.
217
+ - **It dies with DSH**: restarting DSH invalidates that screen's pass; click once more to reopen.
187
218
 
188
- ## FAQ
219
+ #### Cross-Machine Setup (Two Computers)
189
220
 
190
- **The QR code scans but the page won't open.**
191
- First check that the phone and the computer are on the same Wi-Fi.
221
+ Below, **A** is the computer being connected to, and **B** is the one connecting to it.
192
222
 
193
- **Scanning the "public" route from outside won't open.**
194
- Wait half a minute and try again. If it still won't, the pairing page shows the reason directly. The most common one is **a proxy or VPN running on the computer** — the "TUN mode" in tools like Clash cuts the tunnel's connections; the process looks fine while not a single connection has actually been established. Turn it off and try again. Another possibility: that network simply can't reach Cloudflare (it's intermittent in mainland China, and not something you misconfigured). If so, don't burn time on the public route — **switch to the Tailscale route**.
223
+ **On A**
195
224
 
196
- **It says "disconnected".**
197
- This happens often after the phone has been in the background. The page reconnects by itself; give it a few seconds. If that doesn't work, open settings and tap "Reconnect".
225
+ 1. **Install this plugin, version `0.2.1` or newer.** "Remote Window" first shipped in `0.2.1` — B connects to the code running on A, so if A is on an older version, B sees the old interface.
226
+ 2. Open "Settings → Phone Remote → Allow other computers to connect" and switch it on. It is off by default; while it is off, A does not accept pairing requests at all.
227
+ 3. In the "Password" section of the same settings page, click "Copy" to get A's pass.
198
228
 
199
- **The reply arrives but there's no sound.**
200
- Audio only plays after you've touched the page once. Tap it.
229
+ **On B** (in B's "Settings → Phone Remote")
201
230
 
202
- **The phone keeps asking for a password.**
203
- That means the link you opened didn't carry one — for example, you typed the address by hand. Go back to the computer and scan the QR code again.
231
+ The section you need is "Other computers", near the bottom of the settings page. It is the mirror image of the "Devices" section above — that one lists who can get in, this one lists whom you can reach.
204
232
 
205
- **I want a password I can remember.**
206
- Change it in the password section of "Settings → Phone Remote". **At least 12 characters.** A DSH restart is required afterwards, and the phone has to scan a new code.
233
+ 1. Click "Add a computer" to unfold three fields.
234
+ 2. **That computer's address (the one on its "Phone Remote" page, no `/mini`)** — enter A's address. This is the field that matters most; see "Which address to enter" below.
235
+ 3. **That computer's pass (copy it from its "Phone Remote" settings)** — paste what you copied in step 3 on A. This field is masked.
236
+ 4. **Give it a name (optional; the address is used if you leave it blank)** — so you can tell it apart in the list.
237
+ 5. Click "Confirm add". This really does pair with A once — afterwards A's settings page gains a "this computer" entry and B gains a row.
238
+ 6. Click that row in the list.
207
239
 
208
- ---
240
+ Each row shows the name, the address, `last ok <time>` (or "no record yet"), and two buttons on the right: **"Reconnect"** fetches a fresh pass, **"Disconnect"** removes the pairing. Disconnecting asks once and states that the entry on the far computer **stays** — to revoke it fully, remove this device on A.
209
241
 
210
- ## Security
242
+ **Which address to enter**
211
243
 
212
- **The pairing page carries the password — don't screenshot it and send it around.** The password is encoded straight into the QR code so you never have to type it. That's convenient, and the price is that whoever holds that image can get in.
244
+ - Enter the address shown on A's "Phone Remote" page (no trailing `/mini` needed) — **not** the one you use to open the DSH interface on A itself.
245
+ - **It must be `https://`.** A plain `http://` address can pair and can obtain the pass, but the frame stays blank — the browser drops that pass on a non-HTTPS address.
246
+ - Tailscale is recommended: switch on "HTTPS address (Tailscale)" on A, then enter `https://<machine>.<your-tailnet>.ts.net` on B — **no port needed**. The address is stable, so you set it once.
247
+ - The "Public access" tunnel address changes on every restart, so it is not suitable for cross-machine use.
213
248
 
214
- Beyond that: every endpoint requires the password; password comparison is constant-time; five wrong attempts from one source blocks that source for a minute; pairing information is **readable only from the local machine**, so other devices on the same Wi-Fi can't get it; the public tunnel is off by default and you have to turn it on yourself in the settings page; the phone sees no file contents — when you pick a workspace it lists folder names only, and never lists or reads files. **The one exception is images**: when something the AI wants to show you includes a picture (an interface screenshot, say), that image is placed under the plugin's `lib/art/` directory with a name starting with `out-`, and the page fetches it over the same password-protected image route the sprites use. Only that one class of file — an image, with that prefix — can be fetched; message bodies, configuration files and everything else stay unreadable, and directories still cannot be listed. **One thing worth stating plainly: the phone can switch the agent's permission preset.** On Full Access, the agent can then modify any file on this computer. That path is open.
249
+ **How to tell it worked**
215
250
 
216
- ---
251
+ Click the row in the list and that computer's interface appears in the frame. When something fails, an explanation appears under that row — the far side has not switched it on, the pairing was revoked, it is unreachable, or the address is wrong; each has its own message.
217
252
 
218
- ## Why I built this plugin
253
+ **Revoking a computer later**
219
254
 
220
- The idea came from this: an agent task often takes a long time to finish, and if you step out, you need the phone to drive it remotely.
255
+ On A, open "Settings → Phone Remote → Devices" — the list of who can get in, each row carrying "Rename" and "Revoke". Find that computer, click "Revoke", then "Confirm revoke". **It takes effect immediately**: a window the far side already has open fails on its next request; no need to wait for it to disconnect.
221
256
 
222
- But the phone clients that exist show the PC's execution steps in faithful detail. You send one instruction; it may think for several minutes, read dozens of files, call tools a few times, and only then give you a conclusion. If you're out, or busy away from the computer, you simply don't have the time to watch the phone that closely.
257
+ ### Feishu Bot Setup Guide
223
258
 
224
- I don't think that approach is bad. It's complete and controllable, and if you're going to do serious work, it's the right one.
259
+ 1. Log in to the [Feishu Open Platform](https://open.feishu.cn/) and create a custom enterprise application.
260
+ 2. Record the `App ID` and `App Secret` under Credentials & Basic Info.
261
+ 3. Navigate to "Add Capabilities" and add the "Bot" capability.
262
+ 4. Navigate to "Events & Callbacks", set the subscription mode to "Receive events over a long connection", and subscribe to `im.message.receive_v1`.
263
+ 5. Under "Permissions", grant the following 3 scopes:
264
+ - Receive messages (`im:message:receive_v1`)
265
+ - Send messages as bot (`im:message:send_as_bot`)
266
+ - Read and send single/group chat messages (`im:message.group_at_msg:readonly` suite)
267
+ 6. Create and **publish an application version**.
268
+ 7. Return to DSH desktop "Settings" → "Phone Remote" → "Feishu", paste the credentials, and turn the toggle on. The first time you message the bot, it replies with your `open_id`. Add this ID to the allow-list to finish onboarding.
225
269
 
226
- But when I'm out, what I want is something else — **a lighter way to interact that asks less of my attention**. The phone screen is small, and so is the attention I have to spare when I'm out. Most of the time I only need one thing: **this round is done, time to send the next instruction.** And even at my desk, I rarely read the AI's running commentary while it works.
270
+ ### Configuration Parameters
227
271
 
228
- So the interface here is deliberately crude: it drops the PC's execution steps entirely and puts only the AI's final conclusion in front of you.
272
+ Settings can be managed either via the desktop "Phone Remote" panel or declared directly in the standard DSH profile:
229
273
 
230
- **In a sense, it exists so that you look at it less.**
231
-
232
- So you can spend your time more freely — instead of being stuck in that small screen while you're playing with your daughter or out on a trip.
274
+ | Parameter | Type | Default | Lifecycle | Description |
275
+ | :--- | :--- | :--- | :--- | :--- |
276
+ | `port` | `number` | `3090` | Restart required | Local HTTP port for the remote service (auto-increments on conflict) |
277
+ | `token` | `string` | *(generated)* | Restart required | Access token (must be at least 12 characters if customized) |
278
+ | `defaultMode` | `string` | `"minimal"` | Immediate | Default view mode on mobile: `"minimal"`, `"chat"`, `"full"` |
279
+ | `externalNotify` | `boolean` | `true` | Immediate | Play chimes and vibrate on task completion |
280
+ | `tunnel.enabled` | `boolean` | `false` | Restart required | Enable Cloudflare temporary public tunnel |
281
+ | `tailscale.serve` | `boolean` | `false` | Restart required | Enable Tailscale HTTPS certificate listener |
282
+ | `feishu.enabled` | `boolean` | `false` | Immediate | Enable Feishu WebSocket long connection |
233
283
 
234
284
  ---
235
285
 
236
- ## For maintainers
286
+ ## License
237
287
 
238
- After upgrading DSH, run `node tools/structure-check.mjs` once. It reports entry by entry: which ones still hold, which have drifted, and whether a drifted one actually needs attention. When anything has drifted the exit code is 1, so the check can be wired into a pipeline later.
288
+ This project is licensed under the [MIT License](LICENSE).
239
289
 
240
- ---
290
+ ### Documentation & Reference Links
241
291
 
242
- ## Credits
292
+ - [Sprites and Animation Guide](docs/character.md) (Chinese): Image tool pipelines, shared prompt templates, dimensions, and acceptance criteria.
293
+ - [Sprite Reference Frames (Frozen 2026-09-28)](docs/art-refs/2026-09-28/) (Chinese): Reference frames and prompt baselines.
294
+ - [Changelog](CHANGELOG.md): Historical evolution and bug fix records.
295
+ - [Repository](https://github.com/xingzhen199186/dsh-mini-remote): Official GitHub home.
243
296
 
244
- This plugin's design draws on [dsh-pocket](https://www.npmjs.com/package/dsh-pocket) by shaobeichen — in particular the shape of the configuration page, where each connection route gets its own link, its own QR code, and its own password.
245
-
246
- ## License
297
+ ### Credits
247
298
 
248
- MIT
299
+ Special thanks to [dsh-pocket](https://www.npmjs.com/package/dsh-pocket) by @shaobeichen for inspiring the multi-path independent QR pairing layout.