@goodandready/dsh-remote-workspace 0.3.2 → 0.3.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/docs/design/DESIGN.md +15 -1
- package/lib/client.js +36 -7
- package/lib/updater-service.js +3 -2
- package/package.json +4 -2
package/docs/design/DESIGN.md
CHANGED
|
@@ -7,7 +7,7 @@ emote_fs,
|
|
|
7
7
|
emote_sync,
|
|
8
8
|
emote_tunnel).
|
|
9
9
|
- **Аудитория**: Разработчики и инженеры, использующие DSH для работы с проектами на VPS, удаленных серверах, облачных инстансах и MiniPC.
|
|
10
|
-
- **Статус**: Стабильный релиз v0.3.
|
|
10
|
+
- **Статус**: Стабильный релиз v0.3.3 (One-Click Updater, Cross-Plugin API, Clean Tokens, Modular Routes).
|
|
11
11
|
|
|
12
12
|
## User Surfaces
|
|
13
13
|
- **Web/UI**: Нативная карточка настроек профилей хостов (settings.plugin.item), удаленный SFTP браузер каталогов, чип статуса подключения в шапке сессии (conversation.session.header.utilities).
|
|
@@ -69,3 +69,17 @@ emote_tunnel: создание/остановка/листинг туннеле
|
|
|
69
69
|
- Защита всех мутирующих эндпоинтов проверкой isTrustedSettingsRequest(req) (защита от cross-site атак).
|
|
70
70
|
- Безопасное чтение Cordis сервисов через .get() с fallback.
|
|
71
71
|
- Изоляция жизненного цикла стримов в TunnelService (прослушивание сокетных и потоковых ошибок).
|
|
72
|
+
|
|
73
|
+
### v0.3.3 Client Architecture Modularization (Refs: #14)
|
|
74
|
+
- Client-side code decomposed into modular ES components under `src/client/`:
|
|
75
|
+
- `src/client/styles.js` — CSS styling with DSH theme variables
|
|
76
|
+
- `src/client/locales.js` — English and Chinese translation dictionaries
|
|
77
|
+
- `src/client/env-editor.js` — Remote .env manager tab component
|
|
78
|
+
- `src/client/docker.js` — Container inspector tab component
|
|
79
|
+
- `src/client/terminal.js` — Web terminal tab component
|
|
80
|
+
- `src/client/file-browser.js` — Remote file explorer tab component
|
|
81
|
+
- `src/client/settings-view.js` — Profiles, tunnels, and sync settings component
|
|
82
|
+
- `src/client/updater-section.js` — One-click updater section component
|
|
83
|
+
- `src/client/plugin-card.js` — Plugin card and status chip components
|
|
84
|
+
- `src/client/entry.js` — Cordis client plugin apply and slot registration
|
|
85
|
+
- Added native builder `scripts/build-client.mjs` hooked into `prepack` and `npm test`.
|
package/lib/client.js
CHANGED
|
@@ -7,6 +7,9 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
const React = require('react')
|
|
8
8
|
|
|
9
9
|
const NS = 'dsh-remote-workspace'
|
|
10
|
+
// Plugins page row seat (DSH 0.1.6-alpha.2): key = '<package name>#<row id>'.
|
|
11
|
+
const ROW_ID = 'dsh-remote-workspace'
|
|
12
|
+
const ROW_CONFIG_KEY = '@goodandready/dsh-remote-workspace#' + ROW_ID
|
|
10
13
|
|
|
11
14
|
function ensureCss() {
|
|
12
15
|
if (typeof document === 'undefined') return
|
|
@@ -435,6 +438,7 @@ window.__ModuleLoader__.load({
|
|
|
435
438
|
|
|
436
439
|
|
|
437
440
|
// --- Sub-component: Remote Environment Tab (New in v0.3.1) ---
|
|
441
|
+
|
|
438
442
|
function EnvTab(props) {
|
|
439
443
|
const { activeProfile, t } = props
|
|
440
444
|
const [envEntries, setEnvEntries] = React.useState([])
|
|
@@ -538,6 +542,7 @@ window.__ModuleLoader__.load({
|
|
|
538
542
|
}
|
|
539
543
|
|
|
540
544
|
// --- Sub-component: Docker Containers Tab ---
|
|
545
|
+
|
|
541
546
|
function ContainersTab(props) {
|
|
542
547
|
const { activeProfile, t } = props
|
|
543
548
|
const [containers, setContainers] = React.useState([])
|
|
@@ -688,6 +693,7 @@ window.__ModuleLoader__.load({
|
|
|
688
693
|
}
|
|
689
694
|
|
|
690
695
|
// --- Sub-component: Web Terminal Tab ---
|
|
696
|
+
|
|
691
697
|
function TerminalTab(props) {
|
|
692
698
|
const { activeProfile, t } = props
|
|
693
699
|
const [connected, setConnected] = React.useState(false)
|
|
@@ -893,6 +899,7 @@ window.__ModuleLoader__.load({
|
|
|
893
899
|
}
|
|
894
900
|
|
|
895
901
|
// --- Sub-component: Remote File Explorer Tab ---
|
|
902
|
+
|
|
896
903
|
function ExplorerTab(props) {
|
|
897
904
|
const { activeProfile, t } = props
|
|
898
905
|
const [currentPath, setCurrentPath] = React.useState(activeProfile?.remoteWorkspace || '/')
|
|
@@ -2071,6 +2078,7 @@ window.__ModuleLoader__.load({
|
|
|
2071
2078
|
}
|
|
2072
2079
|
|
|
2073
2080
|
// Accordion item for Settings -> Plugins section
|
|
2081
|
+
|
|
2074
2082
|
function UpdaterSection(props) {
|
|
2075
2083
|
const t = props.t || ((k) => k);
|
|
2076
2084
|
const [updateStatus, setUpdateStatus] = React.useState(null);
|
|
@@ -2186,16 +2194,23 @@ window.__ModuleLoader__.load({
|
|
|
2186
2194
|
}
|
|
2187
2195
|
|
|
2188
2196
|
function PluginCard(props) {
|
|
2189
|
-
const
|
|
2197
|
+
const page = !!(props && props.view === 'page')
|
|
2198
|
+
const [open, setOpen] = React.useState(!!page)
|
|
2190
2199
|
const t = props.t || (props.locale === 'zh' ? makeT(zh, en) : makeT(en, zh))
|
|
2191
2200
|
|
|
2192
2201
|
React.useEffect(() => {
|
|
2193
2202
|
ensureCss()
|
|
2194
2203
|
}, [])
|
|
2195
2204
|
|
|
2205
|
+
// Row seat (plugins.row.config): the host page draws title/icon/crumb and the
|
|
2206
|
+
// padding, so the summary is a one-liner and the page drops our card chrome.
|
|
2207
|
+
if (props && props.view === 'summary') {
|
|
2208
|
+
return React.createElement('span', { style: { fontSize: '13px', color: 'var(--dsw-alias-label-secondary)' } }, t('subtitle'))
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2196
2211
|
return React.createElement(
|
|
2197
|
-
'li',
|
|
2198
|
-
{ className: 'drw-card', style: { listStyle: 'none', marginBottom: '12px' } },
|
|
2212
|
+
page ? 'div' : 'li',
|
|
2213
|
+
{ className: page ? 'drw-page' : 'drw-card', style: page ? undefined : { listStyle: 'none', marginBottom: '12px' } },
|
|
2199
2214
|
React.createElement(
|
|
2200
2215
|
'button',
|
|
2201
2216
|
{
|
|
@@ -2204,13 +2219,13 @@ window.__ModuleLoader__.load({
|
|
|
2204
2219
|
background: 'none',
|
|
2205
2220
|
border: 'none',
|
|
2206
2221
|
cursor: 'pointer',
|
|
2207
|
-
display: 'flex',
|
|
2222
|
+
display: page ? 'none' : 'flex',
|
|
2208
2223
|
alignItems: 'center',
|
|
2209
2224
|
width: '100%',
|
|
2210
2225
|
padding: 0,
|
|
2211
2226
|
textAlign: 'left',
|
|
2212
2227
|
},
|
|
2213
|
-
'aria-expanded': open,
|
|
2228
|
+
'aria-expanded': page ? true : open,
|
|
2214
2229
|
onClick: () => setOpen((v) => !v),
|
|
2215
2230
|
},
|
|
2216
2231
|
React.createElement('span', { style: { fontSize: '20px', marginRight: '12px' } }, '🌐'),
|
|
@@ -2227,7 +2242,7 @@ window.__ModuleLoader__.load({
|
|
|
2227
2242
|
React.createElement(FallbackChevron)
|
|
2228
2243
|
)
|
|
2229
2244
|
),
|
|
2230
|
-
open
|
|
2245
|
+
(page || open)
|
|
2231
2246
|
? React.createElement(
|
|
2232
2247
|
'div',
|
|
2233
2248
|
{ style: { marginTop: '16px', borderTop: '1px solid var(--dsw-alias-border-l2)', paddingTop: '16px' } },
|
|
@@ -2285,6 +2300,19 @@ window.__ModuleLoader__.load({
|
|
|
2285
2300
|
}
|
|
2286
2301
|
|
|
2287
2302
|
if (ctx.slots && typeof ctx.slots.inject === 'function') {
|
|
2303
|
+
// Row seat first (the seat the current core renders), legacy seat after it.
|
|
2304
|
+
ctx.slots.inject('plugins.row.config', () =>
|
|
2305
|
+
ctx.slots.register(
|
|
2306
|
+
{
|
|
2307
|
+
name: 'plugins.row.config',
|
|
2308
|
+
key: ROW_CONFIG_KEY,
|
|
2309
|
+
locale: NS,
|
|
2310
|
+
inject: () => ({ ctx })
|
|
2311
|
+
},
|
|
2312
|
+
(props) => React.createElement(PluginCard, Object.assign({}, props, { ctx }))
|
|
2313
|
+
)
|
|
2314
|
+
)
|
|
2315
|
+
|
|
2288
2316
|
ctx.slots.inject('settings.plugin.item', () =>
|
|
2289
2317
|
ctx.slots.register(
|
|
2290
2318
|
{
|
|
@@ -2312,5 +2340,6 @@ window.__ModuleLoader__.load({
|
|
|
2312
2340
|
|
|
2313
2341
|
module.exports = { apply, inject: ['slots', 'locale'] }
|
|
2314
2342
|
return module.exports
|
|
2315
|
-
|
|
2343
|
+
|
|
2344
|
+
},
|
|
2316
2345
|
})
|
package/lib/updater-service.js
CHANGED
|
@@ -276,12 +276,13 @@ function json(response, statusCode, value) {
|
|
|
276
276
|
|
|
277
277
|
export function registerPluginUpdater(ctx, options) {
|
|
278
278
|
let installing = false
|
|
279
|
-
|
|
279
|
+
const webServer = ctx?.get ? (ctx.get('webServer') ?? ctx?.webServer) : ctx?.webServer;
|
|
280
|
+
if (!webServer || typeof webServer.register !== 'function') {
|
|
280
281
|
ctx?.logger?.warn?.('[dsh-remote-workspace] webServer service unavailable, updater skipped')
|
|
281
282
|
return () => {}
|
|
282
283
|
}
|
|
283
284
|
|
|
284
|
-
return
|
|
285
|
+
return webServer.register({
|
|
285
286
|
kind: 'exact',
|
|
286
287
|
path: options.endpoint,
|
|
287
288
|
handler: async (request, response) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-remote-workspace",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Enterprise Remote Workspace Plugin for DeepSeek Harness: SSH2 connection pool, SFTP operations, 3-way conflict-aware mirror sync, port forwarding, and native DSH UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsup",
|
|
24
|
-
"test": "node --test test/*.test.mjs"
|
|
24
|
+
"test": "node scripts/build-client.mjs && node --test test/*.test.mjs test/*.test.js",
|
|
25
|
+
"build:client": "node scripts/build-client.mjs",
|
|
26
|
+
"prepack": "node scripts/build-client.mjs"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"deepseek-harness",
|