dsh-remote-plugin 0.4.4

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.md ADDED
@@ -0,0 +1,34 @@
1
+ # dsh-remote-plugin
2
+
3
+ DSH Remote 的 DSH bundle 插件:在 DSH 左侧原生边栏注册入口,点击从右侧滑出管理抽屉;插件**内置网关程序并随 DSH 自动启停**(独立 systemd 单元),抽屉直显令牌、主机 IP 与设备监控,配合 [dsh-Remote](https://github.com/Blank-not-black/dsh-Remote) 的 Android App 实现手机远程操控。
4
+
5
+ ## 安装
6
+
7
+ ```sh
8
+ dsh plugin --profile web add dsh-remote-plugin
9
+ # 或 pin 版本
10
+ dsh plugin --profile web add dsh-remote-plugin@0.4.4
11
+ ```
12
+
13
+ 重启 DSH Web 后 Ctrl+F5,左侧边栏底部出现 App 图标入口。
14
+
15
+ git 源安装(等价):
16
+
17
+ ```sh
18
+ dsh plugin --profile web add "github:Blank-not-black/dsh-Remote#main&path:/packages/plugin"
19
+ ```
20
+
21
+ ## 网关
22
+
23
+ - 默认**自动启动**:DSH 启动或抽屉刷新时,插件会拉起内置 `gateway.cjs`(`0.0.0.0:8787`),独立于 DSH 进程。
24
+ - 开关持久化在 `~/.dsh-remote/gateway.enabled`;抽屉内可停止/启动。
25
+ - 令牌在 `~/.dsh-remote/token`(首次自动生成,重复使用不覆盖),抽屉里显示并可复制。
26
+ - 环境变量 `DSH_REMOTE_AUTOSTART=0` 可关闭自动管理。
27
+
28
+ ## 手机 App
29
+
30
+ 从 [Releases](https://github.com/Blank-not-black/dsh-Remote/releases/latest) 下载 `dsh-remote.apk`,设置服务器 `http://电脑IP:8787` + 抽屉里的令牌即可。
31
+
32
+ ## License
33
+
34
+ MIT
package/client.js ADDED
@@ -0,0 +1,140 @@
1
+ /* dsh-remote 插件 client half
2
+ * 注册进 DSH 原生左侧边栏 footer(与 OpenBiliClaw 上下并列) + 右侧 shell.overlay 抽屉。
3
+ * 抽屉内 iframe 懒加载 /remote/admin/ —— 即本地网关管理控制台的桌面 UI。
4
+ * 产物入库, 无构建步骤; 参考 @openbiliclaw/dsh-plugin 的官方 slot 注册模式。
5
+ */
6
+ window.__ModuleLoader__.load({
7
+ id: 'dsh-remote-plugin',
8
+ factory: (require) => {
9
+ var module = { exports: {} }
10
+ var exports = module.exports
11
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
12
+ var React = require('react')
13
+ var runtime = require('@deepseek-ai/dsh-client-runtime/client')
14
+
15
+ var DRAWER_STYLE = {
16
+ position: 'fixed', top: 0, right: 0, bottom: 0, zIndex: 2147483000,
17
+ width: 'min(460px, 96vw)', background: '#0b0e1a',
18
+ boxShadow: '-10px 0 32px rgba(0,0,0,.5)',
19
+ transform: 'translateX(102%)', transition: 'transform .22s ease',
20
+ display: 'flex', flexDirection: 'column',
21
+ }
22
+ var HEAD_STYLE = {
23
+ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
24
+ gap: 8, padding: '9px 12px', background: '#0f766e', color: '#fff',
25
+ font: '600 13px/1 system-ui, sans-serif', flexShrink: 0,
26
+ }
27
+ // DSH 原生 footerActions 容器默认 flex-row(官方类名已编译定型);
28
+ // 动态注入列布局, 让各 footer action 上下堆叠。
29
+ var FOOTER_FIX_ID = 'dsh-remote-footer-stack'
30
+ var FOOTER_FIX_CSS = '.kIs9zW_footerActions{flex-direction:column!important;align-items:stretch!important}'
31
+
32
+ function useFooterStack() {
33
+ React.useEffect(function () {
34
+ if (document.getElementById(FOOTER_FIX_ID)) return
35
+ var style = document.createElement('style')
36
+ style.id = FOOTER_FIX_ID
37
+ style.textContent = FOOTER_FIX_CSS
38
+ document.head.appendChild(style)
39
+ }, [])
40
+ }
41
+
42
+ function SidebarButton(props) {
43
+ useFooterStack()
44
+ var open = props.useStore(function (s) { return s.open })
45
+ var hoverState = React.useState(false)
46
+ var hover = hoverState[0]
47
+ var setHover = hoverState[1]
48
+ return React.createElement('button', {
49
+ type: 'button',
50
+ title: 'DSH Remote',
51
+ 'aria-haspopup': 'dialog',
52
+ 'aria-expanded': open,
53
+ onClick: function () { props.actions.toggle() },
54
+ onMouseEnter: function () { setHover(true) },
55
+ onMouseLeave: function () { setHover(false) },
56
+ style: {
57
+ display: 'flex', alignItems: 'center', gap: 7, width: '100%',
58
+ padding: '6px 10px', border: 'none', borderRadius: 8,
59
+ background: hover ? 'rgba(125, 207, 255, .14)' : 'transparent',
60
+ transition: 'background .15s ease',
61
+ cursor: 'pointer', color: open ? '#5df2d6' : 'inherit',
62
+ font: '500 13px/1.3 system-ui, sans-serif', textAlign: 'left',
63
+ },
64
+ },
65
+ React.createElement('img', {
66
+ src: '/remote/icon.svg', alt: '', 'aria-hidden': true,
67
+ style: { width: 16, height: 16, flexShrink: 0 },
68
+ }),
69
+ props.wide ? React.createElement('span', null, 'DSH Remote') : null)
70
+ }
71
+
72
+ function Drawer(props) {
73
+ var open = props.useStore(function (s) { return s.open })
74
+ var loaded = React.useRef(false)
75
+ if (open) loaded.current = true
76
+ // 管理页里的「收起面板」通过 postMessage 请求父窗口关闭抽屉
77
+ React.useEffect(function () {
78
+ function onMsg(e) {
79
+ if (e.origin !== location.origin) return
80
+ var d = e.data
81
+ if (d && d.source === 'dsh-remote-admin' && d.type === 'close') props.actions.close()
82
+ }
83
+ window.addEventListener('message', onMsg)
84
+ return function () { window.removeEventListener('message', onMsg) }
85
+ }, [])
86
+ return React.createElement('div', {
87
+ 'aria-hidden': !open,
88
+ style: Object.assign({}, DRAWER_STYLE, { transform: open ? 'translateX(0)' : 'translateX(102%)' }),
89
+ },
90
+ React.createElement('div', { style: HEAD_STYLE },
91
+ React.createElement('span', null, '🖥 DSH Remote'),
92
+ React.createElement('button', {
93
+ type: 'button', 'aria-label': '关闭',
94
+ onClick: function () { props.actions.close() },
95
+ style: { border: 'none', background: 'transparent', color: '#fff', font: '600 16px/1 system-ui, sans-serif', cursor: 'pointer', padding: '2px 6px' },
96
+ }, '✕')),
97
+ loaded.current ? React.createElement('iframe', {
98
+ src: '/remote/admin/?embedded=1',
99
+ title: 'DSH Remote',
100
+ sandbox: 'allow-scripts allow-same-origin allow-forms allow-modals allow-popups',
101
+ style: { flex: 1, width: '100%', border: 'none', background: '#0b0e1a' },
102
+ }) : null)
103
+ }
104
+
105
+ var inject = ['slots']
106
+ function apply(ctx) {
107
+ var store = runtime.defineStore({
108
+ init: function () { return { open: false } },
109
+ actions: {
110
+ toggle: function (d) { d.open = !d.open },
111
+ open: function (d) { d.open = true },
112
+ close: function (d) { d.open = false },
113
+ },
114
+ })
115
+ ctx.effect(function () {
116
+ return ctx.slots.inject('sidebar.footer.action', function () {
117
+ return ctx.slots.register({
118
+ name: 'sidebar.footer.action',
119
+ id: 'dsh-remote',
120
+ order: 1,
121
+ store,
122
+ }, SidebarButton)
123
+ })
124
+ }, 'dsh-remote: sidebar footer entry')
125
+ ctx.effect(function () {
126
+ return ctx.slots.inject('shell.overlay', function () {
127
+ return ctx.slots.register({
128
+ name: 'shell.overlay',
129
+ id: 'dsh-remote-drawer',
130
+ store,
131
+ }, Drawer)
132
+ })
133
+ }, 'dsh-remote: overlay drawer')
134
+ }
135
+
136
+ exports.apply = apply
137
+ exports.inject = inject
138
+ return module.exports
139
+ },
140
+ })
@@ -0,0 +1,4 @@
1
+ # dsh-remote bundle patch: 把插件自身 insert 进 profile 层栈
2
+ - insert:
3
+ - id: dsh-remote
4
+ name: 'dsh-remote-plugin'