@linxin666/dsh-remote-web-ui 0.3.14 → 0.3.15

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/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # node scripts/verify-docs.mjs --write <dir>
5
- README.md: 62dd01494df6877b90725715495c39f115dd1e5a
6
- README.zh.md: 0e1ce635be94a16bfe14bd2ced9a26c8df140e21
5
+ README.md: 8e93c9e36c4c1cb042df29d494419347181142b0
6
+ README.zh.md: fb6955a0be096fe3d04cff2600484409c8b62df9
package/README.md CHANGED
@@ -24,7 +24,7 @@ The official desktop layout already auto-collapses the sidebar below 1024px. On
24
24
  - a **draggable whale button** as the entry to the collapsed sidebar (position persisted; wired to the official `ctx.layout.toggleSidebar()`), hidden while the sidebar is expanded;
25
25
  - **gestures**: left-swipe collapses the sidebar, right-swipe in the conversation opens it; long-pressing a session row opens the same action menu as the desktop ellipsis; tapping a session row or anywhere outside the sidebar collapses it again;
26
26
  - **input behavior for touch**: Enter only inserts a newline (send goes through the send button), programmatic composer focus is suppressed (no spurious keyboards), and official tooltip bubbles are hidden because taps leave them stuck;
27
- - **mobile plugin scope**: while the layer is active, the right-hand details column and the desktop-oriented tool surfaces (SSH terminal, skill explorer, task board, git graph, pet, perf, usage) are hidden - keyed on the L2 semantic roots (`data-dsh-plugin`), so ownership stays with the declaring plugin and class churn cannot resurrect them. These are render suppressions; the client bundles still load. Activation also closes the details panel through the official `ctx.layout.closeDetails()`.
27
+ - **mobile plugin scope**: while the layer is active, the right-hand details column and the desktop-oriented tool surfaces (SSH terminal, skill explorer, task board, git graph, pet, usage) are hidden - keyed on the L2 semantic roots (`data-dsh-plugin`), so ownership stays with the declaring plugin and class churn cannot resurrect them. These are render suppressions; the client bundles still load. Activation also closes the details panel through the official `ctx.layout.closeDetails()`.
28
28
  - a **manual opt-out**: `sessionStorage.dsh-remote-force-desktop = 1` disables the whole layer; landscape, desktop, and wide viewports are never touched.
29
29
 
30
30
  The paired remote desktop also runs in **host mode**: on this harness line the "configuration plane is local" behavior is a client-side branch on `connection.isLoopback`, and the channel boot script installs the transport hook (`__DSH_TRANSPORT__.ownsHost = true`) on non-loopback origins before any boot entry. Settings, credentials, agent presets, and deliverables therefore work on the phone exactly as on the desktop — every call still rides the gated `/remote` channel. Three control planes stay physically local: `/api/pair/*`, `/api/update/*`, and `/api/plugin-manager/*`.
package/README.zh.md CHANGED
@@ -24,7 +24,7 @@
24
24
  - **可拖拽小鲸鱼按钮**作为折叠侧栏的展开入口(位置记忆;接到官方 `ctx.layout.toggleSidebar()`),侧栏展开时隐藏;
25
25
  - **手势**:左滑收起侧栏、会话区右滑展开;长按会话行打开与桌面省略号相同的操作菜单;点会话行或侧栏外任意位置再次收起;
26
26
  - **触控输入行为**:Enter 只换行(发送走发送按钮)、抑制程序化 composer 聚焦(不乱弹键盘)、隐藏官方 tooltip 气泡(触屏上会残留);
