@mrrisega/dsh-remote 0.6.0-beta.0 → 0.6.0-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrisega/dsh-remote",
3
- "version": "0.6.0-beta.0",
3
+ "version": "0.6.0-beta.1",
4
4
  "description": "手机远程控制 DeepSeek Harness · Remote control DeepSeek Harness (dsh web) from any phone browser — 100% 全功能 App 级体验:发消息、看工具执行、审批权限、改设置、管凭据,含特权操作,免内网穿透。一条命令安装 npx @mrrisega/dsh-remote。Mobile remote control for DSH, self-host or SaaS, no server needed on LAN.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -146,9 +146,71 @@ window.__ModuleLoader__.load({
146
146
  ".dru-dev-sub{font-size:11px;color:#8c959f;margin-top:3px}",
147
147
  ".dru-dev-tag{font-size:10.5px;color:#8c959f;border:1px solid #d0d7de;border-radius:999px;padding:0 7px;flex:none;white-space:nowrap}",
148
148
  ".dru-dev-tag-off{color:#cf222e;border-color:#ffb3b6;background:#fff0f1}",
149
+ // 左下角「远程访问」快捷小手机图标(安装后常驻;首次点击前带红点)
150
+ ".dru-fab{position:fixed;left:18px;bottom:18px;z-index:2147482100;width:46px;height:46px;border-radius:50%;background:#0969da;color:#fff;border:none;display:flex;align-items:center;justify-content:center;font-size:22px;line-height:1;box-shadow:0 6px 18px rgba(0,0,0,.28);cursor:pointer;font-family:inherit;padding:0}",
151
+ ".dru-fab:hover{background:#0860bd}",
152
+ ".dru-fab-dot{position:absolute;top:2px;right:2px;width:9px;height:9px;border-radius:50%;background:#e5484d;box-shadow:0 0 0 2px #fff;pointer-events:none}",
149
153
  ].join("\n");
150
154
  document.head.appendChild(styleEl);
151
155
 
156
+ // ── 左下角「远程访问」快捷小手机图标 ──
157
+ // 常驻于左下角:点击打开 设置页 → 「远程访问」栏目;首次点击前显示小红点(localStorage 一次)。
158
+ var FAB_SEEN_KEY = "dsh-remote-fab-seen";
159
+ function clickTextNav(text) {
160
+ try {
161
+ var nodes = document.querySelectorAll('button, [role="tab"], [class*="navCell"], [class*="nav"], [class*="sidebar"] a, a');
162
+ for (var i = 0; i < nodes.length; i++) {
163
+ var el = nodes[i];
164
+ var t = (el.textContent || "").trim();
165
+ if (t === text || t.indexOf(text) === 0) {
166
+ try { el.click(); return true; } catch (e) { /* 尝试下一个 */ }
167
+ }
168
+ }
169
+ } catch (e) { /* 忽略 */ }
170
+ return false;
171
+ }
172
+ function openRemoteSettings() {
173
+ if (clickTextNav("远程访问")) return; // 已在栏目内/可直接点到
174
+ if (clickTextNav("设置")) { /* 进入设置页后再轮询远程访问栏目 */ }
175
+ var tries = 0;
176
+ var iv = setInterval(function () {
177
+ if (clickTextNav("远程访问")) { clearInterval(iv); return; }
178
+ if (++tries > 40) clearInterval(iv);
179
+ }, 150);
180
+ if (typeof iv.unref === "function") iv.unref();
181
+ }
182
+ function ensureRemoteFab() {
183
+ try {
184
+ if (document.getElementById("dru-remote-fab")) return;
185
+ if (!document.body) { setTimeout(ensureRemoteFab, 300); return; }
186
+ var fab = document.createElement("button");
187
+ fab.id = "dru-remote-fab";
188
+ fab.className = "dru-fab";
189
+ fab.type = "button";
190
+ fab.setAttribute("aria-label", "远程访问");
191
+ fab.textContent = "📱";
192
+ var seen = false;
193
+ try { seen = !!localStorage.getItem(FAB_SEEN_KEY); } catch (e) {}
194
+ if (!seen) {
195
+ var dot = document.createElement("span");
196
+ dot.className = "dru-fab-dot";
197
+ fab.appendChild(dot);
198
+ }
199
+ fab.addEventListener("click", function () {
200
+ try { localStorage.setItem(FAB_SEEN_KEY, "1"); } catch (e) {}
201
+ var d = fab.querySelector(".dru-fab-dot");
202
+ if (d) d.remove();
203
+ openRemoteSettings();
204
+ });
205
+ document.body.appendChild(fab);
206
+ } catch (e) { /* 非关键 */ }
207
+ }
208
+ if (document.readyState === "loading") {
209
+ document.addEventListener("DOMContentLoaded", ensureRemoteFab);
210
+ } else {
211
+ setTimeout(ensureRemoteFab, 600);
212
+ }
213
+
152
214
  // ── 首次安装引导小红点(设置页「远程访问」栏目,localStorage 控制) ────
