@jingyi0605/codingns4dsh 0.1.2 → 0.1.7-rc.3
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.en.md +4 -4
- package/README.md +14 -5
- package/data/build/dist/client/account-bar.js +57 -3
- package/data/build/dist/client/bundle.js +36246 -268
- package/data/build/dist/client/cli-slots.js +60 -18
- package/data/build/dist/client/dsh-h5-bootstrap.d.ts +2 -0
- package/data/build/dist/client/dsh-h5-bootstrap.js +79 -13
- package/data/build/dist/client/features/file-management-panel.d.ts +5 -0
- package/data/build/dist/client/features/file-management-panel.js +48 -0
- package/data/build/dist/client/features/file-management.d.ts +4 -0
- package/data/build/dist/client/features/file-management.js +50 -0
- package/data/build/dist/client/features/index.d.ts +10 -1
- package/data/build/dist/client/features/index.js +12 -1
- package/data/build/dist/client/features/login-protection-panel.js +1 -1
- package/data/build/dist/client/features/login-protection-session.d.ts +2 -0
- package/data/build/dist/client/features/login-protection-session.js +18 -0
- package/data/build/dist/client/features/peer-host.d.ts +4 -0
- package/data/build/dist/client/features/peer-host.js +89 -0
- package/data/build/dist/client/features/reverse-proxy-panel.js +23 -7
- package/data/build/dist/client/features/reverse-proxy.d.ts +1 -2
- package/data/build/dist/client/features/reverse-proxy.js +75 -5
- package/data/build/dist/client/features/types.d.ts +9 -0
- package/data/build/dist/client/features/workspace-session-enhancement-panel.js +10 -0
- package/data/build/dist/client/features/workspace-session-enhancement.js +18 -1
- package/data/build/dist/client/file-management-dom.d.ts +12 -0
- package/data/build/dist/client/file-management-dom.js +527 -0
- package/data/build/dist/client/git-management.js +24 -5
- package/data/build/dist/client/host-navigation.d.ts +29 -0
- package/data/build/dist/client/host-navigation.js +29 -0
- package/data/build/dist/client/host-router.d.ts +3 -0
- package/data/build/dist/client/host-router.js +2 -0
- package/data/build/dist/client/index.d.ts +6 -1
- package/data/build/dist/client/index.js +30 -10
- package/data/build/dist/client/locale.js +36 -7
- package/data/build/dist/client/peer-host-connection-button.d.ts +13 -0
- package/data/build/dist/client/peer-host-connection-button.js +69 -0
- package/data/build/dist/client/peer-host-management-api.d.ts +40 -0
- package/data/build/dist/client/peer-host-management-api.js +33 -0
- package/data/build/dist/client/peer-host-management-panel.d.ts +13 -0
- package/data/build/dist/client/peer-host-management-panel.js +181 -0
- package/data/build/dist/client/peer-host-native-session-ui.d.ts +60 -0
- package/data/build/dist/client/peer-host-native-session-ui.js +372 -0
- package/data/build/dist/client/peer-host-scoped-client.d.ts +67 -0
- package/data/build/dist/client/peer-host-scoped-client.js +316 -0
- package/data/build/dist/client/peer-host-session-controller.d.ts +30 -0
- package/data/build/dist/client/peer-host-session-controller.js +95 -0
- package/data/build/dist/client/quick-phrase-slot.js +14 -0
- package/data/build/dist/client/remote-web-context.js +26 -4
- package/data/build/dist/client/session-changed-files-view.d.ts +15 -0
- package/data/build/dist/client/session-changed-files-view.js +337 -0
- package/data/build/dist/client/settings-bridge.d.ts +14 -4
- package/data/build/dist/client/settings-bridge.js +59 -12
- package/data/build/dist/client/settings-section.js +17 -4
- package/data/build/dist/client/subscription-slot.js +21 -8
- package/data/build/dist/client/workspace-session-rightbar-dom.d.ts +28 -0
- package/data/build/dist/client/workspace-session-rightbar-dom.js +291 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +25 -33
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +7 -1
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +34 -11
- package/data/build/dist/dsh-capabilities/matrix.js +9 -0
- package/data/build/dist/dsh-capabilities/routes.js +35 -0
- package/data/build/dist/dsh-capabilities/settings-store.d.ts +12 -0
- package/data/build/dist/dsh-capabilities/settings-store.js +34 -0
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/features/host-router.d.ts +26 -0
- package/data/build/dist/features/host-router.js +110 -0
- package/data/build/dist/features/registry.js +3 -0
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts +13 -1
- package/data/build/dist/host/cli-adapters/codex-driver.js +528 -72
- package/data/build/dist/host/cli-adapters/command-code-driver.d.ts +21 -2
- package/data/build/dist/host/cli-adapters/command-code-driver.js +408 -105
- package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +47 -28
- package/data/build/dist/host/cli-adapters/dsh-tool-history.js +37 -0
- package/data/build/dist/host/cli-adapters/feature.js +94 -10
- package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +6 -0
- package/data/build/dist/host/cli-adapters/json-rpc-process.js +14 -3
- package/data/build/dist/host/cli-adapters/kimi-driver.js +3 -3
- package/data/build/dist/host/cli-adapters/model-catalog.d.ts +6 -0
- package/data/build/dist/host/cli-adapters/model-catalog.js +8 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.js +14 -2
- package/data/build/dist/host/cli-adapters/pi-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/process-utils.d.ts +8 -0
- package/data/build/dist/host/cli-adapters/process-utils.js +48 -0
- package/data/build/dist/host/cli-adapters/registry.d.ts +6 -1
- package/data/build/dist/host/cli-adapters/registry.js +41 -7
- package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +23 -4
- package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
- package/data/build/dist/host/cli-adapters/standard-stream-driver.js +36 -15
- package/data/build/dist/host/dsh-device-runtime.d.ts +2 -0
- package/data/build/dist/host/dsh-device-runtime.js +55 -29
- package/data/build/dist/host/dsh-runtime-version.d.ts +3 -2
- package/data/build/dist/host/dsh-runtime-version.js +71 -2
- package/data/build/dist/host/features/auth.js +10 -2
- package/data/build/dist/host/features/file-management.d.ts +5 -0
- package/data/build/dist/host/features/file-management.js +267 -0
- package/data/build/dist/host/features/git-management.js +24 -2
- package/data/build/dist/host/features/index.d.ts +2 -0
- package/data/build/dist/host/features/index.js +6 -0
- package/data/build/dist/host/features/peer-host.d.ts +22 -0
- package/data/build/dist/host/features/peer-host.js +322 -0
- package/data/build/dist/host/features/types.d.ts +4 -0
- package/data/build/dist/host/host-router.d.ts +3 -0
- package/data/build/dist/host/host-router.js +2 -0
- package/data/build/dist/host/index-injection.d.ts +17 -0
- package/data/build/dist/host/index-injection.js +24 -0
- package/data/build/dist/host/index.d.ts +4 -1
- package/data/build/dist/host/index.js +41 -7
- package/data/build/dist/host/lan-access-dsh.d.ts +34 -1
- package/data/build/dist/host/lan-access-dsh.js +145 -26
- package/data/build/dist/host/modules/peer-host/host-api-proxy-service.d.ts +52 -0
- package/data/build/dist/host/modules/peer-host/host-api-proxy-service.js +166 -0
- package/data/build/dist/host/modules/peer-host/host-ws-connector.d.ts +31 -0
- package/data/build/dist/host/modules/peer-host/host-ws-connector.js +108 -0
- package/data/build/dist/host/modules/peer-host/host-ws-proxy-service.d.ts +26 -0
- package/data/build/dist/host/modules/peer-host/host-ws-proxy-service.js +159 -0
- package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.d.ts +50 -0
- package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.js +97 -0
- package/data/build/dist/host/modules/peer-host/peer-host-diagnostics.d.ts +19 -0
- package/data/build/dist/host/modules/peer-host/peer-host-diagnostics.js +54 -0
- package/data/build/dist/host/modules/peer-host/peer-host-handshake.d.ts +44 -0
- package/data/build/dist/host/modules/peer-host/peer-host-handshake.js +133 -0
- package/data/build/dist/host/modules/peer-host/peer-host-relay.d.ts +65 -0
- package/data/build/dist/host/modules/peer-host/peer-host-relay.js +196 -0
- package/data/build/dist/host/modules/peer-host/peer-host-session.d.ts +42 -0
- package/data/build/dist/host/modules/peer-host/peer-host-session.js +152 -0
- package/data/build/dist/host/modules/peer-host/peer-host-store.d.ts +92 -0
- package/data/build/dist/host/modules/peer-host/peer-host-store.js +323 -0
- package/data/build/dist/host/modules/peer-host/peer-host-ws-gateway.d.ts +34 -0
- package/data/build/dist/host/modules/peer-host/peer-host-ws-gateway.js +156 -0
- package/data/build/dist/host/native-session-bridge.d.ts +18 -2
- package/data/build/dist/host/native-session-bridge.js +236 -8
- package/data/build/dist/host/remote-web-runtime.js +26 -1
- package/data/build/dist/host/rpc.js +8 -3
- package/data/build/dist/host/session-changes.d.ts +5 -0
- package/data/build/dist/host/session-changes.js +163 -0
- package/data/build/dist/host/settings.js +6 -0
- package/data/build/dist/index.d.ts +1 -1
- package/data/build/dist/index.js +1 -1
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +23 -2
- package/data/build/dist/shared/contracts/config.d.ts +15 -0
- package/data/build/dist/shared/contracts/config.js +10 -0
- package/data/build/dist/shared/contracts/dsh-device.d.ts +2 -0
- package/data/build/dist/shared/contracts/errors.d.ts +14 -0
- package/data/build/dist/shared/contracts/errors.js +15 -0
- package/data/build/dist/shared/contracts/feature.d.ts +2 -0
- package/data/build/dist/shared/contracts/file-management.d.ts +6 -0
- package/data/build/dist/shared/contracts/file-management.js +3 -0
- package/data/build/dist/shared/contracts/peer-host.d.ts +116 -15
- package/data/build/dist/shared/contracts/peer-host.js +19 -0
- package/data/build/dist/shared/contracts/version.d.ts +1 -1
- package/data/build/dist/shared/contracts/version.js +1 -1
- package/data/build/dist/shared/index.d.ts +4 -3
- package/data/build/dist/shared/index.js +2 -2
- package/data/build/dist/transport/debug.d.ts +5 -0
- package/data/build/dist/transport/debug.js +23 -1
- package/data/build/dist/transport/dsh-transport.d.ts +2 -0
- package/data/build/dist/transport/dsh-transport.js +11 -0
- package/data/build/dist/transport/webrtc-client.d.ts +2 -0
- package/data/build/dist/transport/webrtc-client.js +2 -1
- package/data/build/dist/transport/webrtc-host.d.ts +2 -0
- package/data/build/dist/transport/webrtc-host.js +6 -3
- package/data/build/dist/typert.host.d.ts +1 -1
- package/data/build/dist/typert.host.js +2 -1
- package/dsh.bundle.patch +10 -0
- package/package.json +19 -11
- package/profile/README.md +2 -2
- package/profile/package.json +2 -2
- package/profile/version.json +1 -1
- package/version.json +1 -1
|
@@ -7,13 +7,18 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis';
|
|
9
9
|
import './provider-icon-assets.js';
|
|
10
|
+
export { PeerHostSessionController } from './peer-host-session-controller.js';
|
|
10
11
|
export { ensureCryptoRandomUUID } from './lan-access.js';
|
|
11
12
|
export type { CryptoRandomUUIDInstallResult, LanAccessCrypto, LanAccessGlobal, } from './lan-access.js';
|
|
12
|
-
export { CLIENT_FEATURES, settingsModules, startBrowserRelayConnection, gitManagementFeature } from './features/index.js';
|
|
13
|
+
export { CLIENT_FEATURES, settingsModules, startBrowserRelayConnection, gitManagementFeature, fileManagementFeature } from './features/index.js';
|
|
13
14
|
export { chooseDshDevice, createHttpDshH5ControlApi, startDshH5Bootstrap, startDshH5BrowserBootstrap } from './dsh-h5-bootstrap.js';
|
|
14
15
|
export type { DshH5BootstrapOptions, DshH5BootstrapResult, DshH5BrowserBootstrapOptions, DshH5BrowserBootstrapResult, DshH5BrowserControlApi, } from './dsh-h5-bootstrap.js';
|
|
15
16
|
export { RemoteDshWebContext } from './remote-web-context.js';
|
|
16
17
|
export type { RemoteDshWebBoot, RemoteDshWebContextOptions } from './remote-web-context.js';
|
|
18
|
+
export { createPeerHostScopedClient, createPeerHostWebSocketFactory } from './peer-host-scoped-client.js';
|
|
19
|
+
export type { PeerHostClientMessageType, PeerHostEventStreamOptions, PeerHostEventSubscription, PeerHostProxyResponse, PeerHostScopedClient } from './peer-host-scoped-client.js';
|
|
20
|
+
export { startPeerHostNativeNavigation, startPeerHostNativeSession, probePeerHostNativeNavigation, probePeerHostNativeSession, PEER_HOST_NAVIGATION_ATTRIBUTE, PEER_HOST_SESSION_ATTRIBUTE, PEER_HOST_STATUS_ATTRIBUTE, } from './peer-host-native-session-ui.js';
|
|
21
|
+
export type { PeerHostNativeUiState, PeerHostNativeNavigationController, PeerHostNativeSessionController, } from './peer-host-native-session-ui.js';
|
|
17
22
|
export type { CodingNsClientFeatureModule, CodingNsClientServices, CodingNsRpcClient, CodingNsRpcResult, FeaturePanelProps, } from './features/index.js';
|
|
18
23
|
export { CodingNsSettingsSection } from './settings-section.js';
|
|
19
24
|
export { startWorkspaceSessionArchiveDom, WORKSPACE_SESSION_ARCHIVE_ATTRIBUTE, WORKSPACE_SESSION_ARCHIVE_MODAL_ATTRIBUTE, } from './workspace-session-archive-dom.js';
|
|
@@ -6,17 +6,23 @@ import { CLIENT_FEATURES } from './features/index.js';
|
|
|
6
6
|
import { ensureCryptoRandomUUID } from './lan-access.js';
|
|
7
7
|
import { CodingNsSettingsSection } from './settings-section.js';
|
|
8
8
|
import { callCodingNsRpc, createCodingNsSettingsBridge } from './settings-bridge.js';
|
|
9
|
-
import { debugInfo } from '../shared/debug.js';
|
|
9
|
+
import { debugInfo, debugWarn } from '../shared/debug.js';
|
|
10
10
|
import { createConfigFormSettingsStore } from '../dsh-capabilities/client/config-forms-adapter.js';
|
|
11
11
|
import { CodingNsWebTerminals, registerCodingNsTerminalUi } from './terminal/index.js';
|
|
12
12
|
import { startCodingNsAccountBar } from './account-bar.js';
|
|
13
13
|
import { assertInjectedDshVersion } from './dsh-runtime-version.js';
|
|
14
14
|
import { createDshCapabilityRegistry } from '../dsh-capabilities/index.js';
|
|
15
15
|
import { TYPERT_REMOTE } from '../typert.remote-client.js';
|
|
16
|
+
import { createPeerHostScopedClient } from './peer-host-scoped-client.js';
|
|
17
|
+
import { HostRouter } from './host-router.js';
|
|
18
|
+
import { PeerHostSessionController } from './peer-host-session-controller.js';
|
|
19
|
+
export { PeerHostSessionController } from './peer-host-session-controller.js';
|
|
16
20
|
export { ensureCryptoRandomUUID } from './lan-access.js';
|
|
17
|
-
export { CLIENT_FEATURES, settingsModules, startBrowserRelayConnection, gitManagementFeature } from './features/index.js';
|
|
21
|
+
export { CLIENT_FEATURES, settingsModules, startBrowserRelayConnection, gitManagementFeature, fileManagementFeature } from './features/index.js';
|
|
18
22
|
export { chooseDshDevice, createHttpDshH5ControlApi, startDshH5Bootstrap, startDshH5BrowserBootstrap } from './dsh-h5-bootstrap.js';
|
|
19
23
|
export { RemoteDshWebContext } from './remote-web-context.js';
|
|
24
|
+
export { createPeerHostScopedClient, createPeerHostWebSocketFactory } from './peer-host-scoped-client.js';
|
|
25
|
+
export { startPeerHostNativeNavigation, startPeerHostNativeSession, probePeerHostNativeNavigation, probePeerHostNativeSession, PEER_HOST_NAVIGATION_ATTRIBUTE, PEER_HOST_SESSION_ATTRIBUTE, PEER_HOST_STATUS_ATTRIBUTE, } from './peer-host-native-session-ui.js';
|
|
20
26
|
export { CodingNsSettingsSection } from './settings-section.js';
|
|
21
27
|
export { startWorkspaceSessionArchiveDom, WORKSPACE_SESSION_ARCHIVE_ATTRIBUTE, WORKSPACE_SESSION_ARCHIVE_MODAL_ATTRIBUTE, } from './workspace-session-archive-dom.js';
|
|
22
28
|
export { startWorkspaceSessionVisibilityDom, WORKSPACE_SESSION_HIDDEN_ATTRIBUTE, WORKSPACE_SESSION_HIDDEN_MENU_ATTRIBUTE, WORKSPACE_SESSION_HIDDEN_LIST_ATTRIBUTE, } from './workspace-session-visibility-dom.js';
|
|
@@ -68,10 +74,15 @@ export function apply(ctx) {
|
|
|
68
74
|
debugInfo('codingns4dsh: client terminal UI registration begin');
|
|
69
75
|
const disposeTerminalUi = registerCodingNsTerminalUi(settingsCtx, webTerminals, settings);
|
|
70
76
|
debugInfo('codingns4dsh: client terminal UI registration ready');
|
|
77
|
+
const hostRouter = new HostRouter();
|
|
78
|
+
const peerHost = createPeerHostScopedClient(connection.rpc);
|
|
71
79
|
const services = {
|
|
72
80
|
dshVersion,
|
|
73
81
|
settings,
|
|
74
82
|
rpc: connection.rpc,
|
|
83
|
+
peerHost,
|
|
84
|
+
hostRouter,
|
|
85
|
+
peerHostSession: new PeerHostSessionController(hostRouter, peerHost),
|
|
75
86
|
remote: settingsCtx.remote,
|
|
76
87
|
terminalRemote,
|
|
77
88
|
slots: settingsCtx.slots,
|
|
@@ -125,6 +136,7 @@ export function apply(ctx) {
|
|
|
125
136
|
return async () => {
|
|
126
137
|
unsubscribe();
|
|
127
138
|
await registry.reconcile([]);
|
|
139
|
+
await services.hostRouter.clear();
|
|
128
140
|
disposeTerminalUi();
|
|
129
141
|
await disposeAccountBar.dispose();
|
|
130
142
|
await disposeTerminalRemote();
|
|
@@ -172,15 +184,23 @@ function createClientSettingsStore(ctx, rpc) {
|
|
|
172
184
|
}
|
|
173
185
|
const forms = ctx.get('configForms');
|
|
174
186
|
const form = findConfigForm(forms);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
writeUnfenced: async (ops) => callCodingNsRpc(rpc, 'settings/set', { ops }),
|
|
187
|
+
if (form === undefined) {
|
|
188
|
+
// DSH 只向回环页面或声明了 Host 所有权的页面下发持久设置命名空间;局域网和
|
|
189
|
+
// 中继页面会降级为 memory 模式,ConfigForm 因此缺失。设置页不能停在这里:
|
|
190
|
+
// 插件设置本来就由自己的 Host RPC 承载,退回 RPC 边界后这些页面依然可读写,
|
|
191
|
+
// 也不再需要宿主启动页去改页面级 Transport 全局(那会覆盖 Desktop Transport)。
|
|
192
|
+
debugWarn('codingns4dsh: client config form unavailable; falling back to Host settings RPC', {
|
|
193
|
+
hasConfigForms: forms !== undefined,
|
|
183
194
|
});
|
|
195
|
+
return createCodingNsSettingsBridge(undefined, rpc);
|
|
196
|
+
}
|
|
197
|
+
debugInfo('codingns4dsh: client settings source=configForms', { hasConfigForms: forms !== undefined, hasForm: true });
|
|
198
|
+
return createConfigFormSettingsStore({ get: () => form }, CODINGNS_SETTINGS_NAMESPACE, {
|
|
199
|
+
// DSH 0.1.7 的 ConfigForm 会把 Host 后台索引更新也纳入 revision。
|
|
200
|
+
// Codingns4DSH 的路径操作是原子的,交给 Host RPC 无条件合并,避免
|
|
201
|
+
// 模块开关因为 cliSessions 的后台心跳而永久冲突。
|
|
202
|
+
writeUnfenced: async (ops) => callCodingNsRpc(rpc, 'settings/set', { ops }),
|
|
203
|
+
});
|
|
184
204
|
}
|
|
185
205
|
function findConfigForm(forms) {
|
|
186
206
|
if (forms === undefined)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSyncExternalStore } from 'react';
|
|
1
|
+
import { useMemo, useSyncExternalStore } from 'react';
|
|
2
2
|
/** Codingns4DSH 自有词典命名空间。词典缺少的语言由 DSH 自动回退到英文。 */
|
|
3
3
|
export const CODINGNS_LOCALE_NS = 'codingns';
|
|
4
4
|
const en = {
|
|
@@ -23,9 +23,18 @@ const en = {
|
|
|
23
23
|
'feature.cliAdapters.label': 'External Agent integration',
|
|
24
24
|
'feature.cliAdapters.description': 'View installed external Agents, versions, command paths, available models, and enable them independently.',
|
|
25
25
|
'feature.workspaceSession.label': 'Workspace session enhancement',
|
|
26
|
-
'feature.workspaceSession.description': 'Show Agent logos, archived-session entries, workspace hiding controls, subscription or usage information,
|
|
26
|
+
'feature.workspaceSession.description': 'Show Agent logos, archived-session entries, workspace hiding controls, subscription or usage information, local quick sessions, and an optional remembered conversation/right-sidebar width ratio.',
|
|
27
27
|
'feature.terminal.label': 'Terminal enhancements',
|
|
28
28
|
'feature.terminal.description': 'Configure the default shell and terminal appearance. Enabling or disabling requires a DSH restart.',
|
|
29
|
+
'feature.fileManagement.label': 'File management enhancements',
|
|
30
|
+
'feature.fileManagement.description': 'Add file and folder operation menus to the DSH file sidebar and edit common text files in place.',
|
|
31
|
+
'fileManagement.menuEnhancement': 'File and folder operation menu',
|
|
32
|
+
'fileManagement.menuEnhancementDescription': 'Show the right-click operation menu for files and folders in the DSH sidebar.',
|
|
33
|
+
'fileManagement.fileEditor': 'File viewer editor',
|
|
34
|
+
'fileManagement.fileEditorDescription': 'Show the icon button for editing supported text files with syntax highlighting and line numbers.',
|
|
35
|
+
'fileManagement.sessionChangedFiles': 'Show current session changed files',
|
|
36
|
+
'fileManagement.sessionChangedFilesDescription': 'Show the files changed in the current session and their Git Diff.',
|
|
37
|
+
'fileManagement.saved': 'File management settings saved.',
|
|
29
38
|
'terminal.title': 'Terminal',
|
|
30
39
|
'terminal.new': 'New terminal',
|
|
31
40
|
'terminal.description': 'Run commands in the session workspace',
|
|
@@ -202,6 +211,8 @@ const en = {
|
|
|
202
211
|
'workspace.subscriptionUsageDescription': 'Detect and display provider subscription balances and upstream usage in the conversation footer.',
|
|
203
212
|
'workspace.showQuickPhrases': 'Show quick sessions',
|
|
204
213
|
'workspace.quickPhrasesDescription': 'Keep reusable session instructions locally in Codingns4DSH and show the quick sessions button inside the composer.',
|
|
214
|
+
'workspace.rememberConversationRightbarRatio': 'Remember conversation and right sidebar width ratio',
|
|
215
|
+
'workspace.rememberConversationRightbarRatioDescription': 'Restore the right sidebar proportion after refreshing this browser; the ratio is stored locally.',
|
|
205
216
|
'workspace.quickPhrasesTitle': 'Quick sessions',
|
|
206
217
|
'workspace.quickPhrasesHint': 'Click an item in the composer to fill the current draft.',
|
|
207
218
|
'workspace.quickPhrasesEmpty': 'No quick sessions yet.',
|
|
@@ -241,9 +252,18 @@ const zh = {
|
|
|
241
252
|
'feature.cliAdapters.label': '外部Agent集成',
|
|
242
253
|
'feature.cliAdapters.description': '查看外部 Agent 的安装状态、版本、命令路径和可用模型,并单独启用或停用。',
|
|
243
254
|
'feature.workspaceSession.label': '工作区会话增强',
|
|
244
|
-
'feature.workspaceSession.description': '在原生工作区会话行显示 Agent Logo
|
|
255
|
+
'feature.workspaceSession.description': '在原生工作区会话行显示 Agent Logo、归档会话入口、工作区隐藏功能和订阅/用量信息,提供本地快捷会话,并可记忆对话窗口与右侧栏宽度比例。',
|
|
245
256
|
'feature.terminal.label': '终端增强',
|
|
246
257
|
'feature.terminal.description': '配置持久终端的默认 shell 与插件终端外观。启用和禁用均需重启 DSH。',
|
|
258
|
+
'feature.fileManagement.label': '文件管理增强',
|
|
259
|
+
'feature.fileManagement.description': '为 DSH 文件侧栏增加文件和文件夹操作菜单,并支持直接编辑常用文本文件。',
|
|
260
|
+
'fileManagement.menuEnhancement': '文件管理菜单增强',
|
|
261
|
+
'fileManagement.menuEnhancementDescription': '在 DSH 文件侧栏为文件和目录显示右键操作菜单。',
|
|
262
|
+
'fileManagement.fileEditor': '文件查看器编辑功能',
|
|
263
|
+
'fileManagement.fileEditorDescription': '为支持的文本文件显示编辑图标按钮,并保留语法高亮和行号。',
|
|
264
|
+
'fileManagement.sessionChangedFiles': '显示当前会话修改的文件',
|
|
265
|
+
'fileManagement.sessionChangedFilesDescription': '在当前会话顶部显示已修改文件,并支持查看 Git Diff 和暂存。',
|
|
266
|
+
'fileManagement.saved': '文件管理设置已保存。',
|
|
247
267
|
'terminal.title': '终端',
|
|
248
268
|
'terminal.new': '新建终端',
|
|
249
269
|
'terminal.description': '在会话工作区运行命令',
|
|
@@ -346,7 +366,7 @@ const zh = {
|
|
|
346
366
|
'relay.dshVersion': 'DSH 版本:{value}',
|
|
347
367
|
'relay.computerName': '计算机名:{value}',
|
|
348
368
|
'relay.host': 'Host:{value}',
|
|
349
|
-
'relay.devicesSummary': '当前设备 {current}
|
|
369
|
+
'relay.devicesSummary': '当前设备 {current},活动设备 {count} 台',
|
|
350
370
|
'relay.deviceStatus': '设备状态:{value}',
|
|
351
371
|
'relay.dshDevices': 'Codingns4DSH 设备',
|
|
352
372
|
'relay.selectDevice': '选择 DSH Host',
|
|
@@ -420,6 +440,8 @@ const zh = {
|
|
|
420
440
|
'workspace.subscriptionUsageDescription': '在对话底部检测并显示 Agent 订阅余额和上游用量。',
|
|
421
441
|
'workspace.showQuickPhrases': '显示快捷会话',
|
|
422
442
|
'workspace.quickPhrasesDescription': '在 Codingns4DSH 内本地保存可复用的会话指令,并将快捷会话按钮显示在输入工具区。',
|
|
443
|
+
'workspace.rememberConversationRightbarRatio': '记忆对话窗口与右侧栏的宽度比例',
|
|
444
|
+
'workspace.rememberConversationRightbarRatioDescription': '刷新后恢复右侧栏比例;比例仅保存在当前浏览器中。',
|
|
423
445
|
'workspace.quickPhrasesTitle': '快捷会话',
|
|
424
446
|
'workspace.quickPhrasesHint': '点击条目即可填入当前对话框。',
|
|
425
447
|
'workspace.quickPhrasesEmpty': '还没有快捷会话。',
|
|
@@ -443,11 +465,18 @@ export function registerCodingNsLocale(ctx) {
|
|
|
443
465
|
}
|
|
444
466
|
/** 订阅 DSH 语言修订,并返回当前 Codingns4DSH 命名空间翻译函数。 */
|
|
445
467
|
export function useCodingNsTranslator(locale) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
468
|
+
// useSyncExternalStore 要求 subscribe/getSnapshot 保持稳定引用:内联闭包会让
|
|
469
|
+
// React 在每次渲染后追加一次一致性检查,并在引用变化时强制重新渲染。
|
|
470
|
+
const store = useMemo(() => localeSnapshotHandle(locale), [locale]);
|
|
471
|
+
useSyncExternalStore(store.subscribe, store.getRevision, store.getRevision);
|
|
449
472
|
return locale.bind(CODINGNS_LOCALE_NS);
|
|
450
473
|
}
|
|
474
|
+
function localeSnapshotHandle(locale) {
|
|
475
|
+
return {
|
|
476
|
+
subscribe: (listener) => locale.subscribe(listener),
|
|
477
|
+
getRevision: () => locale.getSnapshot().revision,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
451
480
|
/** 非 React 注册回调使用的翻译函数。 */
|
|
452
481
|
export function codingNsTranslator(locale) {
|
|
453
482
|
return locale.bind(CODINGNS_LOCALE_NS);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const PEER_HOST_BUTTON_ATTRIBUTE = "data-codingns-peer-host-button";
|
|
2
|
+
export declare const PEER_HOST_OPEN_EVENT = "codingns4dsh:peer-host-open";
|
|
3
|
+
export interface PeerHostConnectionButtonController {
|
|
4
|
+
dispose(): void;
|
|
5
|
+
}
|
|
6
|
+
export interface PeerHostConnectionButtonOptions {
|
|
7
|
+
readonly document?: Document;
|
|
8
|
+
readonly onOpen?: () => void;
|
|
9
|
+
}
|
|
10
|
+
/** 在现有账户入口旁提供 PeerHost 管理按钮;模块停用时完整移除 DOM。 */
|
|
11
|
+
export declare function startPeerHostConnectionButton(options?: PeerHostConnectionButtonOptions): PeerHostConnectionButtonController;
|
|
12
|
+
export declare function createPeerHostButton(dom: Pick<Document, 'createElement'>): HTMLButtonElement;
|
|
13
|
+
//# sourceMappingURL=peer-host-connection-button.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export const PEER_HOST_BUTTON_ATTRIBUTE = 'data-codingns-peer-host-button';
|
|
2
|
+
export const PEER_HOST_OPEN_EVENT = 'codingns4dsh:peer-host-open';
|
|
3
|
+
/** 在现有账户入口旁提供 PeerHost 管理按钮;模块停用时完整移除 DOM。 */
|
|
4
|
+
export function startPeerHostConnectionButton(options = {}) {
|
|
5
|
+
const dom = options.document ?? (typeof document === 'undefined' ? undefined : document);
|
|
6
|
+
if (dom === undefined)
|
|
7
|
+
return { dispose() { } };
|
|
8
|
+
let disposed = false;
|
|
9
|
+
let observer;
|
|
10
|
+
const scan = () => {
|
|
11
|
+
if (disposed)
|
|
12
|
+
return;
|
|
13
|
+
const settings = dom.querySelector('button[aria-label="设置"]');
|
|
14
|
+
const account = dom.querySelector('button[data-codingns-account-button]');
|
|
15
|
+
const anchor = account ?? settings;
|
|
16
|
+
const parent = anchor?.parentElement;
|
|
17
|
+
if (parent === null || parent === undefined)
|
|
18
|
+
return;
|
|
19
|
+
let button = parent.querySelector(`button[${PEER_HOST_BUTTON_ATTRIBUTE}]`);
|
|
20
|
+
if (button === null) {
|
|
21
|
+
button = createPeerHostButton(dom);
|
|
22
|
+
button.addEventListener('click', (event) => {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
event.stopPropagation();
|
|
25
|
+
options.onOpen?.();
|
|
26
|
+
dom.defaultView?.dispatchEvent(new Event(PEER_HOST_OPEN_EVENT));
|
|
27
|
+
});
|
|
28
|
+
parent.insertBefore(button, anchor?.nextSibling ?? null);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
observer = typeof MutationObserver === 'undefined' ? undefined : new MutationObserver(scan);
|
|
32
|
+
observer?.observe(dom.documentElement, { childList: true, subtree: true });
|
|
33
|
+
scan();
|
|
34
|
+
return {
|
|
35
|
+
dispose() {
|
|
36
|
+
if (disposed)
|
|
37
|
+
return;
|
|
38
|
+
disposed = true;
|
|
39
|
+
observer?.disconnect();
|
|
40
|
+
dom.querySelectorAll(`button[${PEER_HOST_BUTTON_ATTRIBUTE}]`).forEach((node) => node.remove());
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function createPeerHostButton(dom) {
|
|
45
|
+
const button = dom.createElement('button');
|
|
46
|
+
button.type = 'button';
|
|
47
|
+
button.setAttribute(PEER_HOST_BUTTON_ATTRIBUTE, '');
|
|
48
|
+
button.setAttribute('aria-label', '管理其他 DSH Host');
|
|
49
|
+
button.title = '管理其他 DSH Host';
|
|
50
|
+
button.textContent = 'Host';
|
|
51
|
+
Object.assign(button.style, {
|
|
52
|
+
minWidth: '30px',
|
|
53
|
+
height: '30px',
|
|
54
|
+
padding: '0 6px',
|
|
55
|
+
border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.16))',
|
|
56
|
+
borderRadius: '6px',
|
|
57
|
+
background: 'var(--dsw-alias-button-elevated-fill, #545557)',
|
|
58
|
+
color: 'var(--dsw-alias-label-primary, #fff)',
|
|
59
|
+
cursor: 'pointer',
|
|
60
|
+
boxSizing: 'border-box',
|
|
61
|
+
display: 'inline-flex',
|
|
62
|
+
alignItems: 'center',
|
|
63
|
+
justifyContent: 'center',
|
|
64
|
+
fontSize: '11px',
|
|
65
|
+
fontWeight: '600',
|
|
66
|
+
});
|
|
67
|
+
return button;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=peer-host-connection-button.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AggregateHostResult, PeerHostClientRecord, PeerHostDiagnosticSnapshot, PeerHostRoute, PeerHostWebSocketEndpoint } from '../shared/contracts/peer-host.js';
|
|
2
|
+
import type { CodingNsRpcClient } from './features/types.js';
|
|
3
|
+
export interface PeerHostCreateRequest {
|
|
4
|
+
readonly displayName: string;
|
|
5
|
+
readonly route: PeerHostRoute;
|
|
6
|
+
}
|
|
7
|
+
export interface PeerHostUpdateRequest {
|
|
8
|
+
readonly peerHostId: string;
|
|
9
|
+
readonly displayName?: string;
|
|
10
|
+
readonly route?: PeerHostRoute;
|
|
11
|
+
}
|
|
12
|
+
export interface PeerHostLoginRequest {
|
|
13
|
+
readonly peerHostId: string;
|
|
14
|
+
readonly username: string;
|
|
15
|
+
readonly password: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PeerHostManagementApi {
|
|
18
|
+
list(): Promise<readonly PeerHostClientRecord[]>;
|
|
19
|
+
create(input: PeerHostCreateRequest): Promise<PeerHostClientRecord>;
|
|
20
|
+
update(input: PeerHostUpdateRequest): Promise<PeerHostClientRecord>;
|
|
21
|
+
remove(peerHostId: string): Promise<void>;
|
|
22
|
+
check(peerHostId: string): Promise<PeerHostClientRecord>;
|
|
23
|
+
reconnect(peerHostId: string): Promise<PeerHostClientRecord>;
|
|
24
|
+
login(input: PeerHostLoginRequest): Promise<{
|
|
25
|
+
readonly peerHostId: string;
|
|
26
|
+
readonly status: string;
|
|
27
|
+
readonly expiresAt: number | null;
|
|
28
|
+
}>;
|
|
29
|
+
logout(peerHostId: string): Promise<{
|
|
30
|
+
readonly peerHostId: string;
|
|
31
|
+
readonly status: string;
|
|
32
|
+
readonly expiresAt: number | null;
|
|
33
|
+
}>;
|
|
34
|
+
webSocketEndpoint(): Promise<PeerHostWebSocketEndpoint | null>;
|
|
35
|
+
aggregate(): Promise<readonly AggregateHostResult[]>;
|
|
36
|
+
diagnostics(): Promise<readonly PeerHostDiagnosticSnapshot[]>;
|
|
37
|
+
}
|
|
38
|
+
/** PeerHost 管理 RPC 封装;客户端不接受目标凭据字段。 */
|
|
39
|
+
export declare function createPeerHostManagementApi(rpc: CodingNsRpcClient): PeerHostManagementApi;
|
|
40
|
+
//# sourceMappingURL=peer-host-management-api.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CODINGNS_RPC_CHANNEL } from '../shared/contracts/transport.js';
|
|
2
|
+
/** PeerHost 管理 RPC 封装;客户端不接受目标凭据字段。 */
|
|
3
|
+
export function createPeerHostManagementApi(rpc) {
|
|
4
|
+
const call = async (endpoint, payload) => {
|
|
5
|
+
let result;
|
|
6
|
+
try {
|
|
7
|
+
result = await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11
|
+
if (!/HTTP (?:404|405)\b/u.test(message))
|
|
12
|
+
throw error;
|
|
13
|
+
result = await rpc.call('/api', `codingns/${endpoint}`, payload);
|
|
14
|
+
}
|
|
15
|
+
if (!result.ok)
|
|
16
|
+
throw new Error(result.error.message);
|
|
17
|
+
return result.value;
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
list: () => call('peerHost/list', {}),
|
|
21
|
+
create: (input) => call('peerHost/create', input),
|
|
22
|
+
update: (input) => call('peerHost/update', input),
|
|
23
|
+
remove: (peerHostId) => call('peerHost/remove', { peerHostId }).then(() => undefined),
|
|
24
|
+
check: (peerHostId) => call('peerHost/check', { peerHostId }),
|
|
25
|
+
reconnect: (peerHostId) => call('peerHost/reconnect', { peerHostId }),
|
|
26
|
+
login: (input) => call('peerHost/login', input),
|
|
27
|
+
logout: (peerHostId) => call('peerHost/logout', { peerHostId }),
|
|
28
|
+
webSocketEndpoint: () => call('peerHost/wsEndpoint', {}),
|
|
29
|
+
aggregate: () => call('peerHost/aggregate', {}),
|
|
30
|
+
diagnostics: () => call('peerHost/diagnostics', {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=peer-host-management-api.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CodingNsRpcClient } from './features/types.js';
|
|
2
|
+
import { type PeerHostManagementApi } from './peer-host-management-api.js';
|
|
3
|
+
export interface PeerHostManagementPanelController {
|
|
4
|
+
dispose(): void;
|
|
5
|
+
}
|
|
6
|
+
export interface PeerHostManagementPanelOptions {
|
|
7
|
+
readonly document?: Document;
|
|
8
|
+
readonly rpc: CodingNsRpcClient;
|
|
9
|
+
readonly api?: PeerHostManagementApi;
|
|
10
|
+
}
|
|
11
|
+
/** PeerHost 管理面板;只渲染脱敏记录和稳定状态。 */
|
|
12
|
+
export declare function startPeerHostManagementPanel(options: PeerHostManagementPanelOptions): PeerHostManagementPanelController;
|
|
13
|
+
//# sourceMappingURL=peer-host-management-panel.d.ts.map
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { PEER_HOST_OPEN_EVENT } from './peer-host-connection-button.js';
|
|
2
|
+
import { createPeerHostManagementApi } from './peer-host-management-api.js';
|
|
3
|
+
/** PeerHost 管理面板;只渲染脱敏记录和稳定状态。 */
|
|
4
|
+
export function startPeerHostManagementPanel(options) {
|
|
5
|
+
const dom = options.document ?? (typeof document === 'undefined' ? undefined : document);
|
|
6
|
+
if (dom === undefined)
|
|
7
|
+
return { dispose() { } };
|
|
8
|
+
const api = options.api ?? createPeerHostManagementApi(options.rpc);
|
|
9
|
+
let disposed = false;
|
|
10
|
+
let overlay = null;
|
|
11
|
+
const open = () => {
|
|
12
|
+
if (disposed)
|
|
13
|
+
return;
|
|
14
|
+
if (overlay === null)
|
|
15
|
+
overlay = createOverlay(dom, api, () => { overlay = null; });
|
|
16
|
+
void refreshList(overlay, api);
|
|
17
|
+
};
|
|
18
|
+
dom.defaultView?.addEventListener(PEER_HOST_OPEN_EVENT, open);
|
|
19
|
+
return {
|
|
20
|
+
dispose() {
|
|
21
|
+
if (disposed)
|
|
22
|
+
return;
|
|
23
|
+
disposed = true;
|
|
24
|
+
dom.defaultView?.removeEventListener(PEER_HOST_OPEN_EVENT, open);
|
|
25
|
+
overlay?.remove();
|
|
26
|
+
overlay = null;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createOverlay(dom, api, onClose) {
|
|
31
|
+
const overlay = dom.createElement('div');
|
|
32
|
+
overlay.setAttribute('data-codingns-peer-host-panel', '');
|
|
33
|
+
overlay.setAttribute('role', 'dialog');
|
|
34
|
+
overlay.setAttribute('aria-label', '管理其他 DSH Host');
|
|
35
|
+
Object.assign(overlay.style, { position: 'fixed', right: '16px', bottom: '56px', zIndex: '9999', width: 'min(520px, calc(100vw - 32px))', maxHeight: 'min(720px, calc(100vh - 80px))', overflow: 'auto', padding: '16px', border: '1px solid var(--dsw-alias-border-l2, #555)', borderRadius: '8px', background: 'var(--dsw-alias-bg-primary, #202124)', color: 'var(--dsw-alias-label-primary, #fff)', boxShadow: '0 12px 32px rgba(0,0,0,.28)' });
|
|
36
|
+
const header = dom.createElement('header');
|
|
37
|
+
const title = dom.createElement('strong');
|
|
38
|
+
title.textContent = '管理其他 DSH Host';
|
|
39
|
+
const close = dom.createElement('button');
|
|
40
|
+
close.type = 'button';
|
|
41
|
+
close.textContent = '关闭';
|
|
42
|
+
close.addEventListener('click', () => { overlay.remove(); onClose(); });
|
|
43
|
+
Object.assign(close.style, { float: 'right' });
|
|
44
|
+
header.append(title, close);
|
|
45
|
+
const message = dom.createElement('div');
|
|
46
|
+
message.setAttribute('role', 'status');
|
|
47
|
+
message.setAttribute('data-codingns-peer-host-message', '');
|
|
48
|
+
const list = dom.createElement('div');
|
|
49
|
+
list.setAttribute('data-codingns-peer-host-list', '');
|
|
50
|
+
const form = createAddForm(dom, api, list, message);
|
|
51
|
+
overlay.append(header, message, form, list);
|
|
52
|
+
dom.body.append(overlay);
|
|
53
|
+
return overlay;
|
|
54
|
+
}
|
|
55
|
+
function createAddForm(dom, api, list, message) {
|
|
56
|
+
const form = dom.createElement('form');
|
|
57
|
+
const name = input(dom, '名称', 'text');
|
|
58
|
+
const routeKind = dom.createElement('select');
|
|
59
|
+
routeKind.required = true;
|
|
60
|
+
for (const option of [['lan', '局域网'], ['relay', '中转']]) {
|
|
61
|
+
const item = dom.createElement('option');
|
|
62
|
+
item.value = option[0];
|
|
63
|
+
item.textContent = option[1];
|
|
64
|
+
routeKind.append(item);
|
|
65
|
+
}
|
|
66
|
+
const routeKindLabel = dom.createElement('label');
|
|
67
|
+
routeKindLabel.textContent = '路由类型';
|
|
68
|
+
routeKindLabel.append(routeKind);
|
|
69
|
+
const url = input(dom, '局域网地址', 'url');
|
|
70
|
+
const deviceId = input(dom, '中转设备标识', 'text');
|
|
71
|
+
const relayEntryId = input(dom, '中转绑定标识', 'text');
|
|
72
|
+
const transportVersion = input(dom, '中转协议版本', 'text');
|
|
73
|
+
const routeFields = dom.createElement('div');
|
|
74
|
+
routeFields.append(url.wrapper, deviceId.wrapper, relayEntryId.wrapper, transportVersion.wrapper);
|
|
75
|
+
const updateRouteFields = () => {
|
|
76
|
+
const relay = routeKind.value === 'relay';
|
|
77
|
+
url.wrapper.hidden = relay;
|
|
78
|
+
deviceId.wrapper.hidden = !relay;
|
|
79
|
+
relayEntryId.wrapper.hidden = !relay;
|
|
80
|
+
transportVersion.wrapper.hidden = !relay;
|
|
81
|
+
url.input.required = !relay;
|
|
82
|
+
deviceId.input.required = relay;
|
|
83
|
+
relayEntryId.input.required = relay;
|
|
84
|
+
transportVersion.input.required = relay;
|
|
85
|
+
};
|
|
86
|
+
routeKind.addEventListener('change', updateRouteFields);
|
|
87
|
+
updateRouteFields();
|
|
88
|
+
const submit = dom.createElement('button');
|
|
89
|
+
submit.type = 'submit';
|
|
90
|
+
submit.textContent = '添加';
|
|
91
|
+
form.append(name.wrapper, routeKindLabel, routeFields, submit);
|
|
92
|
+
form.addEventListener('submit', (event) => {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
const route = routeKind.value === 'relay'
|
|
95
|
+
? { kind: 'relay', deviceId: deviceId.input.value.trim(), relayEntryId: relayEntryId.input.value.trim(), transportVersion: transportVersion.input.value.trim() }
|
|
96
|
+
: { kind: 'lan', baseUrl: url.input.value.trim(), normalizedOrigin: '' };
|
|
97
|
+
void api.create({ displayName: name.input.value.trim(), route }).then(() => refreshList(list.parentElement, api)).then(() => { message.textContent = '已添加 PeerHost'; }).catch((error) => { message.textContent = error instanceof Error ? error.message : String(error); });
|
|
98
|
+
});
|
|
99
|
+
return form;
|
|
100
|
+
}
|
|
101
|
+
async function refreshList(overlay, api) {
|
|
102
|
+
const list = overlay.querySelector('[data-codingns-peer-host-list]');
|
|
103
|
+
if (list === null)
|
|
104
|
+
return;
|
|
105
|
+
list.textContent = '正在读取 PeerHost...';
|
|
106
|
+
try {
|
|
107
|
+
const records = await api.list();
|
|
108
|
+
list.textContent = '';
|
|
109
|
+
for (const record of records)
|
|
110
|
+
list.append(renderRecord(overlay.ownerDocument, api, record, list));
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
list.textContent = error instanceof Error ? error.message : String(error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function renderRecord(dom, api, record, list) {
|
|
117
|
+
const row = dom.createElement('article');
|
|
118
|
+
row.setAttribute('data-peer-host-id', record.id);
|
|
119
|
+
const title = dom.createElement('strong');
|
|
120
|
+
title.textContent = `${record.displayName} · ${record.route.kind} · ${record.status}`;
|
|
121
|
+
const detail = dom.createElement('div');
|
|
122
|
+
detail.textContent = `DSH ${record.dshVersion ?? '未知'} · 插件 ${record.pluginVersion ?? '未知'} · fingerprint ${redactFingerprint(record.fingerprint)}${record.lastErrorCode === null ? '' : ` · ${record.lastErrorCode}`}`;
|
|
123
|
+
const actions = dom.createElement('div');
|
|
124
|
+
actions.append(actionButton(dom, '编辑', () => edit(dom, api, record, run)), actionButton(dom, '检查', () => run(() => api.check(record.id))), actionButton(dom, '重连', () => run(() => api.reconnect(record.id))), actionButton(dom, '登录', () => login(dom, api, record.id, run)), actionButton(dom, '退出', () => run(() => api.logout(record.id))), actionButton(dom, '删除', () => {
|
|
125
|
+
if (dom.defaultView?.confirm(`确认删除 PeerHost“${record.displayName}”?`) !== true)
|
|
126
|
+
return;
|
|
127
|
+
run(() => api.remove(record.id));
|
|
128
|
+
}));
|
|
129
|
+
row.append(title, detail, actions);
|
|
130
|
+
return row;
|
|
131
|
+
function run(operation) {
|
|
132
|
+
void operation().then(() => refreshList(list.parentElement, api)).catch((error) => { detail.textContent = error instanceof Error ? error.message : String(error); });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function login(dom, api, peerHostId, run) {
|
|
136
|
+
const username = dom.defaultView?.prompt('目标 Host 用户名');
|
|
137
|
+
const password = dom.defaultView?.prompt('目标 Host 密码');
|
|
138
|
+
if (!username || !password)
|
|
139
|
+
return;
|
|
140
|
+
run(() => api.login({ peerHostId, username, password }));
|
|
141
|
+
}
|
|
142
|
+
function edit(dom, api, record, run) {
|
|
143
|
+
const displayName = dom.defaultView?.prompt('PeerHost 名称', record.displayName)?.trim();
|
|
144
|
+
if (!displayName)
|
|
145
|
+
return;
|
|
146
|
+
if (record.route.kind === 'lan') {
|
|
147
|
+
const baseUrl = dom.defaultView?.prompt('局域网地址(重新输入)')?.trim();
|
|
148
|
+
if (!baseUrl)
|
|
149
|
+
return;
|
|
150
|
+
run(() => api.update({ peerHostId: record.id, displayName, route: { kind: 'lan', baseUrl, normalizedOrigin: '' } }));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const deviceId = dom.defaultView?.prompt('中转设备标识')?.trim();
|
|
154
|
+
const relayEntryId = dom.defaultView?.prompt('中转绑定标识')?.trim();
|
|
155
|
+
const transportVersion = dom.defaultView?.prompt('中转协议版本')?.trim();
|
|
156
|
+
if (!deviceId || !relayEntryId || !transportVersion)
|
|
157
|
+
return;
|
|
158
|
+
run(() => api.update({ peerHostId: record.id, displayName, route: { kind: 'relay', deviceId, relayEntryId, transportVersion } }));
|
|
159
|
+
}
|
|
160
|
+
function actionButton(dom, label, action) {
|
|
161
|
+
const button = dom.createElement('button');
|
|
162
|
+
button.type = 'button';
|
|
163
|
+
button.textContent = label;
|
|
164
|
+
button.addEventListener('click', action);
|
|
165
|
+
return button;
|
|
166
|
+
}
|
|
167
|
+
function input(dom, label, type) {
|
|
168
|
+
const wrapper = dom.createElement('label');
|
|
169
|
+
wrapper.textContent = label;
|
|
170
|
+
const control = dom.createElement('input');
|
|
171
|
+
control.type = type;
|
|
172
|
+
control.required = true;
|
|
173
|
+
wrapper.append(control);
|
|
174
|
+
return { wrapper, input: control };
|
|
175
|
+
}
|
|
176
|
+
function redactFingerprint(value) {
|
|
177
|
+
if (value === null || value.length <= 12)
|
|
178
|
+
return value ?? '未知';
|
|
179
|
+
return `${value.slice(0, 8)}...${value.slice(-4)}`;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=peer-host-management-panel.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { AggregateHostResult, HostScope } from '../shared/contracts/peer-host.js';
|
|
2
|
+
import type { PeerHostEventSocketFactory, PeerHostScopedClient } from './peer-host-scoped-client.js';
|
|
3
|
+
import type { PeerHostSessionController } from './peer-host-session-controller.js';
|
|
4
|
+
export declare const PEER_HOST_NAVIGATION_ATTRIBUTE = "data-codingns-peer-host-navigation";
|
|
5
|
+
export declare const PEER_HOST_SESSION_ATTRIBUTE = "data-codingns-peer-host-session";
|
|
6
|
+
export declare const PEER_HOST_STATUS_ATTRIBUTE = "data-codingns-peer-host-status";
|
|
7
|
+
export type PeerHostNativeUiStatus = 'ready' | 'degraded' | 'unavailable';
|
|
8
|
+
export interface PeerHostNativeUiState {
|
|
9
|
+
readonly status: PeerHostNativeUiStatus;
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
}
|
|
12
|
+
export interface PeerHostNativeNavigationOptions {
|
|
13
|
+
readonly document?: Document;
|
|
14
|
+
readonly controller: PeerHostSessionController;
|
|
15
|
+
readonly onSelect?: (scope: HostScope) => void | Promise<void>;
|
|
16
|
+
readonly onStatus?: (state: PeerHostNativeUiState) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface PeerHostNativeNavigationController {
|
|
19
|
+
refresh(results: readonly AggregateHostResult[]): void;
|
|
20
|
+
setStatus(state: PeerHostNativeUiState): void;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
readonly state: PeerHostNativeUiState;
|
|
23
|
+
}
|
|
24
|
+
/** 仅探测,不修改 DOM;供能力诊断和版本 fixture 使用。 */
|
|
25
|
+
export declare function probePeerHostNativeNavigation(dom?: Document): PeerHostNativeUiState;
|
|
26
|
+
/** 仅探测会话容器,不触发请求。 */
|
|
27
|
+
export declare function probePeerHostNativeSession(dom?: Document): PeerHostNativeUiState;
|
|
28
|
+
/**
|
|
29
|
+
* 将聚合导航挂到 DSH 已声明的 tree 容器。
|
|
30
|
+
*
|
|
31
|
+
* 这里不猜 React Fiber 或版本专属 class。只有同时存在 tree 和至少一个
|
|
32
|
+
* treeitem 才认为原生导航扩展点可用;否则保留明确的降级状态,不创建伪造
|
|
33
|
+
* 的工作区数据。
|
|
34
|
+
*/
|
|
35
|
+
export declare function startPeerHostNativeNavigation(options: PeerHostNativeNavigationOptions): PeerHostNativeNavigationController;
|
|
36
|
+
export interface PeerHostNativeSessionOptions {
|
|
37
|
+
readonly document?: Document;
|
|
38
|
+
readonly controller: PeerHostSessionController;
|
|
39
|
+
readonly client: PeerHostScopedClient;
|
|
40
|
+
readonly socketFactory?: PeerHostEventSocketFactory;
|
|
41
|
+
readonly onStatus?: (state: PeerHostNativeUiState) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface PeerHostNativeSessionController {
|
|
44
|
+
open(scope: HostScope): Promise<void>;
|
|
45
|
+
close(): void;
|
|
46
|
+
send(body: string): Promise<void>;
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
replyPermission(body: string): Promise<void>;
|
|
49
|
+
answerQuestion(body: string): Promise<void>;
|
|
50
|
+
readonly state: PeerHostNativeUiState;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 远端会话的原生三栏适配器。
|
|
54
|
+
*
|
|
55
|
+
* DSH 目前没有公开的 HostScope 会话 store 注入点,因此消息先落到当前
|
|
56
|
+
* conversation 容器中的插件节点。这个节点与原生布局同层渲染,明确标记
|
|
57
|
+
* 来源和作用域;若容器探测失败则报告 degraded,不把 iframe 当作原生 UI。
|
|
58
|
+
*/
|
|
59
|
+
export declare function startPeerHostNativeSession(options: PeerHostNativeSessionOptions): PeerHostNativeSessionController;
|
|
60
|
+
//# sourceMappingURL=peer-host-native-session-ui.d.ts.map
|