27
- - **移动端插件范围**:适配层激活时,右侧详情列与面向桌面的工具界面(SSH 终端、技能中心、任务看板、git graph、宠物、性能引擎、使用统计)一律隐藏——以 L2 语义根(`data-dsh-plugin`)为键,归属由声明方插件负责,官方类名变动也不会复活它们。这些是渲染抑制;客户端 bundle 仍会加载。激活时还会经官方 `ctx.layout.closeDetails()` 真正关闭详情面板。
27
+ - **移动端插件范围**:适配层激活时,右侧详情列与面向桌面的工具界面(SSH 终端、技能中心、任务看板、git graph、宠物、使用统计)一律隐藏——以 L2 语义根(`data-dsh-plugin`)为键,归属由声明方插件负责,官方类名变动也不会复活它们。这些是渲染抑制;客户端 bundle 仍会加载。激活时还会经官方 `ctx.layout.closeDetails()` 真正关闭详情面板。
28
28
  - **手动退出**:`sessionStorage.dsh-remote-force-desktop = 1` 关闭整个适配层;横屏、桌面与宽视口永不触碰。
29
29
 
30
30
  配对远程桌面同时运行在 **host 模式**:在本 harness 线上,「配置面仅限本机」的行为是客户端分支(`connection.isLoopback`),通道 boot 脚本在一切 boot entry 之前对非回环源安装传输钩子(`__DSH_TRANSPORT__.ownsHost = true`)。设置、凭据、Agent 预设与产出物在手机上与桌面完全一致——所有调用仍走门控 `/remote` 通道。三个控制面保持物理本地:`/api/pair/*`、`/api/update/*` 与 `/api/plugin-manager/*`。
package/lib/client.js CHANGED
@@ -1514,7 +1514,7 @@ window.__ModuleLoader__.load({
1514
1514
  * @param props - copy, state, and actions.
1515
1515
  * @returns the panel element tree.
1516
1516
  */
1517
- function RemotePanel({ t, state, copied, onClose, onStop, onRefresh, onCopy, onPickAddress, onPickPublic, onRevoke }) {
1517
+ function RemotePanel({ t, state, copied, copiedToken, onClose, onStop, onRefresh, onCopy, onCopyToken, onPickAddress, onPickPublic, onRevoke }) {
1518
1518
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1519
1519
  className: remote_module_css_default.panel,
1520
1520
  role: "dialog",
@@ -1623,9 +1623,9 @@ window.__ModuleLoader__.load({
1623
1623
  className: remote_module_css_default.hint,
1624
1624
  children: state.public ? t("pair.publicHint") : t("pair.hint")
1625
1625
  }),
1626
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1627
1627
  className: remote_module_css_default.pairLinks,
1628
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1628
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1629
1629
  className: remote_module_css_default.pairLinkRow,
1630
1630
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1631
1631
  className: remote_module_css_default.pairLinkText,
@@ -1643,11 +1643,33 @@ window.__ModuleLoader__.load({
1643
1643
  onClick: () => onCopy(state.url),
1644
1644
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, { size: 14 }), copied ? t("action.copied") : t("action.copyLink")]
1645
1645
  })]
1646
- })
1646
+ }), state.token !== void 0 && state.token !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1647
+ className: remote_module_css_default.pairLinkRow,
1648
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1649
+ className: remote_module_css_default.pairLinkText,
1650
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1651
+ className: remote_module_css_default.pairLinkLabel,
1652
+ children: t("pair.tokenLabel")
1653
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1654
+ className: remote_module_css_default.link,
1655
+ title: state.token,
1656
+ children: state.token
1657
+ })]
1658
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1659
+ type: "button",
1660
+ className: remote_module_css_default.copyLink,
1661
+ onClick: () => onCopyToken ? onCopyToken(state.token) : onCopy(state.token),
1662
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, { size: 14 }), copiedToken ? t("action.copiedToken") : t("action.copyToken")]
1663
+ })]
1664
+ })]
1647
1665
  }),
1648
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1666
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1649
1667
  className: remote_module_css_default.oneTimeHint,
1650
- children: t("pair.oneTimeHint")
1668
+ children: [
1669
+ t("pair.oneTimeHint"),
1670
+ " ",
1671
+ t("pair.dockerHint")
1672
+ ]
1651
1673
  }),