153
215
  // 无 dsh-remote-seen-dot key 视为首次:在设置页导航栏目右上角显示 CSS 圆点;
154
216
  // 点击栏目/红点后写入 key(之后不再显示),重启 DSH Web 不复发。
@@ -921,6 +983,11 @@ window.__ModuleLoader__.load({
921
983
  /** 创建(或刷新)一次性访问密钥:GET /dsh-remote/access-key(node 半转发企业端 /api/auth-key)。 */
922
984
  function loadAccessKey() {
923
985
  if (akeyBusy) return;
986
+ // 登录前不请求企业端(避免 401/404 噪音);由账号登录成功后触发
987
+ if (!(st && st.config && st.config.phone)) {
988
+ setAkeyMsg(null);
989
+ return;
990
+ }
924
991
  setAkeyBusy(true);
925
992
  api("/dsh-remote/access-key").then(function (b) {
926
993
  if (!b || !b.ok) {
@@ -1266,8 +1333,12 @@ window.__ModuleLoader__.load({
1266
1333
  var expMs = akey ? toMs(akey.expires_at) : 0;
1267
1334
  var remainMs = expMs ? expMs - nowTick : 0;
1268
1335
  var loggedInSaaS = !!(st && st.config && st.config.phone);
1269
- var statusTxt = st === null ? "查询中…" : serviceRunning ? "已连接(可远程访问)" : "等待设备连接";
1270
- var dotCls = "dru-dot " + (serviceRunning ? "dru-dot-on" : "dru-dot-off");
1336
+ var statusTxt = st === null
1337
+ ? "查询中…"
1338
+ : !loggedInSaaS
1339
+ ? "请先登录(下方账号卡片)后启用远程访问"
1340
+ : serviceRunning ? "已连接(可远程访问)" : "等待设备连接";
1341
+ var dotCls = "dru-dot " + (loggedInSaaS && serviceRunning ? "dru-dot-on" : "dru-dot-off");
1271
1342
  return card("📱 远程访问", [
1272
1343
  h("div", { className: "dru-status-line" },
1273
1344
  h("span", { className: dotCls }),
@@ -1394,7 +1465,8 @@ window.__ModuleLoader__.load({
1394
1465
  // 云端 tab:📱 远程访问(一次性扫码访问 + 已授权设备)+ 账号(手机号登录,官方托管)
1395
1466
  !isLocal ? h("div", null,
1396
1467
  renderAccessCard(),
1397
- renderDevicesCard(),
1468
+ // 已授权设备:仅登录后展示(登录前不显示,避免空列表/误导)
1469
+ loggedIn && st.config.phone ? renderDevicesCard() : null,
1398
1470
  card("🔑 账号",
1399
1471
  st === null
1400
1472
  ? h("div", { className: "dru-hint" }, "正在读取远控状态…")
@@ -946,7 +946,7 @@ const PLUGIN_ID = "dsh-remote-web";
946
946
  const PLUGIN_LEGACY_IDS = ["dsh-remote-ui"];
947
947
  const PLUGIN_ALL_IDS = [PLUGIN_ID, ...PLUGIN_LEGACY_IDS];
948
948
  /** 插件自身发布版本(与 dsh-remote 根包同步递增)。 */
949
- const PLUGIN_VERSION = "0.6.0-beta.0";
949
+ const PLUGIN_VERSION = "0.6.0-beta.1";
950
950
  const UPDATE_LOG = ".dsh-update.log";
951
951
  const UPDATE_MARKER = ".dsh-update-running";
952
952
 
@@ -58,7 +58,7 @@ test("反馈代理:附加设备身份/手机号,透传 thread_token", async
58
58
  assert.equal(echo.url, "/api/feedback");
59
59
  assert.equal(echo.headers["x-dsh-device"], "dev-testproxy123");
60
60
  assert.equal(echo.headers["x-dsh-phone"], "13800000000");
61
- assert.equal(echo.headers["x-dsh-client"], "dsh-remote-web/0.5.0");
61
+ assert.match(echo.headers["x-dsh-client"], /^dsh-remote-web\/\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, `x-dsh-client 应带插件名与版本,实际 ${echo.headers["x-dsh-client"]}`);
62
62
  assert.equal(echo.headers.authorization, "Bearer thread-token-abc");
63
63
  assert.equal(echo.body.category, "bug");
64
64
 
@@ -55,7 +55,7 @@ test("self 路由:版本可见 + 运行环境状态(无 npx 环境时不谎
55
55
  try {
56
56
  const self = await (await fetch(`${base}/dsh-remote/self`)).json();
57
57
  assert.equal(self.ok, true);
58
- assert.match(self.version, /^\d+\.\d+\.\d+$/, `version 应为 semver,实际 ${self.version}`);
58
+ assert.match(self.version, /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/, `version 应为 semver(含预发布),实际 ${self.version}`);
59
59
  assert.equal(self.runtimeReady, false, "temp 目录没有 dsh-setup.mjs → runtimeReady=false");
60
60
  assert.equal(self.relayDir, tempDir);
61
61
  } finally {