@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 +2 -2
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/lib/client.js +55 -17
- package/lib/client.js.map +1 -1
- package/lib/index.js +171 -31
- package/lib/types/client/RemoteEntry.d.ts.map +1 -1
- package/lib/types/client/RemoteEntry.js +11 -1
- package/lib/types/client/RemotePanel.d.ts +5 -1
- package/lib/types/client/RemotePanel.d.ts.map +1 -1
- package/lib/types/client/RemotePanel.js +2 -2
- package/lib/types/client/locales.d.ts +8 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +8 -0
- package/lib/types/client/mobile-adapt.d.ts.map +1 -1
- package/lib/types/client/mobile-adapt.js +7 -12
- package/lib/types/index.d.ts +9 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +54 -27
- package/lib/types/loopback-proxy.d.ts.map +1 -1
- package/lib/types/loopback-proxy.js +16 -0
- package/lib/types/routes.d.ts +26 -2
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +150 -5
- package/package.json +1 -1
- package/src/client/RemoteEntry.tsx +12 -0
- package/src/client/RemotePanel.tsx +37 -2
- package/src/client/locales.ts +8 -0
- package/src/client/mobile-adapt.ts +5 -10
- package/src/index.ts +59 -26
- package/src/loopback-proxy.ts +15 -0
- package/src/routes.ts +141 -7
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:
|
|
6
|
-
README.zh.md:
|
|
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,
|
|
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
|
|
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.
|
|
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.
|
|
1666
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1649
1667
|
className: remote_module_css_default.oneTimeHint,
|
|
1650
|
-
children:
|
|
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.
|
|
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
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
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,
|