1652
1674
  state.phase === "stopped" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1653
1675
  className: remote_module_css_default.stoppedHint,
@@ -2306,6 +2328,7 @@ window.__ModuleLoader__.load({
2306
2328
  stateRef.current = state;
2307
2329
  }, [state]);
2308
2330
  const [copied, setCopied] = (0, react.useState)(false);
2331
+ const [copiedToken, setCopiedToken] = (0, react.useState)(false);
2309
2332
  const eventSource = (0, react.useRef)(void 0);
2310
2333
  const openSeq = (0, react.useRef)(0);
2311
2334
  const closeEventSource = (0, react.useCallback)(() => {
@@ -2328,6 +2351,7 @@ window.__ModuleLoader__.load({
2328
2351
  return {
2329
2352
  kind: "ready",
2330
2353
  url: result.url,
2354
+ token: result.token,
2331
2355
  expiresAt: result.expiresAt,
2332
2356
  expired: Date.now() > result.expiresAt,
2333
2357
  phase: "waiting",
@@ -2424,6 +2448,15 @@ window.__ModuleLoader__.load({
2424
2448
  }, 1500);
2425
2449
  });
2426
2450
  }, []);
2451
+ const handleCopyToken = (0, react.useCallback)((token) => {
2452
+ copyText(token).then((ok) => {
2453
+ if (!ok) return;
2454
+ setCopiedToken(true);
2455
+ window.setTimeout(() => {
2456
+ setCopiedToken(false);
2457
+ }, 1500);
2458
+ });
2459
+ }, []);
2427
2460
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2428
2461
  className: remote_module_css_default.entryRow,
2429
2462
  "data-rail": wide ? void 0 : "rail",
@@ -2447,10 +2480,12 @@ window.__ModuleLoader__.load({
2447
2480
  t,
2448
2481
  state,
2449
2482
  copied,
2483
+ copiedToken,
2450
2484
  onClose: closePanel,
2451
2485
  onStop: handleStop,
2452
2486
  onRefresh: handleRefresh,
2453
2487
  onCopy: handleCopy,
2488
+ onCopyToken: handleCopyToken,
2454
2489
  onPickAddress: handlePickAddress,
2455
2490
  onPickPublic: handlePickPublic,
2456
2491
  onRevoke: handleRevoke
@@ -3647,6 +3682,8 @@ window.__ModuleLoader__.load({
3647
3682
  "pair.expires": "二维码有效至 {time}",
3648
3683
  "pair.expired": "二维码已过期,请刷新",
3649
3684
  "pair.linkLabel": "配对链接",
3685
+ "pair.tokenLabel": "配对令牌",
3686
+ "pair.dockerHint": "Docker 或反向代理环境下,可直接复制此令牌并在目标设备配对页面输入。",
3650
3687
  "pair.oneTimeHint": "链接含一次性令牌;任一设备配对成功后立即失效,配对下一台设备请刷新二维码。",
3651
3688
  "pair.failed.title": "配对失败",
3652
3689
  "pair.failed.detail": "链接无效或已使用,请回到电脑端刷新二维码后重新扫码。",
@@ -3670,7 +3707,9 @@ window.__ModuleLoader__.load({
3670
3707
  "action.refresh": "刷新二维码",
3671
3708
  "action.copy": "复制链接",
3672
3709
  "action.copyLink": "复制链接",
3710
+ "action.copyToken": "复制令牌",
3673
3711
  "action.copied": "已复制",
3712
+ "action.copiedToken": "已复制令牌",
3674
3713
  "devices.title": "已授权设备",
3675
3714
  "devices.empty": "还没有已配对的设备。扫码或打开链接后会出现在这里。",
3676
3715
  "devices.unknown": "未知设备",
@@ -3808,6 +3847,8 @@ window.__ModuleLoader__.load({
3808
3847
  "pair.expires": "QR code valid until {time}",
3809
3848
  "pair.expired": "QR code expired — refresh it",
3810
3849
  "pair.linkLabel": "Pairing link",
3850
+ "pair.tokenLabel": "Pairing token",
3851
+ "pair.dockerHint": "In Docker or reverse proxy environments, copy this token to pair directly on the target device.",
3811
3852
  "pair.oneTimeHint": "The link carries one single-use token; it dies as soon as any device pairs. Refresh the QR to pair the next device.",
3812
3853
  "pair.failed.title": "Pairing failed",
3813
3854
  "pair.failed.detail": "The link is invalid or was already used. Refresh the QR code on your computer and scan again.",
@@ -3831,7 +3872,9 @@ window.__ModuleLoader__.load({
3831
3872
  "action.refresh": "Refresh QR",
3832
3873
  "action.copy": "Copy link",
3833
3874
  "action.copyLink": "Copy link",
3875
+ "action.copyToken": "Copy token",
3834
3876
  "action.copied": "Copied",
3877
+ "action.copiedToken": "Token copied",
3835
3878
  "devices.title": "Authorized devices",
3836
3879
  "devices.empty": "No paired devices yet. Scan the QR or open the link to add one.",
3837
3880
  "devices.unknown": "Unknown device",
@@ -4410,7 +4453,7 @@ window.__ModuleLoader__.load({
4410
4453
  /** The building package's version, when the bundle carries it. */
4411
4454
  function bakedVersion() {
4412
4455
  try {
4413
- return "0.3.14";
4456
+ return "0.3.15";
4414
4457
  } catch {
4415
4458
  return;
4416
4459
  }
@@ -4569,7 +4612,6 @@ window.__ModuleLoader__.load({
4569
4612
  `body.${ACTIVE_CLASS} [data-dsh-plugin=\"task-board\"],`,
4570
4613
  `body.${ACTIVE_CLASS} [data-dsh-plugin=\"git-graph\"],`,
4571
4614
  `body.${ACTIVE_CLASS} [data-dsh-plugin=\"pet\"],`,
4572
- `body.${ACTIVE_CLASS} [data-dsh-plugin=\"perf\"],`,
4573
4615
  `body.${ACTIVE_CLASS} [data-dsh-plugin=\"usage\"]{display:none !important}`,
4574
4616
  `body.${ACTIVE_CLASS} [class$=\"_overlayLayer\"] [class$=\"_workbench\"]{display:none !important}`,
4575
4617
  "[class$=\"_overlay\"] [class$=\"_panel\"]{flex-direction:column;max-height:calc(100dvh - 32px)}",
@@ -5160,15 +5202,11 @@ window.__ModuleLoader__.load({
5160
5202
  if (active && (this.tagName === "TEXTAREA" || this.tagName === "INPUT") && this.closest("[class$=\"_composerSeat\"]") !== null && Date.now() - lastComposerTap >= 800) return;
5161
5203
  lanOrigFocus.call(this, options);
5162
5204
  };
5163
- let lastComposerTapRegistered = false;
5164
- if (!lastComposerTapRegistered) {
5165
- lastComposerTapRegistered = true;
5166
- document.addEventListener("pointerdown", (e) => {
5167
- if (!active) return;
5168
- const t = e.target;
5169
- if (t instanceof Element && (t.tagName === "TEXTAREA" || t.tagName === "INPUT") && t.closest("[class$=\"_composerSeat\"]") !== null) lastComposerTap = Date.now();
5170
- }, true);
5171
- }
5205
+ document.addEventListener("pointerdown", (e) => {
5206
+ if (!active) return;
5207
+ const t = e.target;
5208
+ if (t instanceof Element && (t.tagName === "TEXTAREA" || t.tagName === "INPUT") && t.closest("[class$=\"_composerSeat\"]") !== null) lastComposerTap = Date.now();
5209
+ }, true);
5172
5210
  w.__dshRemoteAdapt = {
5173
5211
  evaluate,
5174
5212
  toggleSidebar: null,