dsh-remote-local-plugin 0.8.1 → 0.8.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.md +1 -1
- package/cordis.patch.yml +3 -0
- package/lib/client.js +6 -0
- package/lib/client.js.map +2 -2
- package/lib/index.js +77 -4
- package/lib/types/config.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Remote development that appears as ordinary local sessions.
|
|
|
7
7
|
This plugin targets the official **DSH Desktop** application. Tested/supported versions:
|
|
8
8
|
|
|
9
9
|
- [DSH Desktop](https://github.com/deepseek-ai/deepseek-harness) [`0.2.1-rc.2`](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.2)
|
|
10
|
-
- Plugin [`0.8.
|
|
10
|
+
- Plugin [`0.8.3`](https://www.npmjs.com/package/dsh-remote-local-plugin)
|
|
11
11
|
- Remote DSH [`0.2.1-rc.2`](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-rc.2)
|
|
12
12
|
- Remote [Node.js `22.19+`](https://nodejs.org/en/download) on Linux/macOS
|
|
13
13
|
|
package/cordis.patch.yml
CHANGED
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
remotePnpmVersion: 11.21.0
|
|
34
34
|
remoteStart: systemd
|
|
35
35
|
provisionTimeoutMs: 600000
|
|
36
|
+
# Remote-visible HTTP(S) proxy. Empty means inspect the account login shell.
|
|
37
|
+
remoteInstallProxy: ''
|
|
38
|
+
remoteInstallNoProxy: 127.0.0.1,localhost
|
|
36
39
|
|
|
37
40
|
# Default: copy the locally resolved key into the remote service env.
|
|
38
41
|
credentialProxy: false
|
package/lib/client.js
CHANGED
|
@@ -134,6 +134,8 @@ var DETAIL_KEYS = {
|
|
|
134
134
|
"\u6B63\u5728\u91CD\u65B0\u5B89\u88C5\u8FDC\u7AEF agent\u2026": "detail.reprovisioning",
|
|
135
135
|
"SSH \u96A7\u9053\u65AD\u5F00\uFF0C\u7B49\u5F85\u91CD\u8FDE\u2026": "detail.reconnecting",
|
|
136
136
|
"\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026": "detail.preparing",
|
|
137
|
+
"\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026": "detail.proxyPreparing",
|
|
138
|
+
"\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026": "detail.proxy",
|
|
137
139
|
"\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026": "detail.uploadingAgent",
|
|
138
140
|
"\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026": "detail.uploaded",
|
|
139
141
|
"\u6B63\u5728\u4E0B\u8F7D Node.js\u2026": "detail.nodeDownloading",
|
|
@@ -783,6 +785,8 @@ var zh = {
|
|
|
783
785
|
"detail.connectedDirect": "\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7531\u8FDC\u7AEF\u76F4\u8FDE DeepSeek",
|
|
784
786
|
"detail.connectedRemote": "\u5DF2\u8FDE\u63A5\uFF1B\u8FDC\u7AEF\u4F7F\u7528\u81EA\u8EAB\u51ED\u636E\u6216\u672A\u914D\u7F6E\u6A21\u578B key",
|
|
785
787
|
"detail.preparing": "\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026",
|
|
788
|
+
"detail.proxyPreparing": "\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026",
|
|
789
|
+
"detail.proxy": "\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026",
|
|
786
790
|
"detail.uploadingAgent": "\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026",
|
|
787
791
|
"detail.uploaded": "\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026",
|
|
788
792
|
"detail.nodeDownloading": "\u6B63\u5728\u4E0B\u8F7D Node.js\u2026",
|
|
@@ -905,6 +909,8 @@ var en = {
|
|
|
905
909
|
"detail.connectedDirect": "Connected; the remote host calls DeepSeek directly",
|
|
906
910
|
"detail.connectedRemote": "Connected; the remote host uses its own credentials or has no model key",
|
|
907
911
|
"detail.preparing": "Preparing the remote installation environment\u2026",
|
|
912
|
+
"detail.proxyPreparing": "Configuring the remote installation proxy\u2026",
|
|
913
|
+
"detail.proxy": "Remote installation proxy configured\u2026",
|
|
908
914
|
"detail.uploadingAgent": "Uploading the remote agent package\u2026",
|
|
909
915
|
"detail.uploaded": "Package uploaded; starting the remote installation\u2026",
|
|
910
916
|
"detail.nodeDownloading": "Downloading Node.js\u2026",
|
package/lib/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client/index.tsx", "../src/host-api/contract.ts", "../src/client/api.ts", "../src/client/RemoteDevelopmentPanel.tsx", "../src/client/panel.css", "../src/client/routing.ts", "../src/client/remote-files.ts", "../src/client/locale.ts", "../src/client/workspace-add.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * dsh-remote-local-plugin browser entry.\n *\n * Registers one Settings section. The component talks only to the injected\n * API closure; the Cordis context stays in `apply`.\n *\n * @module dsh-remote-local/client\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { createHostsApi } from './api.ts'\nimport { RemoteDevelopmentPanel } from './RemoteDevelopmentPanel.tsx'\nimport { installNativeWorkspaceRouting } from './routing.ts'\nimport { installRemoteFiles } from './remote-files.ts'\nimport { NS, en, zh, type LocaleFace } from './locale.ts'\nimport { installWorkspaceAddMenu } from './workspace-add.ts'\n\n/** The Settings shell's slot registry and the authenticated connection. */\nexport const inject = ['slots', 'uiWorkspace', 'locale']\n\n/** Register the \u8FDC\u7A0B\u5F00\u53D1 page. */\nexport function apply(ctx: Context): void {\n const api = createHostsApi(ctx)\n const locale = (ctx as unknown as { locale: LocaleFace }).locale\n ctx.effect(() => locale.register(NS, { zh, en }), 'dsh-remote: locale dictionaries')\n const t = locale.bind(NS)\n installNativeWorkspaceRouting(ctx, api)\n installWorkspaceAddMenu(ctx, api, t)\n ctx.inject(['remote.workspaceFiles'], child => {\n installRemoteFiles(child, api)\n })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'remote-development',\n order: 76,\n label: () => t('settings.title'),\n locale: NS,\n inject: () => ({ api }),\n }, RemoteDevelopmentPanel))\n}\n", "/**\n * Host API contract shared by the host handler and the browser Settings page.\n *\n * The route is registered inside DSH Connection's authenticated `/api` fence,\n * so it works through the web HTTP carrier and the desktop IPC carrier without\n * a second authentication scheme.\n *\n * @module dsh-remote-local/host-api/contract\n */\n\nimport type { HostView } from '../hosts/types.ts'\nimport type {\n AcceptedResult,\n CreateSessionResult,\n HostInfo,\n PromptDeliveryMode,\n RemoteSessionSummary,\n RemoteWorkspace,\n SessionSnapshot,\n} from '@dsh-remote/protocol'\n\n/** Exact authenticated Fetch route owned by the local plugin. */\nexport const HOST_API_PATH = '/api/dsh-remote'\n\n/** Endpoint names. */\nexport type HostApiEndpoint =\n | 'state'\n | 'target/validate'\n | 'host/add'\n | 'host/remove'\n | 'host/connect'\n | 'host/disconnect'\n | 'host/refresh'\n | 'host/provision'\n | 'host/workspaces'\n | 'host/workspace/create'\n | 'host/directory/list'\n | 'local/directory/list'\n | 'local/workspace/create'\n | 'host/sessions'\n | 'host/session'\n | 'host/session/create'\n | 'host/session/prompt'\n | 'host/session/cancel'\n | 'host/web-url'\n | 'host/files/list'\n | 'host/files/read'\n | 'host/files/stat'\n | 'host/files/bytes'\n\n/** Browser-safe state snapshot. */\nexport interface RemoteHostsState {\n readonly protocolVersion: number\n readonly hosts: readonly HostView[]\n}\n\n/** Result of parsing a destination. */\nexport interface ValidatedTarget {\n readonly canonical: string\n readonly host: string\n readonly user: string | null\n readonly port: number | null\n}\n\n/** Result of listing workspaces. */\nexport interface HostWorkspace extends RemoteWorkspace {\n /** Local mirror workspace id, when it has been synced. */\n readonly localWorkspaceId?: string\n}\n\nexport interface WorkspacesResult {\n readonly workspaces: readonly HostWorkspace[]\n}\n\n/** Result of listing sessions. */\nexport interface SessionsResult {\n readonly sessions: readonly RemoteSessionSummary[]\n}\n\nexport interface HostCreateSessionResult extends CreateSessionResult {\n /** Local mirror session that opens in the ordinary Conversation UI. */\n readonly localSessionId?: string\n}\n\nexport interface MirrorFileResult {\n readonly mirrored: boolean\n readonly value?: unknown\n}\n\n/** Result of resolving the remote Web UI. */\nexport interface WebUrlResult {\n readonly url: string\n}\n\n/** One request body. */\nexport interface HostApiRequest {\n readonly endpoint: HostApiEndpoint\n readonly payload?: unknown\n}\n\n/** Success/failure result returned by the route. */\nexport type HostApiResult<T> =\n | { readonly ok: true; readonly value: T }\n | {\n readonly ok: false\n readonly error: {\n readonly code: string\n readonly message: string\n readonly details: Record<string, unknown>\n }\n }\n\n/** Payloads accepted by each endpoint. */\nexport interface HostApiPayloads {\n state: undefined\n 'target/validate': { sshTarget: string }\n 'host/add': {\n sshTarget: string\n label?: string\n token?: string\n remoteAgentPort?: number\n autoConnect?: boolean\n }\n 'host/remove': { hostId: string }\n 'host/connect': { hostId: string }\n 'host/disconnect': { hostId: string }\n 'host/refresh': { hostId: string }\n 'host/provision': { hostId: string }\n 'host/workspaces': { hostId: string }\n 'host/workspace/create': { hostId: string; path: string; title?: string }\n 'host/directory/list': { hostId: string; path?: string }\n 'local/directory/list': { path?: string }\n 'local/workspace/create': { path: string; title?: string }\n 'host/sessions': { hostId: string; workspaceId?: string }\n 'host/session': { hostId: string; sessionId: string; limit?: number }\n 'host/session/create': { hostId: string; workspaceId?: string; cwd?: string; agentPreset?: string }\n 'host/session/prompt': {\n hostId: string\n sessionId: string\n text: string\n mode?: PromptDeliveryMode\n provider?: string\n model?: string\n reasoningEffort?: string\n }\n 'host/session/cancel': { hostId: string; sessionId: string }\n 'host/web-url': { hostId: string }\n 'host/files/list': { sessionId: string; path: string }\n 'host/files/read': { sessionId: string; path: string; offset?: number; limit?: number }\n 'host/files/stat': { sessionId: string; path: string }\n 'host/files/bytes': { sessionId: string; path: string; offset?: number; length?: number }\n}\n\n/** Values returned by each endpoint. */\nexport interface HostApiValues {\n state: RemoteHostsState\n 'target/validate': ValidatedTarget\n 'host/add': HostView\n 'host/remove': { removed: true }\n 'host/connect': HostView\n 'host/disconnect': HostView\n 'host/refresh': HostView\n 'host/provision': HostView\n 'host/workspaces': WorkspacesResult\n 'host/workspace/create': RemoteWorkspace\n 'host/directory/list': { path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }\n 'local/directory/list': { path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }\n 'local/workspace/create': { workspaceId: string }\n 'host/sessions': SessionsResult\n 'host/session': SessionSnapshot\n 'host/session/create': HostCreateSessionResult\n 'host/session/prompt': AcceptedResult\n 'host/session/cancel': AcceptedResult\n 'host/web-url': WebUrlResult\n 'host/files/list': MirrorFileResult\n 'host/files/read': MirrorFileResult\n 'host/files/stat': MirrorFileResult\n 'host/files/bytes': MirrorFileResult\n}\n\n/** Informational type for the Settings page. */\nexport interface HostSummary extends Pick<HostView, 'id' | 'label' | 'sshTarget' | 'phase'> {\n readonly hostInfo: HostInfo | null\n}\n", "/**\n * Browser-side API wrapper around the host's authenticated Fetch route.\n * Components never see `ctx`.\n *\n * @module dsh-remote-local/client/api\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { AcceptedResult, PromptDeliveryMode, RemoteWorkspace, SessionSnapshot } from '@dsh-remote/protocol'\nimport type { HostCreateSessionResult, MirrorFileResult } from '../host-api/contract.ts'\nimport {\n HOST_API_PATH,\n type HostApiPayloads,\n type HostApiValues,\n type RemoteHostsState,\n type SessionsResult,\n type ValidatedTarget,\n type WebUrlResult,\n type WorkspacesResult,\n} from '../host-api/contract.ts'\nimport type { HostView } from '../hosts/types.ts'\n\n/** Error surfaced by one host call. */\nexport class RemoteUiError extends Error {\n readonly code: string\n readonly details: Record<string, unknown>\n\n constructor(code: string, message: string, details: Record<string, unknown> = {}) {\n super(message)\n this.name = 'RemoteUiError'\n this.code = code\n this.details = details\n }\n}\n\n/** API surface injected into the Settings component. */\nexport interface HostsApi {\n readonly state: () => Promise<RemoteHostsState>\n readonly validateTarget: (sshTarget: string) => Promise<ValidatedTarget>\n readonly addHost: (input: HostApiPayloads['host/add']) => Promise<HostView>\n readonly removeHost: (hostId: string) => Promise<void>\n readonly connect: (hostId: string) => Promise<HostView>\n readonly disconnect: (hostId: string) => Promise<HostView>\n readonly refresh: (hostId: string) => Promise<HostView>\n readonly provision: (hostId: string) => Promise<HostView>\n readonly workspaces: (hostId: string) => Promise<WorkspacesResult>\n readonly listDirectories: (hostId: string, path?: string) => Promise<{ path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }>\n readonly listLocalDirectories: (path?: string) => Promise<{ path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }>\n readonly createLocalWorkspace: (input: { path: string; title?: string }) => Promise<{ workspaceId: string }>\n readonly createWorkspace: (hostId: string, input: { path: string; title?: string }) => Promise<RemoteWorkspace>\n readonly sessions: (hostId: string, workspaceId?: string) => Promise<SessionsResult>\n readonly webUrl: (hostId: string) => Promise<WebUrlResult>\n readonly snapshot: (hostId: string, sessionId: string, limit?: number) => Promise<SessionSnapshot>\n readonly createSession: (hostId: string, input: { workspaceId?: string; cwd?: string; agentPreset?: string }) => Promise<HostCreateSessionResult>\n readonly openSession: (sessionId: string) => void\n readonly fileList: (sessionId: string, path: string) => Promise<MirrorFileResult>\n readonly fileRead: (sessionId: string, path: string, offset?: number, limit?: number) => Promise<MirrorFileResult>\n readonly fileStat: (sessionId: string, path: string) => Promise<MirrorFileResult>\n readonly fileBytes: (sessionId: string, path: string, offset?: number, length?: number) => Promise<MirrorFileResult>\n readonly prompt: (hostId: string, sessionId: string, text: string, mode?: PromptDeliveryMode, selection?: { provider: string; model: string; reasoningEffort?: string }) => Promise<AcceptedResult>\n readonly cancel: (hostId: string, sessionId: string) => Promise<AcceptedResult>\n}\n\n/** Build the API closure once per plugin mount. */\nexport function createHostsApi(ctx: Context): HostsApi {\n return {\n state: () => call('state', undefined),\n validateTarget: sshTarget => call('target/validate', { sshTarget }),\n addHost: input => call('host/add', input),\n removeHost: async hostId => { await call('host/remove', { hostId }) },\n connect: hostId => call('host/connect', { hostId }),\n disconnect: hostId => call('host/disconnect', { hostId }),\n refresh: hostId => call('host/refresh', { hostId }),\n provision: hostId => call('host/provision', { hostId }),\n workspaces: hostId => call('host/workspaces', { hostId }),\n listDirectories: (hostId, path) => call('host/directory/list', { hostId, ...path === undefined ? {} : { path } }),\n listLocalDirectories: path => call('local/directory/list', { ...path === undefined ? {} : { path } }),\n createLocalWorkspace: input => call('local/workspace/create', input),\n createWorkspace: (hostId, input) => call('host/workspace/create', { hostId, ...input }),\n sessions: (hostId, workspaceId) => call('host/sessions', {\n hostId,\n ...workspaceId === undefined ? {} : { workspaceId },\n }),\n webUrl: hostId => call('host/web-url', { hostId }),\n snapshot: (hostId, sessionId, limit) => call('host/session', {\n hostId,\n sessionId,\n ...limit === undefined ? {} : { limit },\n }),\n createSession: (hostId, input) => call('host/session/create', { hostId, ...input }),\n openSession: sessionId => { ctx.uiWorkspace.openSession(sessionId as never) },\n fileList: (sessionId, path) => call('host/files/list', { sessionId, path }),\n fileRead: (sessionId, path, offset, limit) => call('host/files/read', {\n sessionId,\n path,\n ...offset === undefined ? {} : { offset },\n ...limit === undefined ? {} : { limit },\n }),\n fileStat: (sessionId, path) => call('host/files/stat', { sessionId, path }),\n fileBytes: (sessionId, path, offset, length) => call('host/files/bytes', {\n sessionId,\n path,\n ...offset === undefined ? {} : { offset },\n ...length === undefined ? {} : { length },\n }),\n prompt: (hostId, sessionId, text, mode, selection) => call('host/session/prompt', {\n hostId,\n sessionId,\n text,\n ...mode === undefined ? {} : { mode },\n ...selection === undefined ? {} : selection,\n }),\n cancel: (hostId, sessionId) => call('host/session/cancel', { hostId, sessionId }),\n }\n}\n\nasync function call<K extends keyof HostApiPayloads & string>(\n endpoint: K,\n payload: HostApiPayloads[K],\n): Promise<HostApiValues[K]> {\n const response = await fetch(HOST_API_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload === undefined ? { endpoint } : { endpoint, payload }),\n })\n if (!response.ok) {\n throw new RemoteUiError('request/invalid', `host API returned HTTP ${response.status}`)\n }\n const result = await response.json() as\n | { ok: true; value: HostApiValues[K] }\n | { ok: false; error: { code: string; message: string; details?: Record<string, unknown> } }\n if (!result.ok) {\n throw new RemoteUiError(result.error.code, result.error.message, result.error.details ?? {})\n }\n return result.value\n}\n", "/**\n * Settings \u2192 \u8FDC\u7A0B\u5F00\u53D1 page.\n *\n * The page is a projection over the host plugin's authenticated RPC channel.\n * It owns only view state (form fields, which host is expanded); every\n * durable fact and every tunnel lives in the host process.\n *\n * @module dsh-remote-local/client/panel\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport type { RemoteSessionSummary, RemoteWorkspace } from '@dsh-remote/protocol'\nimport type { HostView } from '../hosts/types.ts'\nimport type { RemoteHostsState } from '../host-api/contract.ts'\nimport type { HostsApi } from './api.ts'\nimport type { CopyKey, Translate } from './locale.ts'\nimport panelCss from './panel.css'\n\n/** Props injected by the Settings page. */\ninterface PanelProps {\n readonly api: HostsApi\n readonly t: Translate\n}\n\nfunction phaseLabel(t: Translate, phase: HostView['phase']): string {\n return t(`phase.${phase}` as CopyKey)\n}\n\nconst DETAIL_KEYS: Record<string, CopyKey> = {\n '\u6B63\u5728\u901A\u8FC7 SSH \u53D1\u73B0\u8FDC\u7AEF agent\u2026': 'detail.discovering',\n '\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5 DSH \u4E0E dsh-remote-agent\uFF0C\u9996\u6B21\u7EA6 1\u20133 \u5206\u949F\u2026': 'detail.installing',\n '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u5E76\u6821\u9A8C\u8FDC\u7AEF agent\u2026': 'detail.connecting',\n '\u6B63\u5728\u91CD\u65B0\u5B89\u88C5\u8FDC\u7AEF agent\u2026': 'detail.reprovisioning',\n 'SSH \u96A7\u9053\u65AD\u5F00\uFF0C\u7B49\u5F85\u91CD\u8FDE\u2026': 'detail.reconnecting',\n '\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026': 'detail.preparing',\n '\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026': 'detail.uploadingAgent',\n '\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026': 'detail.uploaded',\n '\u6B63\u5728\u4E0B\u8F7D Node.js\u2026': 'detail.nodeDownloading',\n 'Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026': 'detail.nodeInstalled',\n 'Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026': 'detail.nodeReady',\n '\u6B63\u5728\u5B89\u88C5 pnpm\u2026': 'detail.pnpmInstalling',\n '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF DSH\uFF08\u4E0B\u8F7D\u4F9D\u8D56\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF09\u2026': 'detail.dshInstalling',\n '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF agent\u2026': 'detail.agentInstalling',\n '\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026': 'detail.webStarting',\n '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u6587\u4EF6\u2026': 'detail.waitingState',\n '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u2026': 'detail.waitingAgent',\n '\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026': 'detail.agentReady',\n '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\u2026': 'detail.installed',\n '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u6B63\u5728\u7B49\u5F85 DSH web \u542F\u52A8\u2026': 'detail.waitingWeb',\n '\u4ECD\u5728\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026': 'detail.stillWaiting',\n '\u6B63\u5728\u8BFB\u53D6\u8FDC\u7AEF agent \u72B6\u6001\u2026': 'detail.readingState',\n '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u2026': 'detail.tunnel',\n '\u6B63\u5728\u6821\u9A8C\u8FDC\u7AEF agent\u2026': 'detail.checkingAgent',\n '\u6B63\u5728\u540C\u6B65\u8FDC\u7AEF\u6A21\u578B\u73AF\u5883\u2026': 'detail.reconcilingModel',\n '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7ECF\u672C\u5730\u51ED\u636E\u4EE3\u7406\u8F6C\u53D1': 'detail.connectedProxy',\n '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7531\u8FDC\u7AEF\u76F4\u8FDE DeepSeek': 'detail.connectedDirect',\n '\u5DF2\u8FDE\u63A5\uFF1B\u8FDC\u7AEF\u4F7F\u7528\u81EA\u8EAB\u51ED\u636E\u6216\u672A\u914D\u7F6E\u6A21\u578B key': 'detail.connectedRemote',\n}\n\nfunction detailLabel(t: Translate, detail: string): string {\n const key = DETAIL_KEYS[detail]\n return key === undefined ? detail : t(key)\n}\n\nconst POLL_MS = 2_500\n\n/** Render the remote-development settings page. */\nexport function RemoteDevelopmentPanel({ api, t }: PanelProps) {\n const [state, setState] = useState<RemoteHostsState | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n const [expandedHost, setExpandedHost] = useState<string | null>(null)\n const [workspaces, setWorkspaces] = useState<Record<string, RemoteWorkspace[] | undefined>>({})\n const [openWorkspace, setOpenWorkspace] = useState<Record<string, boolean>>({})\n const [sessions, setSessions] = useState<Record<string, RemoteSessionSummary[] | undefined>>({})\n const [workspaceDraft, setWorkspaceDraft] = useState('')\n const [form, setForm] = useState({\n sshTarget: '',\n label: '',\n })\n\n useInjectedStyle(panelCss)\n\n const hosts = useMemo(() => state?.hosts ?? [], [state])\n\n useEffect(() => {\n let cancelled = false\n const load = async (): Promise<void> => {\n try {\n const next = await api.state()\n if (!cancelled) {\n setState(next)\n setError(current => current === t('settings.unavailable') ? null : current)\n }\n } catch (failure) {\n if (!cancelled) setError(messageOf(failure, t('settings.unavailable')))\n }\n }\n void load()\n const timer = window.setInterval(() => { void load() }, POLL_MS)\n const onFocus = (): void => { void load() }\n window.addEventListener('focus', onFocus)\n return () => {\n cancelled = true\n window.clearInterval(timer)\n window.removeEventListener('focus', onFocus)\n }\n }, [api, t])\n\n useEffect(() => {\n const host = hosts.find(item => item.id === expandedHost)\n if (host?.phase === 'connected' && workspaces[host.id] === undefined) {\n void loadWorkspaces(host.id)\n }\n }, [hosts, expandedHost, workspaces])\n\n async function refresh(): Promise<void> {\n setState(await api.state())\n }\n\n async function run(key: string, task: () => Promise<void>): Promise<void> {\n setBusy(key)\n setError(null)\n setNotice(null)\n try {\n await task()\n await refresh()\n } catch (failure) {\n setError(messageOf(failure, t('settings.operationFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n async function onAdd(): Promise<void> {\n const sshTarget = form.sshTarget.trim()\n if (sshTarget === '') {\n setError(t('settings.sshRequired'))\n return\n }\n await run('add', async () => {\n await api.validateTarget(sshTarget)\n const host = await api.addHost({\n sshTarget,\n ...form.label.trim() === '' ? {} : { label: form.label.trim() },\n autoConnect: true,\n })\n setForm({ sshTarget: '', label: '' })\n setExpandedHost(host.id)\n setNotice(t('settings.hostSaved'))\n })\n }\n\n async function toggleHost(host: HostView): Promise<void> {\n if (expandedHost === host.id) {\n setExpandedHost(null)\n return\n }\n setExpandedHost(host.id)\n await loadWorkspaces(host.id)\n }\n\n async function loadWorkspaces(hostId: string): Promise<void> {\n setWorkspaces(current => ({ ...current, [hostId]: undefined }))\n try {\n const result = await api.workspaces(hostId)\n setWorkspaces(current => ({ ...current, [hostId]: [...result.workspaces] }))\n } catch (failure) {\n setWorkspaces(current => ({ ...current, [hostId]: [] }))\n setError(messageOf(failure, t('settings.readWorkspacesFailed')))\n }\n }\n\n async function toggleWorkspace(hostId: string, workspaceId: string): Promise<void> {\n const key = `${hostId}:${workspaceId}`\n const next = !(openWorkspace[key] ?? false)\n setOpenWorkspace(current => ({ ...current, [key]: next }))\n if (!next || sessions[key] !== undefined) return\n setSessions(current => ({ ...current, [key]: undefined }))\n try {\n const result = await api.sessions(hostId, workspaceId)\n setSessions(current => ({ ...current, [key]: [...result.sessions] }))\n } catch (failure) {\n setSessions(current => ({ ...current, [key]: [] }))\n setError(messageOf(failure, t('settings.readSessionsFailed')))\n }\n }\n\n async function addWorkspace(host: HostView): Promise<void> {\n const path = workspaceDraft.trim()\n if (path === '') {\n setError(t('settings.pathRequired'))\n return\n }\n setBusy(`workspace:${host.id}`)\n setError(null)\n try {\n await api.createWorkspace(host.id, { path })\n setWorkspaceDraft('')\n await loadWorkspaces(host.id)\n setExpandedHost(host.id)\n } catch (failure) {\n setError(messageOf(failure, t('settings.addWorkspaceFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n\n\n async function newSession(host: HostView, workspaceId: string): Promise<void> {\n setBusy(`create:${host.id}:${workspaceId}`)\n setError(null)\n try {\n const created = await api.createSession(host.id, { workspaceId })\n const key = `${host.id}:${workspaceId}`\n setOpenWorkspace(current => ({ ...current, [key]: true }))\n if (created.localSessionId !== undefined) {\n api.openSession(created.localSessionId)\n setNotice(t('settings.sessionOpening'))\n window.setTimeout(() => {\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))\n }, 80)\n } else {\n setNotice(t('settings.sessionSyncing'))\n }\n const result = await api.sessions(host.id, workspaceId)\n setSessions(current => ({ ...current, [key]: [...result.sessions] }))\n const refreshed = await api.workspaces(host.id)\n setWorkspaces(current => ({ ...current, [host.id]: [...refreshed.workspaces] }))\n } catch (failure) {\n setError(messageOf(failure, t('settings.createSessionFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n\n\n async function onRemove(host: HostView): Promise<void> {\n if (!window.confirm(`${t('settings.confirmRemovePrefix')}${host.label}${t('settings.confirmRemoveSuffix')}`)) return\n await run(`remove:${host.id}`, async () => {\n await api.removeHost(host.id)\n if (expandedHost === host.id) setExpandedHost(null)\n })\n }\n\n return (\n <div className=\"dshr-root\">\n <header className=\"dshr-header\">\n <div>\n <h2>{t('settings.title')}</h2>\n <p className=\"dshr-subtitle\">\n {t('settings.subtitle.lead')}\n {' '}\n {t('settings.subtitle.body')}\n </p>\n </div>\n <button\n type=\"button\"\n className=\"dshr-button\"\n onClick={() => { void refresh().catch(failure => setError(messageOf(failure, t('settings.refreshFailed')))) }}\n disabled={busy !== null}\n >\n {t('settings.refresh')}\n </button>\n </header>\n\n {error !== null && <p className=\"dshr-banner dshr-banner-error\" role=\"alert\">{error}</p>}\n {notice !== null && <p className=\"dshr-banner dshr-banner-info\" role=\"status\">{notice}</p>}\n\n <section className=\"dshr-card\">\n <h3>{t('settings.addHost')}</h3>\n <form\n className=\"dshr-form\"\n onSubmit={event => {\n event.preventDefault()\n void onAdd()\n }}\n >\n <label className=\"dshr-field dshr-field-wide\">\n <span>{t('settings.sshTarget')}</span>\n <input\n value={form.sshTarget}\n onChange={event => setForm(current => ({ ...current, sshTarget: event.target.value }))}\n placeholder={t('settings.sshPlaceholder')}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n <label className=\"dshr-field\">\n <span>{t('settings.label')}</span>\n <input\n value={form.label}\n onChange={event => setForm(current => ({ ...current, label: event.target.value }))}\n placeholder={t('settings.labelPlaceholder')}\n />\n </label>\n <div className=\"dshr-form-actions\">\n <button type=\"submit\" className=\"dshr-button dshr-button-primary\" disabled={busy !== null}>\n {busy === 'add' ? t('settings.adding') : t('settings.saveConnect')}\n </button>\n <span className=\"dshr-hint\">{t('settings.sshHint')}</span>\n </div>\n </form>\n </section>\n\n <section className=\"dshr-card\">\n <div className=\"dshr-section-title\">\n <h3>{t('settings.hosts')}</h3>\n <span className=\"dshr-hint\">{hosts.length} {t('settings.hostsUnit')}</span>\n </div>\n {hosts.length === 0 && <p className=\"dshr-empty\">{t('settings.noHosts')}</p>}\n <div className=\"dshr-hosts\">\n {hosts.map(host => (\n <article key={host.id} className=\"dshr-host\">\n <header className=\"dshr-host-head\">\n <div className=\"dshr-host-title\">\n <strong>{host.label}</strong>\n <code>{host.sshTarget}</code>\n </div>\n <span className={`dshr-phase dshr-phase-${host.phase}`}>{phaseLabel(t, host.phase)}</span>\n </header>\n\n <dl className=\"dshr-meta\">\n <div><dt>{t('settings.remotePort')}</dt><dd>{host.remoteAgentPort ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.localTunnel')}</dt><dd>{host.localPort ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.workspaces')}</dt><dd>{host.workspaceCount ?? '\u2014'}</dd></div>\n <div><dt>Agent</dt><dd>{host.hostInfo?.agentVersion ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.token')}</dt><dd>{host.hasToken ? t('settings.saved') : t('settings.unsaved')}</dd></div>\n <div><dt>{t('settings.modelProxy')}</dt><dd>{host.modelProxy ? t('settings.localProxy') : host.modelDirect ? t('settings.direct') : t('settings.remoteDefault')}</dd></div>\n </dl>\n\n {host.detail !== null && <p className=\"dshr-detail\">{detailLabel(t, host.detail)}</p>}\n {host.error !== null && <p className=\"dshr-host-error\" role=\"alert\">{host.error}</p>}\n\n <div className=\"dshr-actions\">\n {host.phase === 'connected'\n ? (\n <>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void toggleHost(host) }}\n >\n {expandedHost === host.id ? t('settings.collapseWorkspaces') : t('settings.expandWorkspaces')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`refresh:${host.id}`, async () => { await api.refresh(host.id) }) }}\n >\n {t('settings.rediscover')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`disconnect:${host.id}`, async () => { await api.disconnect(host.id) }) }}\n >\n {t('settings.disconnect')}\n </button>\n </>\n )\n : (\n <>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-primary\"\n disabled={busy !== null || host.phase === 'installing' || host.phase === 'discovering' || host.phase === 'connecting'}\n onClick={() => { void run(`connect:${host.id}`, async () => { await api.connect(host.id) }) }}\n >\n {host.phase === 'installing' ? t('settings.installing') : host.phase === 'connecting' ? t('settings.connecting') : t('settings.connect')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`refresh:${host.id}`, async () => { await api.refresh(host.id) }) }}\n >\n {t('settings.rediscover')}\n </button>\n </>\n )}\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null || host.phase === 'installing'}\n onClick={() => { void run(`provision:${host.id}`, async () => { await api.provision(host.id) }) }}\n >\n {t('settings.reprovision')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-danger\"\n disabled={busy !== null}\n onClick={() => { void onRemove(host) }}\n >\n {t('settings.remove')}\n </button>\n </div>\n\n {expandedHost === host.id && (\n <div className=\"dshr-workspaces\">\n <div className=\"dshr-workspace-add\">\n <input\n value={workspaceDraft}\n onChange={event => setWorkspaceDraft(event.target.value)}\n placeholder={t('settings.workspacePathPlaceholder')}\n spellCheck={false}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void addWorkspace(host)\n }\n }}\n />\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-small\"\n disabled={busy !== null}\n onClick={() => { void addWorkspace(host) }}\n >\n {busy === `workspace:${host.id}` ? t('settings.addingWorkspace') : t('settings.addWorkspace')}\n </button>\n </div>\n {workspaces[host.id] === undefined\n ? <p className=\"dshr-empty\">{t('settings.readingWorkspaces')}</p>\n : workspaces[host.id]?.length === 0\n ? <p className=\"dshr-empty\">{t('settings.noWorkspaces')}</p>\n : workspaces[host.id]?.map(workspace => {\n const workspaceKey = `${host.id}:${workspace.workspaceId}`\n const open = openWorkspace[workspaceKey] ?? false\n return (\n <div key={workspace.workspaceId} className=\"dshr-workspace\">\n <div className=\"dshr-workspace-row\">\n <button\n type=\"button\"\n className=\"dshr-workspace-head\"\n aria-expanded={open}\n onClick={() => { void toggleWorkspace(host.id, workspace.workspaceId) }}\n >\n <span className=\"dshr-caret\">{open ? '\u25BE' : '\u25B8'}</span>\n <span>{workspace.title}</span>\n <code>{workspace.path}</code>\n <span className=\"dshr-count\">{workspace.sessionIds.length} {t('settings.sessionsUnit')}</span>\n </button>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-small\"\n disabled={busy !== null}\n onClick={() => { void newSession(host, workspace.workspaceId) }}\n >\n {busy === `create:${host.id}:${workspace.workspaceId}` ? t('settings.creating') : t('settings.newSession')}\n </button>\n </div>\n {open && (\n <div className=\"dshr-sessions\">\n {sessions[workspaceKey] === undefined\n ? <p className=\"dshr-empty\">{t('settings.readingSessions')}</p>\n : sessions[workspaceKey]?.length === 0\n ? <p className=\"dshr-empty\">{t('settings.noSessions')}</p>\n : sessions[workspaceKey]?.map(session => (\n <div key={session.sessionId} className=\"dshr-session\">\n <span className={session.live ? 'dshr-live' : 'dshr-idle'} />\n <code>{session.sessionId}</code>\n <span>{session.cwd ?? '\u2014'}</span>\n <span className=\"dshr-count\">{session.eventCount ?? '\u2014'} {t('settings.eventsUnit')}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n </article>\n ))}\n </div>\n </section>\n\n </div>\n )\n}\n\nfunction useInjectedStyle(css: string): void {\n useEffect(() => {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-remote-local'\n tag.textContent = css\n document.head.appendChild(tag)\n return () => { tag.remove() }\n }, [css])\n}\n\nfunction messageOf(value: unknown, fallback: string): string {\n return value instanceof Error && value.message !== '' ? value.message : fallback\n}\n", ".dshr-root {\n --dshr-accent: #4f7cff;\n --dshr-danger: #d24b4b;\n --dshr-success: #2f9e63;\n --dshr-warning: #c98417;\n --dshr-border: color-mix(in srgb, currentColor 14%, transparent);\n --dshr-soft: color-mix(in srgb, currentColor 4%, transparent);\n --dshr-softer: color-mix(in srgb, currentColor 2.5%, transparent);\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 2px 32px;\n font-size: 13px;\n line-height: 1.5;\n}\n\n.dshr-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n}\n\n.dshr-header h2 {\n margin: 0 0 4px;\n font-size: 17px;\n font-weight: 650;\n}\n\n.dshr-subtitle {\n max-width: 760px;\n margin: 0;\n opacity: 0.72;\n}\n\n.dshr-subtitle code,\n.dshr-host-title code,\n.dshr-workspace-head code,\n.dshr-session code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.92em;\n}\n\n.dshr-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--dshr-border);\n border-radius: 12px;\n background: var(--dshr-softer);\n}\n\n.dshr-card h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 650;\n}\n\n.dshr-section-title {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n}\n\n.dshr-form {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n}\n\n.dshr-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.dshr-field-wide {\n grid-column: 1 / -1;\n}\n\n.dshr-field > span {\n font-size: 12px;\n opacity: 0.72;\n}\n\n.dshr-field input {\n width: 100%;\n box-sizing: border-box;\n padding: 7px 9px;\n border: 1px solid var(--dshr-border);\n border-radius: 8px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n outline: none;\n}\n\n.dshr-field input:focus {\n border-color: var(--dshr-accent);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dshr-accent) 22%, transparent);\n}\n\n.dshr-check {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n}\n\n.dshr-form-actions {\n display: flex;\n grid-column: 1 / -1;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.dshr-button {\n padding: 6px 12px;\n border: 1px solid var(--dshr-border);\n border-radius: 8px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.dshr-button:hover:not(:disabled) {\n background: color-mix(in srgb, currentColor 8%, transparent);\n}\n\n.dshr-button:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n.dshr-button-primary {\n border-color: color-mix(in srgb, var(--dshr-accent) 65%, transparent);\n background: var(--dshr-accent);\n color: #fff;\n}\n\n.dshr-button-primary:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dshr-accent) 84%, #000);\n}\n\n.dshr-button-danger {\n border-color: color-mix(in srgb, var(--dshr-danger) 45%, transparent);\n color: var(--dshr-danger);\n}\n\n.dshr-hint {\n font-size: 12px;\n opacity: 0.62;\n}\n\n.dshr-empty {\n margin: 0;\n padding: 10px 0;\n opacity: 0.62;\n}\n\n.dshr-banner {\n margin: 0;\n padding: 9px 12px;\n border-radius: 9px;\n border: 1px solid var(--dshr-border);\n}\n\n.dshr-banner-error {\n border-color: color-mix(in srgb, var(--dshr-danger) 45%, transparent);\n background: color-mix(in srgb, var(--dshr-danger) 10%, transparent);\n color: var(--dshr-danger);\n}\n\n.dshr-banner-info {\n border-color: color-mix(in srgb, var(--dshr-accent) 35%, transparent);\n background: color-mix(in srgb, var(--dshr-accent) 9%, transparent);\n}\n\n.dshr-hosts {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dshr-host {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dshr-border);\n border-radius: 10px;\n background: var(--dshr-soft);\n}\n\n.dshr-host-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n\n.dshr-host-title {\n display: flex;\n align-items: baseline;\n gap: 10px;\n flex-wrap: wrap;\n min-width: 0;\n}\n\n.dshr-host-title strong {\n font-size: 14px;\n}\n\n.dshr-phase {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n border: 1px solid currentColor;\n opacity: 0.9;\n}\n\n.dshr-phase-connected {\n color: var(--dshr-success);\n}\n\n.dshr-phase-discovering,\n.dshr-phase-connecting {\n color: var(--dshr-warning);\n}\n\n.dshr-phase-error {\n color: var(--dshr-danger);\n}\n\n.dshr-phase-idle,\n.dshr-phase-disconnected {\n opacity: 0.62;\n}\n\n.dshr-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 6px 20px;\n margin: 0;\n font-size: 12px;\n}\n\n.dshr-meta > div {\n display: flex;\n gap: 5px;\n}\n\n.dshr-meta dt {\n opacity: 0.58;\n}\n\n.dshr-meta dd {\n margin: 0;\n font-variant-numeric: tabular-nums;\n}\n\n.dshr-host-error {\n margin: 0;\n color: var(--dshr-danger);\n font-size: 12px;\n overflow-wrap: anywhere;\n}\n\n.dshr-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.dshr-workspaces {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding-top: 4px;\n border-top: 1px dashed var(--dshr-border);\n}\n\n.dshr-workspace {\n border-radius: 8px;\n background: var(--dshr-softer);\n}\n\n.dshr-workspace-head {\n display: flex;\n align-items: baseline;\n gap: 8px;\n width: 100%;\n box-sizing: border-box;\n padding: 8px 10px;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n flex-wrap: wrap;\n}\n\n.dshr-workspace-head:hover {\n background: var(--dshr-soft);\n}\n\n.dshr-workspace-head code {\n opacity: 0.6;\n}\n\n.dshr-caret {\n width: 12px;\n opacity: 0.6;\n}\n\n.dshr-count {\n margin-left: auto;\n font-size: 11px;\n opacity: 0.55;\n white-space: nowrap;\n}\n\n.dshr-sessions {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 0 10px 8px 30px;\n}\n\n.dshr-session {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 3px 0;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.dshr-session > span:not(.dshr-live):not(.dshr-idle) {\n opacity: 0.62;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.dshr-live,\n.dshr-idle {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n transform: translateY(-1px);\n}\n\n.dshr-live {\n background: var(--dshr-success);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dshr-success) 20%, transparent);\n}\n\n.dshr-idle {\n background: color-mix(in srgb, currentColor 28%, transparent);\n}\n\n@media (max-width: 720px) {\n .dshr-form {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshr-header {\n flex-direction: column;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshr-button {\n transition: none;\n }\n}\n\n.dshr-detail {\n margin: 0;\n font-size: 12px;\n color: var(--dshr-warning);\n}\n\n.dshr-workspace-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-right: 6px;\n}\n\n.dshr-workspace-row .dshr-workspace-head {\n flex: 1;\n}\n\n.dshr-button-small {\n flex: none;\n padding: 3px 8px;\n font-size: 11px;\n}\n\n.dshr-workspace-add {\n display: flex;\n gap: 6px;\n padding: 4px 0 6px;\n}\n\n.dshr-workspace-add input {\n flex: 1;\n min-width: 0;\n padding: 5px 8px;\n border: 1px solid var(--dshr-border);\n border-radius: 7px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n font-size: 12px;\n outline: none;\n}\n\n.dshr-workspace-add input:focus {\n border-color: var(--dshr-accent);\n}\n", "/**\n * Route ordinary sidebar \"new session\" actions for mirrored workspaces to the\n * remote agent instead of creating a local Agent in the mirror anchor.\n *\n * The Settings page has its own `+ \u65B0\u4F1A\u8BDD` flow. This adapter covers the\n * standard workspace-row action so the native sidebar behaves the same way.\n *\n * @module dsh-remote-local/client/routing\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostsApi } from './api.ts'\n\ninterface StartSessionOptions {\n readonly agentPreset?: string\n}\n\ninterface WorkspaceService {\n startSession(workspaceId?: unknown, options?: StartSessionOptions): void\n}\n\n/** Install the sidebar routing adapter once per client mount. */\nexport function installNativeWorkspaceRouting(ctx: Context, api: HostsApi): void {\n const workspace = ctx.uiWorkspace as unknown as WorkspaceService | undefined\n if (workspace === undefined || typeof workspace.startSession !== 'function') return\n const original = workspace.startSession.bind(workspace)\n workspace.startSession = (workspaceId, options) => {\n if (workspaceId === undefined) {\n original(workspaceId, options)\n return\n }\n void route(api, String(workspaceId)).then(routed => {\n if (!routed) original(workspaceId, options)\n }).catch(() => { original(workspaceId, options) })\n }\n}\n\nasync function route(api: HostsApi, localWorkspaceId: string): Promise<boolean> {\n const state = await api.state()\n for (const host of state.hosts) {\n if (host.phase !== 'connected') continue\n const result = await api.workspaces(host.id)\n const workspace = result.workspaces.find(item => item.localWorkspaceId === localWorkspaceId)\n if (workspace === undefined) continue\n const created = await api.createSession(host.id, { workspaceId: workspace.workspaceId })\n if (created.localSessionId !== undefined) {\n api.openSession(created.localSessionId)\n return true\n }\n }\n return false\n}\n", "/**\n * Client proxy for workspace-files calls on mirrored Sessions.\n *\n * The Host's generated Remote methods bind the stock workspace-files service\n * before an instance adapter can replace them. The sidebar tree and document\n * preview therefore call this proxy, which asks the local plugin's host API to\n * resolve the mirror and read the remote workspace.\n *\n * @module dsh-remote-local/client/remote-files\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostsApi } from './api.ts'\n\ninterface RemoteFace {\n list(sessionId: string, path: string, signal: AbortSignal): Promise<unknown>\n read(sessionId: string, path: string, range: { offset?: number; limit?: number }, signal: AbortSignal): Promise<unknown>\n stat(sessionId: string, path: string, signal: AbortSignal): Promise<unknown>\n readBytes(sessionId: string, path: string, options: { range?: { offset?: number; length?: number }; baseFile?: string }, signal: AbortSignal): Promise<unknown>\n changes(sessionId: string, path: string, signal: AbortSignal): AsyncIterable<unknown>\n}\n\n/** Install the proxy on the client Remote face. */\nexport function installRemoteFiles(ctx: Context, api: HostsApi): void {\n const remote = ctx.remote as unknown as { workspaceFiles?: RemoteFace } | undefined\n const face = remote?.workspaceFiles\n if (face === undefined) return\n\n const original = {\n list: face.list.bind(face),\n read: face.read.bind(face),\n stat: face.stat.bind(face),\n readBytes: face.readBytes.bind(face),\n }\n\n face.list = async (sessionId, path, signal) => {\n const result = await api.fileList(sessionId, path)\n return result.mirrored ? { ok: true, value: result.value } : original.list(sessionId, path, signal)\n }\n face.read = async (sessionId, path, range, signal) => {\n const result = await api.fileRead(sessionId, path, range.offset, range.limit)\n return result.mirrored ? { ok: true, value: result.value } : original.read(sessionId, path, range, signal)\n }\n face.stat = async (sessionId, path, signal) => {\n const result = await api.fileStat(sessionId, path)\n return result.mirrored ? { ok: true, value: result.value } : original.stat(sessionId, path, signal)\n }\n face.readBytes = async (sessionId, path, options, signal) => {\n const result = await api.fileBytes(sessionId, path, options.range?.offset, options.range?.length)\n return result.mirrored ? { ok: true, value: result.value } : original.readBytes(sessionId, path, options, signal)\n }\n}\n", "/**\n * Client copy for the remote-development surfaces.\n *\n * The dictionaries are registered into DSH's locale service; `ctx.locale.bind`\n * follows the language selected in DSH. Settings components also receive the\n * framework `t` seat, so language switches re-render them.\n */\n\nexport const NS = 'dshRemote'\n\nexport const zh = {\n 'settings.title': '\u8FDC\u7A0B\u5F00\u53D1',\n 'settings.subtitle.lead': '\u53EA\u9700\u586B\u5199 SSH \u76EE\u6807\u3002\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5B89\u88C5\u5E76\u542F\u52A8\u8FDC\u7AEF agent\uFF0C\u5EFA\u7ACB\u96A7\u9053\u3002',\n 'settings.subtitle.body': '\u8FDE\u63A5\u540E\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u548C\u4F1A\u8BDD\u4F1A\u540C\u6B65\u5230\u5DE6\u4FA7\uFF0C\u50CF\u672C\u5730\u4F1A\u8BDD\u4E00\u6837\u6253\u5F00\uFF1B\u6A21\u578B\u51ED\u636E\u9ED8\u8BA4\u5199\u5165\u8FDC\u7AEF\u670D\u52A1\u73AF\u5883\uFF1B\u4E5F\u53EF\u542F\u7528\u672C\u5730\u4EE3\u7406\u6A21\u5F0F\u3002',\n 'settings.refresh': '\u5237\u65B0',\n 'settings.addHost': '\u6DFB\u52A0\u4E3B\u673A',\n 'settings.sshTarget': 'SSH \u76EE\u6807',\n 'settings.sshPlaceholder': 'user@host \u6216 ssh://user@host:22',\n 'settings.label': '\u663E\u793A\u540D\u79F0\uFF08\u53EF\u9009\uFF09',\n 'settings.labelPlaceholder': '\u53EF\u9009\uFF0C\u4F8B\u5982 \u5F00\u53D1\u673A',\n 'settings.saveConnect': '\u4FDD\u5B58\u5E76\u8FDE\u63A5',\n 'settings.adding': '\u6DFB\u52A0\u4E2D\u2026',\n 'settings.sshHint': '\u9700\u8981\u5BC6\u94A5\u6216 ssh-agent \u514D\u4EA4\u4E92\u767B\u5F55\uFF1B\u9996\u6B21\u81EA\u52A8\u5B89\u88C5\u7EA6 1\u20133 \u5206\u949F\u3002',\n 'settings.hosts': '\u4E3B\u673A',\n 'settings.hostsUnit': '\u53F0',\n 'settings.noHosts': '\u8FD8\u6CA1\u6709\u8FDC\u7A0B\u4E3B\u673A\u3002\u5148\u5728\u4E0A\u65B9\u6DFB\u52A0\u4E00\u53F0\u3002',\n 'settings.refreshFailed': '\u5237\u65B0\u5931\u8D25',\n 'settings.unavailable': '\u65E0\u6CD5\u8FDE\u63A5\u672C\u5730\u8FDC\u7A0B\u5BBF\u4E3B\u670D\u52A1',\n 'settings.operationFailed': '\u64CD\u4F5C\u5931\u8D25',\n 'settings.sshRequired': '\u8BF7\u586B\u5199 SSH \u76EE\u6807\uFF0C\u4F8B\u5982 user@host \u6216 ssh://user@host:22',\n 'settings.hostSaved': '\u4E3B\u673A\u5DF2\u4FDD\u5B58\u3002\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5B89\u88C5\u5E76\u542F\u52A8\u8FDC\u7AEF agent\uFF1B\u5B89\u88C5\u8FDB\u5EA6\u4F1A\u663E\u793A\u5728\u4E3B\u673A\u5361\u7247\u4E0A\u3002',\n 'settings.readWorkspacesFailed': '\u8BFB\u53D6\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'settings.readSessionsFailed': '\u8BFB\u53D6\u8FDC\u7AEF\u4F1A\u8BDD\u5931\u8D25',\n 'settings.pathRequired': '\u8BF7\u586B\u5199\u8FDC\u7AEF\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /home/user/project',\n 'settings.addWorkspaceFailed': '\u6DFB\u52A0\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'settings.sessionOpening': '\u8FDC\u7AEF\u4F1A\u8BDD\u5DF2\u521B\u5EFA\uFF0C\u6B63\u5728\u666E\u901A\u4F1A\u8BDD\u754C\u9762\u6253\u5F00\u2026',\n 'settings.sessionSyncing': '\u8FDC\u7AEF\u4F1A\u8BDD\u5DF2\u521B\u5EFA\uFF0C\u6B63\u5728\u540C\u6B65\u5230\u4FA7\u8FB9\u680F\u2026',\n 'settings.createSessionFailed': '\u521B\u5EFA\u8FDC\u7AEF\u4F1A\u8BDD\u5931\u8D25',\n 'settings.confirmRemovePrefix': '\u5220\u9664\u4E3B\u673A\u300C',\n 'settings.confirmRemoveSuffix': '\u300D\uFF1F\u8FDC\u7AEF\u6587\u4EF6\u4E0E\u4F1A\u8BDD\u4E0D\u4F1A\u88AB\u5220\u9664\u3002',\n 'settings.remotePort': '\u8FDC\u7AEF\u7AEF\u53E3',\n 'settings.localTunnel': '\u672C\u5730\u96A7\u9053',\n 'settings.workspaces': '\u5DE5\u4F5C\u533A',\n 'settings.token': 'Token',\n 'settings.saved': '\u5DF2\u4FDD\u5B58',\n 'settings.unsaved': '\u672A\u4FDD\u5B58',\n 'settings.modelProxy': '\u6A21\u578B\u4EE3\u7406',\n 'settings.localProxy': '\u672C\u5730\u4EE3\u7406',\n 'settings.direct': '\u8FDC\u7AEF\u76F4\u8FDE',\n 'settings.remoteDefault': '\u8FDC\u7AEF\u9ED8\u8BA4',\n 'settings.collapseWorkspaces': '\u6536\u8D77\u5DE5\u4F5C\u533A',\n 'settings.expandWorkspaces': '\u5DE5\u4F5C\u533A',\n 'settings.rediscover': '\u91CD\u65B0\u53D1\u73B0',\n 'settings.disconnect': '\u65AD\u5F00',\n 'settings.connect': '\u8FDE\u63A5',\n 'settings.installing': '\u6B63\u5728\u5B89\u88C5\u2026',\n 'settings.connecting': '\u6B63\u5728\u8FDE\u63A5\u2026',\n 'settings.reprovision': '\u91CD\u65B0\u5B89\u88C5',\n 'settings.remove': '\u5220\u9664',\n 'settings.workspacePathPlaceholder': '\u8FDC\u7AEF\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /home/user/project',\n 'settings.addWorkspace': '\u6DFB\u52A0\u5DE5\u4F5C\u533A',\n 'settings.addingWorkspace': '\u6DFB\u52A0\u4E2D\u2026',\n 'settings.readingWorkspaces': '\u6B63\u5728\u8BFB\u53D6\u5DE5\u4F5C\u533A\u2026',\n 'settings.noWorkspaces': '\u8FDC\u7AEF\u8FD8\u6CA1\u6709\u6CE8\u518C\u5DE5\u4F5C\u533A\u3002\u53EF\u5728\u8FDC\u7AEF DSH \u91CC\u6DFB\u52A0\u76EE\u5F55\u540E\u5237\u65B0\u3002',\n 'settings.sessionsUnit': '\u4E2A\u4F1A\u8BDD',\n 'settings.newSession': '+ \u65B0\u4F1A\u8BDD',\n 'settings.creating': '\u521B\u5EFA\u4E2D\u2026',\n 'settings.readingSessions': '\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u2026',\n 'settings.noSessions': '\u8BE5\u5DE5\u4F5C\u533A\u6682\u65E0\u4F1A\u8BDD\u3002\u70B9\u201C+ \u65B0\u4F1A\u8BDD\u201D\u5F00\u59CB\u3002',\n 'settings.eventsUnit': '\u4E8B\u4EF6',\n 'phase.idle': '\u672A\u8FDE\u63A5',\n 'phase.discovering': '\u53D1\u73B0\u4E2D',\n 'phase.installing': '\u5B89\u88C5\u4E2D',\n 'phase.connecting': '\u8FDE\u63A5\u4E2D',\n 'phase.connected': '\u5DF2\u8FDE\u63A5',\n 'phase.disconnected': '\u5DF2\u65AD\u5F00',\n 'phase.error': '\u5F02\u5E38',\n 'detail.discovering': '\u6B63\u5728\u901A\u8FC7 SSH \u53D1\u73B0\u8FDC\u7AEF agent\u2026',\n 'detail.installing': '\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5 DSH \u4E0E dsh-remote-agent\uFF0C\u9996\u6B21\u7EA6 1\u20133 \u5206\u949F\u2026',\n 'detail.connecting': '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u5E76\u6821\u9A8C\u8FDC\u7AEF agent\u2026',\n 'detail.reprovisioning': '\u6B63\u5728\u91CD\u65B0\u5B89\u88C5\u8FDC\u7AEF agent\u2026',\n 'detail.reconnecting': 'SSH \u96A7\u9053\u65AD\u5F00\uFF0C\u7B49\u5F85\u91CD\u8FDE\u2026',\n 'detail.connectedProxy': '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7ECF\u672C\u5730\u51ED\u636E\u4EE3\u7406\u8F6C\u53D1',\n 'detail.connectedDirect': '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7531\u8FDC\u7AEF\u76F4\u8FDE DeepSeek',\n 'detail.connectedRemote': '\u5DF2\u8FDE\u63A5\uFF1B\u8FDC\u7AEF\u4F7F\u7528\u81EA\u8EAB\u51ED\u636E\u6216\u672A\u914D\u7F6E\u6A21\u578B key',\n 'detail.preparing': '\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026',\n 'detail.uploadingAgent': '\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026',\n 'detail.uploaded': '\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026',\n 'detail.nodeDownloading': '\u6B63\u5728\u4E0B\u8F7D Node.js\u2026',\n 'detail.nodeInstalled': 'Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026',\n 'detail.nodeReady': 'Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026',\n 'detail.pnpmInstalling': '\u6B63\u5728\u5B89\u88C5 pnpm\u2026',\n 'detail.dshInstalling': '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF DSH\uFF08\u4E0B\u8F7D\u4F9D\u8D56\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF09\u2026',\n 'detail.agentInstalling': '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF agent\u2026',\n 'detail.webStarting': '\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026',\n 'detail.waitingState': '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u6587\u4EF6\u2026',\n 'detail.waitingAgent': '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u2026',\n 'detail.agentReady': '\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026',\n 'detail.installed': '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\u2026',\n 'detail.waitingWeb': '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u6B63\u5728\u7B49\u5F85 DSH web \u542F\u52A8\u2026',\n 'detail.stillWaiting': '\u4ECD\u5728\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026',\n 'detail.readingState': '\u6B63\u5728\u8BFB\u53D6\u8FDC\u7AEF agent \u72B6\u6001\u2026',\n 'detail.tunnel': '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u2026',\n 'detail.checkingAgent': '\u6B63\u5728\u6821\u9A8C\u8FDC\u7AEF agent\u2026',\n 'detail.reconcilingModel': '\u6B63\u5728\u540C\u6B65\u8FDC\u7AEF\u6A21\u578B\u73AF\u5883\u2026',\n 'dialog.title': '\u65B0\u5EFA\u5DE5\u4F5C\u533A',\n 'dialog.close': '\u5173\u95ED',\n 'dialog.name': '\u5DE5\u4F5C\u533A\u540D\u79F0',\n 'dialog.namePlaceholder': '\u5DE5\u4F5C\u533A\u540D\u79F0\uFF08\u53EF\u9009\uFF09',\n 'dialog.source': '\u6E90\u76EE\u5F55',\n 'dialog.addToPrefix': '\u5C06\u76EE\u5F55\u6DFB\u52A0\u5230 ',\n 'dialog.addToSuffix': '',\n 'dialog.add': '\u6DFB\u52A0',\n 'dialog.local': '\u672C\u673A',\n 'dialog.remoteDevices': '\u8FDC\u7AEF\u8BBE\u5907',\n 'dialog.addRemote': '+ \u6DFB\u52A0\u8FDC\u7AEF\u2026',\n 'dialog.addRemoteHint': '\u8BF7\u5148\u5728 Settings \u2192 \u8FDC\u7A0B\u5F00\u53D1 \u6DFB\u52A0\u5E76\u8FDE\u63A5\u8FDC\u7AEF\u4E3B\u673A\u3002',\n 'dialog.cancel': '\u53D6\u6D88',\n 'dialog.create': '\u521B\u5EFA\u5DE5\u4F5C\u533A',\n 'dialog.creating': '\u521B\u5EFA\u4E2D\u2026',\n 'dialog.createFailed': '\u65B0\u5EFA\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'dialog.removeFolder': '\u79FB\u9664\u76EE\u5F55',\n 'dialog.selectedFallback': '\u8FDC\u7AEF workspace \u5DF2\u521B\u5EFA\uFF0C\u4F46\u672C\u5730\u955C\u50CF\u8FD8\u6CA1\u6709\u540C\u6B65\u5B8C\u6210',\n 'dialog.folderTitle': '\u9009\u62E9\u6E90\u76EE\u5F55',\n 'dialog.up': '\u4E0A\u4E00\u7EA7',\n 'dialog.selectFolder': '\u9009\u62E9\u5F53\u524D\u76EE\u5F55',\n 'dialog.reading': '\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026',\n 'dialog.emptyFolder': '\u6B64\u76EE\u5F55\u6CA1\u6709\u5B50\u76EE\u5F55',\n 'dialog.readFailed': '\u8BFB\u53D6\u76EE\u5F55\u5931\u8D25',\n 'dialog.nativePickerFailed': '\u65E0\u6CD5\u6253\u5F00\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9\u5668',\n 'dialog.useFolder': '\u4F7F\u7528\u6B64\u76EE\u5F55',\n} as const\n\nexport type CopyKey = keyof typeof zh\n\nexport const en: Record<CopyKey, string> = {\n 'settings.title': 'Remote development',\n 'settings.subtitle.lead': 'Enter an SSH target. The plugin installs and starts the remote agent and opens a tunnel.',\n 'settings.subtitle.body': 'Remote workspaces and sessions sync into the normal sidebar and open like local sessions. The model key is written into the remote service environment by default; local proxying remains optional.',\n 'settings.refresh': 'Refresh',\n 'settings.addHost': 'Add host',\n 'settings.sshTarget': 'SSH target',\n 'settings.sshPlaceholder': 'user@host or ssh://user@host:22',\n 'settings.label': 'Display name (optional)',\n 'settings.labelPlaceholder': 'Optional, e.g. dev box',\n 'settings.saveConnect': 'Save and connect',\n 'settings.adding': 'Adding\u2026',\n 'settings.sshHint': 'Requires key or ssh-agent authentication. First install takes about 1\u20133 minutes.',\n 'settings.hosts': 'Hosts',\n 'settings.hostsUnit': '',\n 'settings.noHosts': 'No remote hosts yet. Add one above.',\n 'settings.refreshFailed': 'Refresh failed',\n 'settings.unavailable': 'Cannot reach the local remote-host service',\n 'settings.operationFailed': 'Operation failed',\n 'settings.sshRequired': 'Enter an SSH target, e.g. user@host or ssh://user@host:22',\n 'settings.hostSaved': 'Host saved. The plugin will install and start the remote agent; progress appears on the host card.',\n 'settings.readWorkspacesFailed': 'Could not read remote workspaces',\n 'settings.readSessionsFailed': 'Could not read remote sessions',\n 'settings.pathRequired': 'Enter an absolute remote directory, e.g. /home/user/project',\n 'settings.addWorkspaceFailed': 'Could not add the remote workspace',\n 'settings.sessionOpening': 'Remote session created; opening it in the conversation view\u2026',\n 'settings.sessionSyncing': 'Remote session created; syncing it into the sidebar\u2026',\n 'settings.createSessionFailed': 'Could not create the remote session',\n 'settings.confirmRemovePrefix': 'Remove host \"',\n 'settings.confirmRemoveSuffix': '\"? Remote files and sessions are not deleted.',\n 'settings.remotePort': 'Remote port',\n 'settings.localTunnel': 'Local tunnel',\n 'settings.workspaces': 'Workspaces',\n 'settings.token': 'Token',\n 'settings.saved': 'Saved',\n 'settings.unsaved': 'Not saved',\n 'settings.modelProxy': 'Model credentials',\n 'settings.localProxy': 'Local proxy',\n 'settings.direct': 'Remote direct',\n 'settings.remoteDefault': 'Remote default',\n 'settings.collapseWorkspaces': 'Hide workspaces',\n 'settings.expandWorkspaces': 'Workspaces',\n 'settings.rediscover': 'Rediscover',\n 'settings.disconnect': 'Disconnect',\n 'settings.connect': 'Connect',\n 'settings.installing': 'Installing\u2026',\n 'settings.connecting': 'Connecting\u2026',\n 'settings.reprovision': 'Reinstall',\n 'settings.remove': 'Remove',\n 'settings.workspacePathPlaceholder': 'Absolute remote path, e.g. /home/user/project',\n 'settings.addWorkspace': 'Add workspace',\n 'settings.addingWorkspace': 'Adding\u2026',\n 'settings.readingWorkspaces': 'Reading workspaces\u2026',\n 'settings.noWorkspaces': 'No remote workspaces registered yet. Add a directory in the remote DSH, then refresh.',\n 'settings.sessionsUnit': 'sessions',\n 'settings.newSession': '+ New session',\n 'settings.creating': 'Creating\u2026',\n 'settings.readingSessions': 'Reading sessions\u2026',\n 'settings.noSessions': 'No sessions in this workspace. Start one with \u201C+ New session\u201D.',\n 'settings.eventsUnit': 'events',\n 'phase.idle': 'Idle',\n 'phase.discovering': 'Discovering',\n 'phase.installing': 'Installing',\n 'phase.connecting': 'Connecting',\n 'phase.connected': 'Connected',\n 'phase.disconnected': 'Disconnected',\n 'phase.error': 'Error',\n 'detail.discovering': 'Discovering the remote agent over SSH\u2026',\n 'detail.installing': 'Installing DSH and dsh-remote-agent remotely; this takes about 1\u20133 minutes\u2026',\n 'detail.connecting': 'Opening the SSH tunnel and checking the remote agent\u2026',\n 'detail.reprovisioning': 'Reinstalling the remote agent\u2026',\n 'detail.reconnecting': 'SSH tunnel closed; waiting to reconnect\u2026',\n 'detail.connectedProxy': 'Connected; model requests go through the local credential proxy',\n 'detail.connectedDirect': 'Connected; the remote host calls DeepSeek directly',\n 'detail.connectedRemote': 'Connected; the remote host uses its own credentials or has no model key',\n 'detail.preparing': 'Preparing the remote installation environment\u2026',\n 'detail.uploadingAgent': 'Uploading the remote agent package\u2026',\n 'detail.uploaded': 'Package uploaded; starting the remote installation\u2026',\n 'detail.nodeDownloading': 'Downloading Node.js\u2026',\n 'detail.nodeInstalled': 'Node.js installed; continuing with pnpm/DSH\u2026',\n 'detail.nodeReady': 'Node.js is ready; preparing pnpm/DSH\u2026',\n 'detail.pnpmInstalling': 'Installing pnpm\u2026',\n 'detail.dshInstalling': 'Installing remote DSH (dependency download may take several minutes)\u2026',\n 'detail.agentInstalling': 'Installing the remote agent\u2026',\n 'detail.webStarting': 'Starting the remote DSH Web service\u2026',\n 'detail.waitingState': 'Waiting for the remote agent state file\u2026',\n 'detail.waitingAgent': 'Waiting for the remote agent\u2026',\n 'detail.agentReady': 'Remote agent is ready; establishing the connection\u2026',\n 'detail.installed': 'Remote installation complete\u2026',\n 'detail.waitingWeb': 'Remote installation complete; waiting for DSH Web\u2026',\n 'detail.stillWaiting': 'Still waiting for remote DSH Web\u2026',\n 'detail.readingState': 'Reading the remote agent state\u2026',\n 'detail.tunnel': 'Establishing the SSH tunnel\u2026',\n 'detail.checkingAgent': 'Checking the remote agent\u2026',\n 'detail.reconcilingModel': 'Synchronizing the remote model environment\u2026',\n 'dialog.title': 'New workspace',\n 'dialog.close': 'Close',\n 'dialog.name': 'Workspace name',\n 'dialog.namePlaceholder': 'Workspace name (optional)',\n 'dialog.source': 'Source folder',\n 'dialog.addToPrefix': 'Add a folder on ',\n 'dialog.addToSuffix': '',\n 'dialog.add': 'Add',\n 'dialog.local': 'This computer',\n 'dialog.remoteDevices': 'Remote devices',\n 'dialog.addRemote': '+ Add remote\u2026',\n 'dialog.addRemoteHint': 'Add and connect a remote host in Settings \u2192 Remote development first.',\n 'dialog.cancel': 'Cancel',\n 'dialog.create': 'Create workspace',\n 'dialog.creating': 'Creating\u2026',\n 'dialog.createFailed': 'Could not create the workspace',\n 'dialog.removeFolder': 'Remove folder',\n 'dialog.selectedFallback': 'The remote workspace was created, but the local mirror has not synced yet',\n 'dialog.folderTitle': 'Choose a source folder',\n 'dialog.up': 'Parent folder',\n 'dialog.selectFolder': 'Select current folder',\n 'dialog.reading': 'Reading folder\u2026',\n 'dialog.emptyFolder': 'No subfolders here',\n 'dialog.readFailed': 'Could not read the folder',\n 'dialog.nativePickerFailed': 'Could not open the system folder picker',\n 'dialog.useFolder': 'Use folder',\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n dshRemote: CopyKey\n }\n}\n\nexport type Translate = (key: CopyKey) => string\n\nexport interface LocaleFace {\n register(namespace: string, dictionaries: { zh: Record<string, string>; en: Record<string, string> }): () => void\n bind(namespace: string): Translate\n}\n", "/**\n * Codex-style unified workspace creation dialog for the sidebar + button.\n *\n * One modal owns the destination (local or a connected remote host), the\n * optional workspace name, and the source folder browser. It is intentionally\n * not a separate local/remote menu.\n *\n * @module dsh-remote-local/client/workspace-add\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostView } from '../hosts/types.ts'\nimport type { HostsApi } from './api.ts'\nimport type { Translate } from './locale.ts'\n\nconst ADD_LABELS = new Set(['Add workspace', '\u6DFB\u52A0\u5DE5\u4F5C\u533A'])\nconst NATIVE_CLICK_FLAG = 'dshrNativeClick'\nconst DIALOG_CLASS = 'dshr-workspace-add-dialog'\nlet closeDialog: (() => void) | undefined\nlet closeBrowser: (() => void) | undefined\nlet closeMenu: (() => void) | undefined\n\ninterface WorkspaceFlowContext {\n readonly ctx: Context\n readonly api: HostsApi\n readonly t: Translate\n}\n\ntype Destination = { readonly kind: 'local' } | { readonly kind: 'remote'; readonly host: HostView }\n\ninterface HostDirectoryPicker {\n pick(): Promise<\n | { readonly ok: true; readonly value: string | null }\n | { readonly ok: false; readonly error: { readonly message: string } }\n >\n}\n\ninterface DesktopDirectoryPicker {\n pick(): Promise<string | null>\n}\n\nasync function pickLocalDirectory(ctx: Context): Promise<string | null> {\n // DSH Desktop installs this bridge before the client mounts; the stock\n // native directory-flow plugin uses exactly the same entry point.\n const desktop = (globalThis as unknown as { __DSH_DIRECTORY_PICKER__?: DesktopDirectoryPicker }).__DSH_DIRECTORY_PICKER__\n if (desktop !== undefined) return desktop.pick()\n const uiWorkspace = (ctx as unknown as { uiWorkspace?: { pickDirectory?: () => Promise<string | null> } }).uiWorkspace\n if (uiWorkspace?.pickDirectory !== undefined) return uiWorkspace.pickDirectory()\n const remote = (ctx as unknown as { remote?: { directoryPicker?: HostDirectoryPicker } }).remote\n if (remote?.directoryPicker === undefined) throw new Error('directory picker is unavailable')\n const result = await remote.directoryPicker.pick()\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\ninterface DirectoryListing {\n readonly path: string\n readonly parent: string\n readonly entries: readonly { readonly name: string; readonly path: string }[]\n readonly truncated: boolean\n}\n\n/** Install the sidebar add-workspace dialog once per client mount. */\nexport function installWorkspaceAddMenu(ctx: Context, api: HostsApi, t: Translate): void {\n if (typeof document === 'undefined') return\n ensureStyles()\n\n ctx.effect(() => {\n const onClick = (event: MouseEvent): void => {\n const target = event.target\n if (!(target instanceof Element)) return\n const button = target.closest<HTMLButtonElement>('button[aria-label]')\n if (button === null) return\n const label = button.getAttribute('aria-label') ?? ''\n if (!ADD_LABELS.has(label)) return\n if (button.closest('[class*=\"headerActions\"]') === null) return\n if (button.dataset[NATIVE_CLICK_FLAG] === '1') {\n delete button.dataset[NATIVE_CLICK_FLAG]\n return\n }\n event.preventDefault()\n event.stopImmediatePropagation()\n void openCreateDialog({ ctx, api, t }, button)\n }\n document.addEventListener('click', onClick, true)\n return () => {\n document.removeEventListener('click', onClick, true)\n closeTransient()\n }\n }, 'dsh-remote: workspace add dialog')\n}\n\nasync function openCreateDialog(flow: WorkspaceFlowContext, anchor: HTMLButtonElement): Promise<void> {\n closeTransient()\n const overlay = document.createElement('div')\n overlay.className = `${DIALOG_CLASS}-overlay`\n overlay.setAttribute('role', 'presentation')\n const dialog = document.createElement('div')\n dialog.className = DIALOG_CLASS\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('aria-label', flow.t('dialog.title'))\n\n const title = document.createElement('h2')\n title.className = `${DIALOG_CLASS}-title`\n title.textContent = flow.t('dialog.title')\n const header = document.createElement('div')\n header.className = `${DIALOG_CLASS}-header`\n const closeButton = document.createElement('button')\n closeButton.type = 'button'\n closeButton.className = `${DIALOG_CLASS}-close`\n closeButton.setAttribute('aria-label', flow.t('dialog.close'))\n closeButton.textContent = '\u00D7'\n header.append(title, closeButton)\n\n const nameLabel = document.createElement('label')\n nameLabel.className = `${DIALOG_CLASS}-field`\n const nameText = document.createElement('span')\n nameText.textContent = flow.t('dialog.name')\n const nameRow = document.createElement('div')\n nameRow.className = `${DIALOG_CLASS}-input-row`\n const nameIcon = document.createElement('span')\n nameIcon.className = `${DIALOG_CLASS}-input-icon`\n setFolderIcon(nameIcon)\n const nameInput = document.createElement('input')\n nameInput.className = `${DIALOG_CLASS}-input`\n nameInput.placeholder = flow.t('dialog.namePlaceholder')\n nameInput.autocomplete = 'off'\n nameRow.append(nameIcon, nameInput)\n nameLabel.append(nameText, nameRow)\n\n const sourceTitle = document.createElement('h3')\n sourceTitle.className = `${DIALOG_CLASS}-section-title`\n sourceTitle.textContent = flow.t('dialog.source')\n const sourceHeader = document.createElement('div')\n sourceHeader.className = `${DIALOG_CLASS}-source-header`\n const hostIndicator = document.createElement('span')\n hostIndicator.className = `${DIALOG_CLASS}-host-indicator`\n const hostIcon = document.createElement('span')\n hostIcon.className = `${DIALOG_CLASS}-host-icon`\n setComputerIcon(hostIcon)\n const hostLabelText = document.createElement('span')\n hostIndicator.append(hostIcon, hostLabelText)\n sourceHeader.append(sourceTitle, hostIndicator)\n const sourceBox = document.createElement('div')\n sourceBox.className = `${DIALOG_CLASS}-source-box`\n const sourceCenter = document.createElement('div')\n sourceCenter.className = `${DIALOG_CLASS}-source-center`\n const sourceTrigger = document.createElement('button')\n sourceTrigger.type = 'button'\n sourceTrigger.className = `${DIALOG_CLASS}-source-trigger`\n const sourceTriggerText = document.createElement('span')\n const sourceChevron = document.createElement('span')\n sourceChevron.className = `${DIALOG_CLASS}-chevron`\n sourceChevron.textContent = '\u2304'\n sourceTrigger.append(sourceTriggerText, sourceChevron)\n const addFolder = document.createElement('button')\n addFolder.type = 'button'\n addFolder.className = `${DIALOG_CLASS}-add-folder`\n const addFolderIcon = document.createElement('span')\n addFolderIcon.className = `${DIALOG_CLASS}-add-folder-icon`\n const addFolderText = document.createElement('span')\n addFolderText.textContent = flow.t('dialog.add')\n addFolder.append(addFolderIcon, addFolderText)\n sourceCenter.append(sourceTrigger, addFolder)\n const selectedFolder = document.createElement('div')\n selectedFolder.className = `${DIALOG_CLASS}-selected-folder`\n const selectedIcon = document.createElement('span')\n selectedIcon.textContent = '\uD83D\uDCC1'\n const selectedName = document.createElement('span')\n selectedName.className = `${DIALOG_CLASS}-selected-name`\n const removeFolder = document.createElement('button')\n removeFolder.type = 'button'\n removeFolder.className = `${DIALOG_CLASS}-remove-folder`\n removeFolder.setAttribute('aria-label', flow.t('dialog.removeFolder'))\n removeFolder.textContent = '\u00D7'\n selectedFolder.append(selectedIcon, selectedName, removeFolder)\n sourceBox.append(sourceCenter, selectedFolder)\n\n const error = document.createElement('p')\n error.className = `${DIALOG_CLASS}-error`\n error.setAttribute('role', 'alert')\n\n const actions = document.createElement('div')\n actions.className = `${DIALOG_CLASS}-actions`\n const cancel = document.createElement('button')\n cancel.type = 'button'\n cancel.className = `${DIALOG_CLASS}-button`\n cancel.textContent = flow.t('dialog.cancel')\n const create = document.createElement('button')\n create.type = 'button'\n create.className = `${DIALOG_CLASS}-button ${DIALOG_CLASS}-primary`\n create.textContent = flow.t('dialog.create')\n actions.append(cancel, create)\n\n dialog.append(header, nameLabel, sourceHeader, sourceBox, error, actions)\n overlay.append(dialog)\n document.body.append(overlay)\n\n let hosts: HostView[] = []\n let destination: Destination = { kind: 'local' }\n let selectedPath = ''\n const update = (): void => {\n const label = destination.kind === 'local' ? flow.t('dialog.local') : destination.host.label\n sourceTriggerText.textContent = `${flow.t('dialog.addToPrefix')}${label}${flow.t('dialog.addToSuffix')}`\n hostLabelText.textContent = label\n addFolderIcon.textContent = '+ '\n const hasFolder = selectedPath !== ''\n sourceCenter.style.display = hasFolder ? 'none' : 'flex'\n selectedFolder.style.display = hasFolder ? 'flex' : 'none'\n sourceBox.classList.toggle(`${DIALOG_CLASS}-source-box-selected`, hasFolder)\n selectedName.textContent = hasFolder ? folderName(selectedPath) : ''\n selectedFolder.title = hasFolder ? selectedPath : ''\n create.disabled = !hasFolder\n }\n const close = (): void => {\n closeBrowser?.()\n closeMenu?.()\n overlay.remove()\n window.removeEventListener('keydown', keyHandler, true)\n overlay.removeEventListener('pointerdown', outside, true)\n if (closeDialog === close) closeDialog = undefined\n }\n closeDialog = close\n const keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n const outside = (event: Event): void => {\n if (event.target === overlay) close()\n }\n window.addEventListener('keydown', keyHandler, true)\n overlay.addEventListener('pointerdown', outside, true)\n cancel.addEventListener('click', close)\n closeButton.addEventListener('click', close)\n\n sourceTrigger.addEventListener('click', () => {\n openDestinationMenu(sourceTrigger, hosts, destination, flow.t, next => {\n destination = next\n selectedPath = ''\n update()\n })\n })\n addFolder.addEventListener('click', () => {\n if (destination.kind === 'local') {\n addFolder.disabled = true\n void pickLocalDirectory(flow.ctx)\n .then(path => {\n if (path !== null) {\n selectedPath = path\n update()\n }\n })\n .catch(failure => { error.textContent = messageOf(failure, flow.t('dialog.nativePickerFailed')) })\n .finally(() => { addFolder.disabled = false })\n return\n }\n const initial = destination.host.hostInfo?.home ?? '~'\n openDirectoryBrowser(flow, destination, initial, path => {\n selectedPath = path\n update()\n })\n })\n removeFolder.addEventListener('click', () => {\n selectedPath = ''\n update()\n })\n nameInput.addEventListener('input', update)\n\n try {\n const state = await flow.api.state()\n hosts = state.hosts.filter(host => host.phase === 'connected')\n } catch {\n hosts = []\n }\n update()\n create.addEventListener('click', () => {\n if (selectedPath === '') return\n const title = nameInput.value.trim() || folderName(selectedPath)\n create.disabled = true\n cancel.disabled = true\n create.textContent = flow.t('dialog.creating')\n void (async () => {\n try {\n if (destination.kind === 'local') {\n const local = await flow.api.createLocalWorkspace({ path: selectedPath, title })\n close()\n flow.ctx.uiWorkspace.startSession(local.workspaceId as never)\n return\n }\n const workspace = await flow.api.createWorkspace(destination.host.id, {\n path: selectedPath,\n title,\n })\n const session = await flow.api.createSession(destination.host.id, {\n workspaceId: workspace.workspaceId,\n })\n if (session.localSessionId !== undefined) {\n close()\n flow.api.openSession(session.localSessionId)\n return\n }\n const localId = await waitForLocalWorkspace(flow.api, destination.host.id, workspace.workspaceId)\n if (localId === undefined) throw new Error(flow.t('dialog.selectedFallback'))\n close()\n flow.ctx.uiWorkspace.startSession(localId as never)\n } catch (failure) {\n error.textContent = messageOf(failure, flow.t('dialog.createFailed'))\n create.disabled = false\n cancel.disabled = false\n create.textContent = flow.t('dialog.create')\n }\n })()\n })\n\n nameInput.focus()\n}\n\nfunction openDestinationMenu(\n anchor: HTMLElement,\n hosts: readonly HostView[],\n current: Destination,\n t: Translate,\n onPick: (destination: Destination) => void,\n): void {\n closeMenu?.()\n const menu = document.createElement('div')\n menu.className = `${DIALOG_CLASS}-destination-menu`\n const add = (label: string, destination: Destination): void => {\n const item = document.createElement('button')\n item.type = 'button'\n item.className = `${DIALOG_CLASS}-destination-item`\n const text = document.createElement('span')\n text.textContent = label\n const check = document.createElement('span')\n check.className = `${DIALOG_CLASS}-destination-check`\n const selected = current.kind === destination.kind\n && (destination.kind === 'local' || (current.kind === 'remote' && current.host.id === destination.host.id))\n check.textContent = selected ? '\u2713' : ''\n item.append(text, check)\n item.addEventListener('click', () => {\n onPick(destination)\n close()\n })\n menu.append(item)\n }\n add(t('dialog.local'), { kind: 'local' })\n if (hosts.length > 0) {\n const section = document.createElement('div')\n section.className = `${DIALOG_CLASS}-destination-section`\n section.textContent = t('dialog.remoteDevices')\n menu.append(section)\n for (const host of hosts) add(host.label, { kind: 'remote', host })\n }\n const addRemote = document.createElement('button')\n addRemote.type = 'button'\n addRemote.className = `${DIALOG_CLASS}-destination-item ${DIALOG_CLASS}-destination-add`\n addRemote.textContent = t('dialog.addRemote')\n addRemote.addEventListener('click', () => {\n close()\n const error = document.querySelector(`.${DIALOG_CLASS}-error`)\n if (error !== null) error.textContent = t('dialog.addRemoteHint')\n })\n menu.append(addRemote)\n document.body.append(menu)\n const rect = anchor.getBoundingClientRect()\n menu.style.left = `${Math.min(rect.left, window.innerWidth - 260)}px`\n menu.style.top = `${rect.bottom + 6}px`\n const close = (): void => {\n menu.remove()\n window.removeEventListener('pointerdown', dismiss, true)\n if (closeMenu === close) closeMenu = undefined\n }\n closeMenu = close\n const dismiss = (event: Event): void => {\n if (event.target instanceof Node && menu.contains(event.target)) return\n close()\n }\n window.addEventListener('pointerdown', dismiss, true)\n}\n\nasync function openDirectoryBrowser(\n flow: WorkspaceFlowContext,\n destination: Destination,\n initialPath: string,\n onPick: (path: string) => void,\n): Promise<void> {\n closeBrowser?.()\n const overlay = document.createElement('div')\n overlay.className = `${DIALOG_CLASS}-browser-overlay`\n overlay.setAttribute('role', 'presentation')\n const dialog = document.createElement('div')\n dialog.className = `${DIALOG_CLASS} ${DIALOG_CLASS}-browser`\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('aria-label', flow.t('dialog.folderTitle'))\n\n const title = document.createElement('h2')\n title.className = `${DIALOG_CLASS}-browser-title`\n title.textContent = flow.t('dialog.folderTitle')\n const browserHeader = document.createElement('div')\n browserHeader.className = `${DIALOG_CLASS}-browser-header`\n const browserClose = document.createElement('button')\n browserClose.type = 'button'\n browserClose.className = `${DIALOG_CLASS}-close`\n browserClose.setAttribute('aria-label', flow.t('dialog.close'))\n browserClose.textContent = '\u00D7'\n browserHeader.append(title, browserClose)\n const pathRow = document.createElement('div')\n pathRow.className = `${DIALOG_CLASS}-browser-path-row`\n const up = document.createElement('button')\n up.type = 'button'\n up.className = `${DIALOG_CLASS}-up`\n up.textContent = '\u2191'\n up.setAttribute('aria-label', flow.t('dialog.up'))\n const pathInput = document.createElement('input')\n pathInput.className = `${DIALOG_CLASS}-browser-path`\n pathInput.value = initialPath\n pathInput.autocomplete = 'off'\n pathRow.append(up, pathInput)\n const status = document.createElement('p')\n status.className = `${DIALOG_CLASS}-browser-status`\n status.textContent = flow.t('dialog.selectFolder')\n const list = document.createElement('div')\n list.className = `${DIALOG_CLASS}-browser-list`\n const actions = document.createElement('div')\n actions.className = `${DIALOG_CLASS}-actions`\n const cancel = document.createElement('button')\n cancel.type = 'button'\n cancel.className = `${DIALOG_CLASS}-button`\n cancel.textContent = flow.t('dialog.cancel')\n const use = document.createElement('button')\n use.type = 'button'\n use.className = `${DIALOG_CLASS}-button ${DIALOG_CLASS}-primary`\n use.textContent = flow.t('dialog.useFolder')\n actions.append(cancel, use)\n dialog.append(browserHeader, pathRow, status, list, actions)\n overlay.append(dialog)\n document.body.append(overlay)\n\n let current = initialPath\n let parent = initialPath\n let currentEntries: readonly { readonly name: string; readonly path: string }[] = []\n let requestSeq = 0\n let filterTimer: number | undefined\n\n const fetchListing = async (path: string): Promise<DirectoryListing | undefined> => {\n const sequence = ++requestSeq\n status.textContent = flow.t('dialog.reading')\n status.classList.remove(`${DIALOG_CLASS}-error-text`)\n try {\n const listing: DirectoryListing = destination.kind === 'local'\n ? await flow.api.listLocalDirectories(path)\n : await flow.api.listDirectories(destination.host.id, path)\n if (sequence !== requestSeq) return undefined\n return listing\n } catch (failure) {\n if (sequence === requestSeq) {\n status.textContent = messageOf(failure, flow.t('dialog.readFailed'))\n status.classList.add(`${DIALOG_CLASS}-error-text`)\n }\n return undefined\n }\n }\n\n const render = (entries: readonly { readonly name: string; readonly path: string }[]): void => {\n list.replaceChildren()\n if (entries.length === 0) {\n const empty = document.createElement('p')\n empty.className = `${DIALOG_CLASS}-browser-empty`\n empty.textContent = flow.t('dialog.emptyFolder')\n list.append(empty)\n return\n }\n for (const entry of entries) {\n const item = document.createElement('button')\n item.type = 'button'\n item.className = `${DIALOG_CLASS}-browser-entry`\n const icon = document.createElement('span')\n icon.textContent = '\uD83D\uDCC1'\n const label = document.createElement('span')\n label.textContent = entry.name\n item.append(icon, label)\n item.addEventListener('click', () => { void load(entry.path) })\n list.append(item)\n }\n }\n\n const load = async (path: string): Promise<void> => {\n const listing = await fetchListing(path)\n if (listing === undefined) return\n current = listing.path\n parent = listing.parent\n currentEntries = listing.entries\n pathInput.value = listing.path\n status.textContent = flow.t('dialog.selectFolder')\n render(listing.entries)\n }\n\n const applyInputFilter = async (raw: string): Promise<void> => {\n if (raw === '') return\n const slash = raw.lastIndexOf('/')\n const dir = slash < 0 ? current : (raw.slice(0, slash + 1) || '/')\n const query = slash < 0 ? raw : raw.slice(slash + 1)\n if (query === '') {\n // A trailing slash is an explicit directory navigation.\n await load(raw)\n return\n }\n const normalizedCurrent = current.replace(/\\/+$/u, '') || '/'\n const normalizedDir = dir.replace(/\\/+$/u, '') || '/'\n if (normalizedDir === normalizedCurrent) {\n const needle = query.toLocaleLowerCase()\n render(currentEntries.filter(entry => entry.name.toLocaleLowerCase().startsWith(needle)))\n status.textContent = flow.t('dialog.selectFolder')\n return\n }\n const listing = await fetchListing(dir)\n if (listing === undefined) return\n current = listing.path\n parent = listing.parent\n currentEntries = listing.entries\n const needle = query.toLocaleLowerCase()\n render(listing.entries.filter(entry => entry.name.toLocaleLowerCase().startsWith(needle)))\n status.textContent = flow.t('dialog.selectFolder')\n }\n\n const close = (): void => {\n overlay.remove()\n window.removeEventListener('keydown', keyHandler, true)\n overlay.removeEventListener('pointerdown', outside, true)\n if (closeBrowser === close) closeBrowser = undefined\n }\n closeBrowser = close\n const keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n const outside = (event: Event): void => {\n if (event.target === overlay) close()\n }\n window.addEventListener('keydown', keyHandler, true)\n overlay.addEventListener('pointerdown', outside, true)\n cancel.addEventListener('click', close)\n browserClose.addEventListener('click', close)\n use.addEventListener('click', () => {\n onPick(current)\n close()\n })\n up.addEventListener('click', () => {\n if (parent !== '' && parent !== current) void load(parent)\n })\n pathInput.addEventListener('input', () => {\n if (filterTimer !== undefined) window.clearTimeout(filterTimer)\n const value = pathInput.value\n filterTimer = window.setTimeout(() => { void applyInputFilter(value) }, 140)\n })\n pathInput.addEventListener('keydown', event => {\n if (event.key !== 'Enter') return\n event.preventDefault()\n const value = pathInput.value.trim()\n if (value !== '') void applyInputFilter(value)\n })\n void load(initialPath)\n}\n\nasync function waitForLocalWorkspace(api: HostsApi, hostId: string, workspaceId: string): Promise<string | undefined> {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n const result = await api.workspaces(hostId)\n const workspace = result.workspaces.find(item => item.workspaceId === workspaceId)\n if (workspace?.localWorkspaceId !== undefined) return workspace.localWorkspaceId\n await new Promise(resolve => setTimeout(resolve, 500))\n }\n return undefined\n}\n\nfunction closeTransient(): void {\n closeDialog?.()\n closeBrowser?.()\n closeMenu?.()\n}\n\nfunction messageOf(failure: unknown, fallback: string): string {\n if (failure instanceof Error && failure.message !== '') return failure.message\n return fallback\n}\n\nfunction setFolderIcon(icon: HTMLElement): void {\n icon.innerHTML = '<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M3.5 7.5A2.5 2.5 0 0 1 6 5h4l2 2h6a2.5 2.5 0 0 1 2.5 2.5v7A2.5 2.5 0 0 1 18 19H6a2.5 2.5 0 0 1-2.5-2.5v-9Z\" stroke=\"currentColor\" stroke-width=\"1.5\"/></svg>'\n}\n\nfunction folderName(path: string): string {\n const clean = path.replace(/[\\\\/]+$/u, '')\n const parts = clean.split(/[\\\\/]+/u)\n return parts[parts.length - 1] ?? clean\n}\n\nfunction setComputerIcon(icon: HTMLElement): void {\n icon.innerHTML = '<svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"12\" rx=\"1.7\" stroke=\"currentColor\" stroke-width=\"1.5\"/><path d=\"M8 20h8M12 17v3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>'\n}\n\nfunction ensureStyles(): void {\n const existing = document.getElementById('dshr-workspace-add-style')\n const style = existing instanceof HTMLStyleElement ? existing : document.createElement('style')\n style.id = 'dshr-workspace-add-style'\n style.textContent = `\n .${DIALOG_CLASS}-overlay {\n position: fixed; inset: 0; z-index: 100001; display: grid; place-items: center;\n padding: 24px; background: rgba(0,0,0,.55);\n }\n .${DIALOG_CLASS} {\n width: min(632px, calc(100vw - 48px));\n box-sizing: border-box; padding: 26px; display: flex; flex-direction: column;\n border-radius: 14px; border: 1px solid rgba(255,255,255,.1);\n background: #242424; color: #f2f2f2; box-shadow: 0 28px 80px rgba(0,0,0,.65);\n font: 14px/1.45 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n }\n .${DIALOG_CLASS}-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; }\n .${DIALOG_CLASS}-title { margin: 0; font-size: 28px; line-height: 1.1; font-weight: 700; letter-spacing: -.02em; }\n .${DIALOG_CLASS}-close { border: 0; background: transparent; color: rgba(255,255,255,.75); font-size: 30px; line-height: 1; cursor: pointer; padding: 0 2px; }\n .${DIALOG_CLASS}-close:hover { color: #fff; }\n .${DIALOG_CLASS}-field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }\n .${DIALOG_CLASS}-field > span { font-size: 13px; color: rgba(255,255,255,.72); }\n .${DIALOG_CLASS}-input-row { display: flex; align-items: center; gap: 10px; border: 1px solid rgba(255,255,255,.24); border-radius: 9px; padding: 0 12px; background: transparent; }\n .${DIALOG_CLASS}-input-icon { display: inline-flex; color: rgba(255,255,255,.7); }\n .${DIALOG_CLASS}-input { width: 100%; border: 0; outline: none; background: transparent; color: inherit; font: inherit; font-size: 14px; padding: 13px 0; }\n .${DIALOG_CLASS}-source-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 10px; }\n .${DIALOG_CLASS}-section-title { margin: 0; font-size: 17px; font-weight: 600; color: rgba(255,255,255,.92); }\n .${DIALOG_CLASS}-host-indicator { display: inline-flex; align-items: center; gap: 8px; color: rgba(255,255,255,.62); font-size: 15px; }\n .${DIALOG_CLASS}-host-icon { display: inline-flex; }\n .${DIALOG_CLASS}-source-box { position: relative; border: 1px solid rgba(255,255,255,.16); border-radius: 9px; padding: 24px 16px; min-height: 150px; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; }\n .${DIALOG_CLASS}-source-center { display: flex; flex-direction: column; align-items: center; gap: 16px; }\n .${DIALOG_CLASS}-source-trigger { display: inline-flex; align-items: center; gap: 8px; border: 0; background: transparent; color: rgba(255,255,255,.75); font: inherit; font-size: 15px; cursor: pointer; }\n .${DIALOG_CLASS}-source-trigger span:first-child { color: #fff; font-weight: 600; }\n .${DIALOG_CLASS}-chevron { font-size: 18px; line-height: 1; }\n .${DIALOG_CLASS}-add-folder { display: inline-flex; align-items: center; gap: 8px; border: 0; border-radius: 8px; padding: 8px 14px; background: rgba(255,255,255,.12); color: #fff; font: inherit; font-size: 14px; cursor: pointer; }\n .${DIALOG_CLASS}-add-folder:hover { background: rgba(255,255,255,.18); }\n .${DIALOG_CLASS}-add-folder-icon { font-size: 18px; line-height: 1; }\n .${DIALOG_CLASS}-source-box-selected { padding: 0; min-height: 0; flex: none; justify-content: flex-start; }\n .${DIALOG_CLASS}-selected-folder { display: none; align-items: center; gap: 12px; width: 100%; box-sizing: border-box; padding: 12px 14px; color: rgba(255,255,255,.92); font-size: 16px; }\n .${DIALOG_CLASS}-selected-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .${DIALOG_CLASS}-remove-folder { flex: none; border: 0; background: transparent; color: rgba(255,255,255,.6); font-size: 24px; line-height: 1; cursor: pointer; padding: 0 2px; }\n .${DIALOG_CLASS}-remove-folder:hover { color: #fff; }\n .${DIALOG_CLASS}-error { margin: 6px 0 0; color: #ff8b8b; font-size: 12px; white-space: pre-wrap; }\n .${DIALOG_CLASS}-error:empty { display: none; }\n .${DIALOG_CLASS}-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }\n .${DIALOG_CLASS}-button { padding: 11px 18px; border-radius: 8px; border: 1px solid rgba(255,255,255,.18); background: transparent; color: #eee; cursor: pointer; font: inherit; font-size: 15px; }\n .${DIALOG_CLASS}-button:disabled { opacity: .45; cursor: default; }\n .${DIALOG_CLASS}-primary { border-color: #bdbdbd; background: #bdbdbd; color: #1a1a1a; font-weight: 600; }\n .${DIALOG_CLASS}-primary:hover:not(:disabled) { background: #d0d0d0; }\n .${DIALOG_CLASS}-destination-menu {\n position: fixed; z-index: 100010; min-width: 250px; padding: 6px;\n border-radius: 12px; border: 1px solid rgba(255,255,255,.14); background: #2a2a2a; color: #eee;\n box-shadow: 0 18px 48px rgba(0,0,0,.55); font: 14px/1.4 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n }\n .${DIALOG_CLASS}-destination-item { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 10px 12px; border: 0; border-radius: 8px; background: transparent; color: inherit; font: inherit; cursor: pointer; text-align: left; }\n .${DIALOG_CLASS}-destination-item:hover { background: rgba(255,255,255,.09); }\n .${DIALOG_CLASS}-destination-section { padding: 14px 12px 6px; color: rgba(255,255,255,.5); font-size: 13px; }\n .${DIALOG_CLASS}-destination-check { color: #bdbdbd; }\n .${DIALOG_CLASS}-destination-add { color: rgba(255,255,255,.75); }\n .${DIALOG_CLASS}-browser-overlay { position: fixed; inset: 0; z-index: 100002; display: grid; place-items: center; background: rgba(0,0,0,.6); padding: 24px; }\n .${DIALOG_CLASS}-browser { width: 640px; max-height: 86vh; display: flex; flex-direction: column; padding: 26px; }\n .${DIALOG_CLASS}-browser-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }\n .${DIALOG_CLASS}-browser-title { margin: 0; font-size: 30px; line-height: 1.15; font-weight: 700; }\n .${DIALOG_CLASS}-browser-path-row { display: flex; align-items: center; gap: 8px; }\n .${DIALOG_CLASS}-up { flex: none; width: 34px; height: 34px; border: 0; background: transparent; color: rgba(255,255,255,.65); font-size: 22px; cursor: pointer; }\n .${DIALOG_CLASS}-browser-path { flex: 1; border: 1px solid rgba(255,255,255,.22); border-radius: 9px; background: transparent; color: #fff; font: inherit; font-size: 16px; padding: 12px 14px; outline: none; }\n .${DIALOG_CLASS}-browser-path:focus { border-color: #4f8cff; }\n .${DIALOG_CLASS}-browser-status { margin: 14px 0 8px; color: rgba(255,255,255,.55); font-size: 13px; }\n .${DIALOG_CLASS}-browser-list { flex: 1; min-height: 220px; max-height: 420px; overflow: auto; border: 1px solid rgba(255,255,255,.16); border-radius: 12px; padding: 6px; }\n .${DIALOG_CLASS}-browser-entry { display: flex; align-items: center; gap: 12px; width: 100%; box-sizing: border-box; padding: 11px 12px; border: 0; border-radius: 8px; background: transparent; color: #fff; font: inherit; font-size: 16px; text-align: left; cursor: pointer; }\n .${DIALOG_CLASS}-browser-entry:hover { background: rgba(255,255,255,.08); }\n .${DIALOG_CLASS}-browser-empty { margin: 16px 12px; color: rgba(255,255,255,.5); font-size: 13px; }\n `\n if (existing === null) document.head.append(style)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * dsh-remote-local-plugin browser entry.\n *\n * Registers one Settings section. The component talks only to the injected\n * API closure; the Cordis context stays in `apply`.\n *\n * @module dsh-remote-local/client\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { createHostsApi } from './api.ts'\nimport { RemoteDevelopmentPanel } from './RemoteDevelopmentPanel.tsx'\nimport { installNativeWorkspaceRouting } from './routing.ts'\nimport { installRemoteFiles } from './remote-files.ts'\nimport { NS, en, zh, type LocaleFace } from './locale.ts'\nimport { installWorkspaceAddMenu } from './workspace-add.ts'\n\n/** The Settings shell's slot registry and the authenticated connection. */\nexport const inject = ['slots', 'uiWorkspace', 'locale']\n\n/** Register the \u8FDC\u7A0B\u5F00\u53D1 page. */\nexport function apply(ctx: Context): void {\n const api = createHostsApi(ctx)\n const locale = (ctx as unknown as { locale: LocaleFace }).locale\n ctx.effect(() => locale.register(NS, { zh, en }), 'dsh-remote: locale dictionaries')\n const t = locale.bind(NS)\n installNativeWorkspaceRouting(ctx, api)\n installWorkspaceAddMenu(ctx, api, t)\n ctx.inject(['remote.workspaceFiles'], child => {\n installRemoteFiles(child, api)\n })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'remote-development',\n order: 76,\n label: () => t('settings.title'),\n locale: NS,\n inject: () => ({ api }),\n }, RemoteDevelopmentPanel))\n}\n", "/**\n * Host API contract shared by the host handler and the browser Settings page.\n *\n * The route is registered inside DSH Connection's authenticated `/api` fence,\n * so it works through the web HTTP carrier and the desktop IPC carrier without\n * a second authentication scheme.\n *\n * @module dsh-remote-local/host-api/contract\n */\n\nimport type { HostView } from '../hosts/types.ts'\nimport type {\n AcceptedResult,\n CreateSessionResult,\n HostInfo,\n PromptDeliveryMode,\n RemoteSessionSummary,\n RemoteWorkspace,\n SessionSnapshot,\n} from '@dsh-remote/protocol'\n\n/** Exact authenticated Fetch route owned by the local plugin. */\nexport const HOST_API_PATH = '/api/dsh-remote'\n\n/** Endpoint names. */\nexport type HostApiEndpoint =\n | 'state'\n | 'target/validate'\n | 'host/add'\n | 'host/remove'\n | 'host/connect'\n | 'host/disconnect'\n | 'host/refresh'\n | 'host/provision'\n | 'host/workspaces'\n | 'host/workspace/create'\n | 'host/directory/list'\n | 'local/directory/list'\n | 'local/workspace/create'\n | 'host/sessions'\n | 'host/session'\n | 'host/session/create'\n | 'host/session/prompt'\n | 'host/session/cancel'\n | 'host/web-url'\n | 'host/files/list'\n | 'host/files/read'\n | 'host/files/stat'\n | 'host/files/bytes'\n\n/** Browser-safe state snapshot. */\nexport interface RemoteHostsState {\n readonly protocolVersion: number\n readonly hosts: readonly HostView[]\n}\n\n/** Result of parsing a destination. */\nexport interface ValidatedTarget {\n readonly canonical: string\n readonly host: string\n readonly user: string | null\n readonly port: number | null\n}\n\n/** Result of listing workspaces. */\nexport interface HostWorkspace extends RemoteWorkspace {\n /** Local mirror workspace id, when it has been synced. */\n readonly localWorkspaceId?: string\n}\n\nexport interface WorkspacesResult {\n readonly workspaces: readonly HostWorkspace[]\n}\n\n/** Result of listing sessions. */\nexport interface SessionsResult {\n readonly sessions: readonly RemoteSessionSummary[]\n}\n\nexport interface HostCreateSessionResult extends CreateSessionResult {\n /** Local mirror session that opens in the ordinary Conversation UI. */\n readonly localSessionId?: string\n}\n\nexport interface MirrorFileResult {\n readonly mirrored: boolean\n readonly value?: unknown\n}\n\n/** Result of resolving the remote Web UI. */\nexport interface WebUrlResult {\n readonly url: string\n}\n\n/** One request body. */\nexport interface HostApiRequest {\n readonly endpoint: HostApiEndpoint\n readonly payload?: unknown\n}\n\n/** Success/failure result returned by the route. */\nexport type HostApiResult<T> =\n | { readonly ok: true; readonly value: T }\n | {\n readonly ok: false\n readonly error: {\n readonly code: string\n readonly message: string\n readonly details: Record<string, unknown>\n }\n }\n\n/** Payloads accepted by each endpoint. */\nexport interface HostApiPayloads {\n state: undefined\n 'target/validate': { sshTarget: string }\n 'host/add': {\n sshTarget: string\n label?: string\n token?: string\n remoteAgentPort?: number\n autoConnect?: boolean\n }\n 'host/remove': { hostId: string }\n 'host/connect': { hostId: string }\n 'host/disconnect': { hostId: string }\n 'host/refresh': { hostId: string }\n 'host/provision': { hostId: string }\n 'host/workspaces': { hostId: string }\n 'host/workspace/create': { hostId: string; path: string; title?: string }\n 'host/directory/list': { hostId: string; path?: string }\n 'local/directory/list': { path?: string }\n 'local/workspace/create': { path: string; title?: string }\n 'host/sessions': { hostId: string; workspaceId?: string }\n 'host/session': { hostId: string; sessionId: string; limit?: number }\n 'host/session/create': { hostId: string; workspaceId?: string; cwd?: string; agentPreset?: string }\n 'host/session/prompt': {\n hostId: string\n sessionId: string\n text: string\n mode?: PromptDeliveryMode\n provider?: string\n model?: string\n reasoningEffort?: string\n }\n 'host/session/cancel': { hostId: string; sessionId: string }\n 'host/web-url': { hostId: string }\n 'host/files/list': { sessionId: string; path: string }\n 'host/files/read': { sessionId: string; path: string; offset?: number; limit?: number }\n 'host/files/stat': { sessionId: string; path: string }\n 'host/files/bytes': { sessionId: string; path: string; offset?: number; length?: number }\n}\n\n/** Values returned by each endpoint. */\nexport interface HostApiValues {\n state: RemoteHostsState\n 'target/validate': ValidatedTarget\n 'host/add': HostView\n 'host/remove': { removed: true }\n 'host/connect': HostView\n 'host/disconnect': HostView\n 'host/refresh': HostView\n 'host/provision': HostView\n 'host/workspaces': WorkspacesResult\n 'host/workspace/create': RemoteWorkspace\n 'host/directory/list': { path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }\n 'local/directory/list': { path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }\n 'local/workspace/create': { workspaceId: string }\n 'host/sessions': SessionsResult\n 'host/session': SessionSnapshot\n 'host/session/create': HostCreateSessionResult\n 'host/session/prompt': AcceptedResult\n 'host/session/cancel': AcceptedResult\n 'host/web-url': WebUrlResult\n 'host/files/list': MirrorFileResult\n 'host/files/read': MirrorFileResult\n 'host/files/stat': MirrorFileResult\n 'host/files/bytes': MirrorFileResult\n}\n\n/** Informational type for the Settings page. */\nexport interface HostSummary extends Pick<HostView, 'id' | 'label' | 'sshTarget' | 'phase'> {\n readonly hostInfo: HostInfo | null\n}\n", "/**\n * Browser-side API wrapper around the host's authenticated Fetch route.\n * Components never see `ctx`.\n *\n * @module dsh-remote-local/client/api\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { AcceptedResult, PromptDeliveryMode, RemoteWorkspace, SessionSnapshot } from '@dsh-remote/protocol'\nimport type { HostCreateSessionResult, MirrorFileResult } from '../host-api/contract.ts'\nimport {\n HOST_API_PATH,\n type HostApiPayloads,\n type HostApiValues,\n type RemoteHostsState,\n type SessionsResult,\n type ValidatedTarget,\n type WebUrlResult,\n type WorkspacesResult,\n} from '../host-api/contract.ts'\nimport type { HostView } from '../hosts/types.ts'\n\n/** Error surfaced by one host call. */\nexport class RemoteUiError extends Error {\n readonly code: string\n readonly details: Record<string, unknown>\n\n constructor(code: string, message: string, details: Record<string, unknown> = {}) {\n super(message)\n this.name = 'RemoteUiError'\n this.code = code\n this.details = details\n }\n}\n\n/** API surface injected into the Settings component. */\nexport interface HostsApi {\n readonly state: () => Promise<RemoteHostsState>\n readonly validateTarget: (sshTarget: string) => Promise<ValidatedTarget>\n readonly addHost: (input: HostApiPayloads['host/add']) => Promise<HostView>\n readonly removeHost: (hostId: string) => Promise<void>\n readonly connect: (hostId: string) => Promise<HostView>\n readonly disconnect: (hostId: string) => Promise<HostView>\n readonly refresh: (hostId: string) => Promise<HostView>\n readonly provision: (hostId: string) => Promise<HostView>\n readonly workspaces: (hostId: string) => Promise<WorkspacesResult>\n readonly listDirectories: (hostId: string, path?: string) => Promise<{ path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }>\n readonly listLocalDirectories: (path?: string) => Promise<{ path: string; parent: string; entries: readonly { name: string; path: string }[]; truncated: boolean }>\n readonly createLocalWorkspace: (input: { path: string; title?: string }) => Promise<{ workspaceId: string }>\n readonly createWorkspace: (hostId: string, input: { path: string; title?: string }) => Promise<RemoteWorkspace>\n readonly sessions: (hostId: string, workspaceId?: string) => Promise<SessionsResult>\n readonly webUrl: (hostId: string) => Promise<WebUrlResult>\n readonly snapshot: (hostId: string, sessionId: string, limit?: number) => Promise<SessionSnapshot>\n readonly createSession: (hostId: string, input: { workspaceId?: string; cwd?: string; agentPreset?: string }) => Promise<HostCreateSessionResult>\n readonly openSession: (sessionId: string) => void\n readonly fileList: (sessionId: string, path: string) => Promise<MirrorFileResult>\n readonly fileRead: (sessionId: string, path: string, offset?: number, limit?: number) => Promise<MirrorFileResult>\n readonly fileStat: (sessionId: string, path: string) => Promise<MirrorFileResult>\n readonly fileBytes: (sessionId: string, path: string, offset?: number, length?: number) => Promise<MirrorFileResult>\n readonly prompt: (hostId: string, sessionId: string, text: string, mode?: PromptDeliveryMode, selection?: { provider: string; model: string; reasoningEffort?: string }) => Promise<AcceptedResult>\n readonly cancel: (hostId: string, sessionId: string) => Promise<AcceptedResult>\n}\n\n/** Build the API closure once per plugin mount. */\nexport function createHostsApi(ctx: Context): HostsApi {\n return {\n state: () => call('state', undefined),\n validateTarget: sshTarget => call('target/validate', { sshTarget }),\n addHost: input => call('host/add', input),\n removeHost: async hostId => { await call('host/remove', { hostId }) },\n connect: hostId => call('host/connect', { hostId }),\n disconnect: hostId => call('host/disconnect', { hostId }),\n refresh: hostId => call('host/refresh', { hostId }),\n provision: hostId => call('host/provision', { hostId }),\n workspaces: hostId => call('host/workspaces', { hostId }),\n listDirectories: (hostId, path) => call('host/directory/list', { hostId, ...path === undefined ? {} : { path } }),\n listLocalDirectories: path => call('local/directory/list', { ...path === undefined ? {} : { path } }),\n createLocalWorkspace: input => call('local/workspace/create', input),\n createWorkspace: (hostId, input) => call('host/workspace/create', { hostId, ...input }),\n sessions: (hostId, workspaceId) => call('host/sessions', {\n hostId,\n ...workspaceId === undefined ? {} : { workspaceId },\n }),\n webUrl: hostId => call('host/web-url', { hostId }),\n snapshot: (hostId, sessionId, limit) => call('host/session', {\n hostId,\n sessionId,\n ...limit === undefined ? {} : { limit },\n }),\n createSession: (hostId, input) => call('host/session/create', { hostId, ...input }),\n openSession: sessionId => { ctx.uiWorkspace.openSession(sessionId as never) },\n fileList: (sessionId, path) => call('host/files/list', { sessionId, path }),\n fileRead: (sessionId, path, offset, limit) => call('host/files/read', {\n sessionId,\n path,\n ...offset === undefined ? {} : { offset },\n ...limit === undefined ? {} : { limit },\n }),\n fileStat: (sessionId, path) => call('host/files/stat', { sessionId, path }),\n fileBytes: (sessionId, path, offset, length) => call('host/files/bytes', {\n sessionId,\n path,\n ...offset === undefined ? {} : { offset },\n ...length === undefined ? {} : { length },\n }),\n prompt: (hostId, sessionId, text, mode, selection) => call('host/session/prompt', {\n hostId,\n sessionId,\n text,\n ...mode === undefined ? {} : { mode },\n ...selection === undefined ? {} : selection,\n }),\n cancel: (hostId, sessionId) => call('host/session/cancel', { hostId, sessionId }),\n }\n}\n\nasync function call<K extends keyof HostApiPayloads & string>(\n endpoint: K,\n payload: HostApiPayloads[K],\n): Promise<HostApiValues[K]> {\n const response = await fetch(HOST_API_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload === undefined ? { endpoint } : { endpoint, payload }),\n })\n if (!response.ok) {\n throw new RemoteUiError('request/invalid', `host API returned HTTP ${response.status}`)\n }\n const result = await response.json() as\n | { ok: true; value: HostApiValues[K] }\n | { ok: false; error: { code: string; message: string; details?: Record<string, unknown> } }\n if (!result.ok) {\n throw new RemoteUiError(result.error.code, result.error.message, result.error.details ?? {})\n }\n return result.value\n}\n", "/**\n * Settings \u2192 \u8FDC\u7A0B\u5F00\u53D1 page.\n *\n * The page is a projection over the host plugin's authenticated RPC channel.\n * It owns only view state (form fields, which host is expanded); every\n * durable fact and every tunnel lives in the host process.\n *\n * @module dsh-remote-local/client/panel\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport type { RemoteSessionSummary, RemoteWorkspace } from '@dsh-remote/protocol'\nimport type { HostView } from '../hosts/types.ts'\nimport type { RemoteHostsState } from '../host-api/contract.ts'\nimport type { HostsApi } from './api.ts'\nimport type { CopyKey, Translate } from './locale.ts'\nimport panelCss from './panel.css'\n\n/** Props injected by the Settings page. */\ninterface PanelProps {\n readonly api: HostsApi\n readonly t: Translate\n}\n\nfunction phaseLabel(t: Translate, phase: HostView['phase']): string {\n return t(`phase.${phase}` as CopyKey)\n}\n\nconst DETAIL_KEYS: Record<string, CopyKey> = {\n '\u6B63\u5728\u901A\u8FC7 SSH \u53D1\u73B0\u8FDC\u7AEF agent\u2026': 'detail.discovering',\n '\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5 DSH \u4E0E dsh-remote-agent\uFF0C\u9996\u6B21\u7EA6 1\u20133 \u5206\u949F\u2026': 'detail.installing',\n '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u5E76\u6821\u9A8C\u8FDC\u7AEF agent\u2026': 'detail.connecting',\n '\u6B63\u5728\u91CD\u65B0\u5B89\u88C5\u8FDC\u7AEF agent\u2026': 'detail.reprovisioning',\n 'SSH \u96A7\u9053\u65AD\u5F00\uFF0C\u7B49\u5F85\u91CD\u8FDE\u2026': 'detail.reconnecting',\n '\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026': 'detail.preparing',\n '\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026': 'detail.proxyPreparing',\n '\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026': 'detail.proxy',\n '\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026': 'detail.uploadingAgent',\n '\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026': 'detail.uploaded',\n '\u6B63\u5728\u4E0B\u8F7D Node.js\u2026': 'detail.nodeDownloading',\n 'Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026': 'detail.nodeInstalled',\n 'Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026': 'detail.nodeReady',\n '\u6B63\u5728\u5B89\u88C5 pnpm\u2026': 'detail.pnpmInstalling',\n '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF DSH\uFF08\u4E0B\u8F7D\u4F9D\u8D56\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF09\u2026': 'detail.dshInstalling',\n '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF agent\u2026': 'detail.agentInstalling',\n '\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026': 'detail.webStarting',\n '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u6587\u4EF6\u2026': 'detail.waitingState',\n '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u2026': 'detail.waitingAgent',\n '\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026': 'detail.agentReady',\n '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\u2026': 'detail.installed',\n '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u6B63\u5728\u7B49\u5F85 DSH web \u542F\u52A8\u2026': 'detail.waitingWeb',\n '\u4ECD\u5728\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026': 'detail.stillWaiting',\n '\u6B63\u5728\u8BFB\u53D6\u8FDC\u7AEF agent \u72B6\u6001\u2026': 'detail.readingState',\n '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u2026': 'detail.tunnel',\n '\u6B63\u5728\u6821\u9A8C\u8FDC\u7AEF agent\u2026': 'detail.checkingAgent',\n '\u6B63\u5728\u540C\u6B65\u8FDC\u7AEF\u6A21\u578B\u73AF\u5883\u2026': 'detail.reconcilingModel',\n '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7ECF\u672C\u5730\u51ED\u636E\u4EE3\u7406\u8F6C\u53D1': 'detail.connectedProxy',\n '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7531\u8FDC\u7AEF\u76F4\u8FDE DeepSeek': 'detail.connectedDirect',\n '\u5DF2\u8FDE\u63A5\uFF1B\u8FDC\u7AEF\u4F7F\u7528\u81EA\u8EAB\u51ED\u636E\u6216\u672A\u914D\u7F6E\u6A21\u578B key': 'detail.connectedRemote',\n}\n\nfunction detailLabel(t: Translate, detail: string): string {\n const key = DETAIL_KEYS[detail]\n return key === undefined ? detail : t(key)\n}\n\nconst POLL_MS = 2_500\n\n/** Render the remote-development settings page. */\nexport function RemoteDevelopmentPanel({ api, t }: PanelProps) {\n const [state, setState] = useState<RemoteHostsState | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [notice, setNotice] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n const [expandedHost, setExpandedHost] = useState<string | null>(null)\n const [workspaces, setWorkspaces] = useState<Record<string, RemoteWorkspace[] | undefined>>({})\n const [openWorkspace, setOpenWorkspace] = useState<Record<string, boolean>>({})\n const [sessions, setSessions] = useState<Record<string, RemoteSessionSummary[] | undefined>>({})\n const [workspaceDraft, setWorkspaceDraft] = useState('')\n const [form, setForm] = useState({\n sshTarget: '',\n label: '',\n })\n\n useInjectedStyle(panelCss)\n\n const hosts = useMemo(() => state?.hosts ?? [], [state])\n\n useEffect(() => {\n let cancelled = false\n const load = async (): Promise<void> => {\n try {\n const next = await api.state()\n if (!cancelled) {\n setState(next)\n setError(current => current === t('settings.unavailable') ? null : current)\n }\n } catch (failure) {\n if (!cancelled) setError(messageOf(failure, t('settings.unavailable')))\n }\n }\n void load()\n const timer = window.setInterval(() => { void load() }, POLL_MS)\n const onFocus = (): void => { void load() }\n window.addEventListener('focus', onFocus)\n return () => {\n cancelled = true\n window.clearInterval(timer)\n window.removeEventListener('focus', onFocus)\n }\n }, [api, t])\n\n useEffect(() => {\n const host = hosts.find(item => item.id === expandedHost)\n if (host?.phase === 'connected' && workspaces[host.id] === undefined) {\n void loadWorkspaces(host.id)\n }\n }, [hosts, expandedHost, workspaces])\n\n async function refresh(): Promise<void> {\n setState(await api.state())\n }\n\n async function run(key: string, task: () => Promise<void>): Promise<void> {\n setBusy(key)\n setError(null)\n setNotice(null)\n try {\n await task()\n await refresh()\n } catch (failure) {\n setError(messageOf(failure, t('settings.operationFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n async function onAdd(): Promise<void> {\n const sshTarget = form.sshTarget.trim()\n if (sshTarget === '') {\n setError(t('settings.sshRequired'))\n return\n }\n await run('add', async () => {\n await api.validateTarget(sshTarget)\n const host = await api.addHost({\n sshTarget,\n ...form.label.trim() === '' ? {} : { label: form.label.trim() },\n autoConnect: true,\n })\n setForm({ sshTarget: '', label: '' })\n setExpandedHost(host.id)\n setNotice(t('settings.hostSaved'))\n })\n }\n\n async function toggleHost(host: HostView): Promise<void> {\n if (expandedHost === host.id) {\n setExpandedHost(null)\n return\n }\n setExpandedHost(host.id)\n await loadWorkspaces(host.id)\n }\n\n async function loadWorkspaces(hostId: string): Promise<void> {\n setWorkspaces(current => ({ ...current, [hostId]: undefined }))\n try {\n const result = await api.workspaces(hostId)\n setWorkspaces(current => ({ ...current, [hostId]: [...result.workspaces] }))\n } catch (failure) {\n setWorkspaces(current => ({ ...current, [hostId]: [] }))\n setError(messageOf(failure, t('settings.readWorkspacesFailed')))\n }\n }\n\n async function toggleWorkspace(hostId: string, workspaceId: string): Promise<void> {\n const key = `${hostId}:${workspaceId}`\n const next = !(openWorkspace[key] ?? false)\n setOpenWorkspace(current => ({ ...current, [key]: next }))\n if (!next || sessions[key] !== undefined) return\n setSessions(current => ({ ...current, [key]: undefined }))\n try {\n const result = await api.sessions(hostId, workspaceId)\n setSessions(current => ({ ...current, [key]: [...result.sessions] }))\n } catch (failure) {\n setSessions(current => ({ ...current, [key]: [] }))\n setError(messageOf(failure, t('settings.readSessionsFailed')))\n }\n }\n\n async function addWorkspace(host: HostView): Promise<void> {\n const path = workspaceDraft.trim()\n if (path === '') {\n setError(t('settings.pathRequired'))\n return\n }\n setBusy(`workspace:${host.id}`)\n setError(null)\n try {\n await api.createWorkspace(host.id, { path })\n setWorkspaceDraft('')\n await loadWorkspaces(host.id)\n setExpandedHost(host.id)\n } catch (failure) {\n setError(messageOf(failure, t('settings.addWorkspaceFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n\n\n async function newSession(host: HostView, workspaceId: string): Promise<void> {\n setBusy(`create:${host.id}:${workspaceId}`)\n setError(null)\n try {\n const created = await api.createSession(host.id, { workspaceId })\n const key = `${host.id}:${workspaceId}`\n setOpenWorkspace(current => ({ ...current, [key]: true }))\n if (created.localSessionId !== undefined) {\n api.openSession(created.localSessionId)\n setNotice(t('settings.sessionOpening'))\n window.setTimeout(() => {\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))\n }, 80)\n } else {\n setNotice(t('settings.sessionSyncing'))\n }\n const result = await api.sessions(host.id, workspaceId)\n setSessions(current => ({ ...current, [key]: [...result.sessions] }))\n const refreshed = await api.workspaces(host.id)\n setWorkspaces(current => ({ ...current, [host.id]: [...refreshed.workspaces] }))\n } catch (failure) {\n setError(messageOf(failure, t('settings.createSessionFailed')))\n } finally {\n setBusy(null)\n }\n }\n\n\n\n async function onRemove(host: HostView): Promise<void> {\n if (!window.confirm(`${t('settings.confirmRemovePrefix')}${host.label}${t('settings.confirmRemoveSuffix')}`)) return\n await run(`remove:${host.id}`, async () => {\n await api.removeHost(host.id)\n if (expandedHost === host.id) setExpandedHost(null)\n })\n }\n\n return (\n <div className=\"dshr-root\">\n <header className=\"dshr-header\">\n <div>\n <h2>{t('settings.title')}</h2>\n <p className=\"dshr-subtitle\">\n {t('settings.subtitle.lead')}\n {' '}\n {t('settings.subtitle.body')}\n </p>\n </div>\n <button\n type=\"button\"\n className=\"dshr-button\"\n onClick={() => { void refresh().catch(failure => setError(messageOf(failure, t('settings.refreshFailed')))) }}\n disabled={busy !== null}\n >\n {t('settings.refresh')}\n </button>\n </header>\n\n {error !== null && <p className=\"dshr-banner dshr-banner-error\" role=\"alert\">{error}</p>}\n {notice !== null && <p className=\"dshr-banner dshr-banner-info\" role=\"status\">{notice}</p>}\n\n <section className=\"dshr-card\">\n <h3>{t('settings.addHost')}</h3>\n <form\n className=\"dshr-form\"\n onSubmit={event => {\n event.preventDefault()\n void onAdd()\n }}\n >\n <label className=\"dshr-field dshr-field-wide\">\n <span>{t('settings.sshTarget')}</span>\n <input\n value={form.sshTarget}\n onChange={event => setForm(current => ({ ...current, sshTarget: event.target.value }))}\n placeholder={t('settings.sshPlaceholder')}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n <label className=\"dshr-field\">\n <span>{t('settings.label')}</span>\n <input\n value={form.label}\n onChange={event => setForm(current => ({ ...current, label: event.target.value }))}\n placeholder={t('settings.labelPlaceholder')}\n />\n </label>\n <div className=\"dshr-form-actions\">\n <button type=\"submit\" className=\"dshr-button dshr-button-primary\" disabled={busy !== null}>\n {busy === 'add' ? t('settings.adding') : t('settings.saveConnect')}\n </button>\n <span className=\"dshr-hint\">{t('settings.sshHint')}</span>\n </div>\n </form>\n </section>\n\n <section className=\"dshr-card\">\n <div className=\"dshr-section-title\">\n <h3>{t('settings.hosts')}</h3>\n <span className=\"dshr-hint\">{hosts.length} {t('settings.hostsUnit')}</span>\n </div>\n {hosts.length === 0 && <p className=\"dshr-empty\">{t('settings.noHosts')}</p>}\n <div className=\"dshr-hosts\">\n {hosts.map(host => (\n <article key={host.id} className=\"dshr-host\">\n <header className=\"dshr-host-head\">\n <div className=\"dshr-host-title\">\n <strong>{host.label}</strong>\n <code>{host.sshTarget}</code>\n </div>\n <span className={`dshr-phase dshr-phase-${host.phase}`}>{phaseLabel(t, host.phase)}</span>\n </header>\n\n <dl className=\"dshr-meta\">\n <div><dt>{t('settings.remotePort')}</dt><dd>{host.remoteAgentPort ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.localTunnel')}</dt><dd>{host.localPort ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.workspaces')}</dt><dd>{host.workspaceCount ?? '\u2014'}</dd></div>\n <div><dt>Agent</dt><dd>{host.hostInfo?.agentVersion ?? '\u2014'}</dd></div>\n <div><dt>{t('settings.token')}</dt><dd>{host.hasToken ? t('settings.saved') : t('settings.unsaved')}</dd></div>\n <div><dt>{t('settings.modelProxy')}</dt><dd>{host.modelProxy ? t('settings.localProxy') : host.modelDirect ? t('settings.direct') : t('settings.remoteDefault')}</dd></div>\n </dl>\n\n {host.detail !== null && <p className=\"dshr-detail\">{detailLabel(t, host.detail)}</p>}\n {host.error !== null && <p className=\"dshr-host-error\" role=\"alert\">{host.error}</p>}\n\n <div className=\"dshr-actions\">\n {host.phase === 'connected'\n ? (\n <>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void toggleHost(host) }}\n >\n {expandedHost === host.id ? t('settings.collapseWorkspaces') : t('settings.expandWorkspaces')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`refresh:${host.id}`, async () => { await api.refresh(host.id) }) }}\n >\n {t('settings.rediscover')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`disconnect:${host.id}`, async () => { await api.disconnect(host.id) }) }}\n >\n {t('settings.disconnect')}\n </button>\n </>\n )\n : (\n <>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-primary\"\n disabled={busy !== null || host.phase === 'installing' || host.phase === 'discovering' || host.phase === 'connecting'}\n onClick={() => { void run(`connect:${host.id}`, async () => { await api.connect(host.id) }) }}\n >\n {host.phase === 'installing' ? t('settings.installing') : host.phase === 'connecting' ? t('settings.connecting') : t('settings.connect')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null}\n onClick={() => { void run(`refresh:${host.id}`, async () => { await api.refresh(host.id) }) }}\n >\n {t('settings.rediscover')}\n </button>\n </>\n )}\n <button\n type=\"button\"\n className=\"dshr-button\"\n disabled={busy !== null || host.phase === 'installing'}\n onClick={() => { void run(`provision:${host.id}`, async () => { await api.provision(host.id) }) }}\n >\n {t('settings.reprovision')}\n </button>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-danger\"\n disabled={busy !== null}\n onClick={() => { void onRemove(host) }}\n >\n {t('settings.remove')}\n </button>\n </div>\n\n {expandedHost === host.id && (\n <div className=\"dshr-workspaces\">\n <div className=\"dshr-workspace-add\">\n <input\n value={workspaceDraft}\n onChange={event => setWorkspaceDraft(event.target.value)}\n placeholder={t('settings.workspacePathPlaceholder')}\n spellCheck={false}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void addWorkspace(host)\n }\n }}\n />\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-small\"\n disabled={busy !== null}\n onClick={() => { void addWorkspace(host) }}\n >\n {busy === `workspace:${host.id}` ? t('settings.addingWorkspace') : t('settings.addWorkspace')}\n </button>\n </div>\n {workspaces[host.id] === undefined\n ? <p className=\"dshr-empty\">{t('settings.readingWorkspaces')}</p>\n : workspaces[host.id]?.length === 0\n ? <p className=\"dshr-empty\">{t('settings.noWorkspaces')}</p>\n : workspaces[host.id]?.map(workspace => {\n const workspaceKey = `${host.id}:${workspace.workspaceId}`\n const open = openWorkspace[workspaceKey] ?? false\n return (\n <div key={workspace.workspaceId} className=\"dshr-workspace\">\n <div className=\"dshr-workspace-row\">\n <button\n type=\"button\"\n className=\"dshr-workspace-head\"\n aria-expanded={open}\n onClick={() => { void toggleWorkspace(host.id, workspace.workspaceId) }}\n >\n <span className=\"dshr-caret\">{open ? '\u25BE' : '\u25B8'}</span>\n <span>{workspace.title}</span>\n <code>{workspace.path}</code>\n <span className=\"dshr-count\">{workspace.sessionIds.length} {t('settings.sessionsUnit')}</span>\n </button>\n <button\n type=\"button\"\n className=\"dshr-button dshr-button-small\"\n disabled={busy !== null}\n onClick={() => { void newSession(host, workspace.workspaceId) }}\n >\n {busy === `create:${host.id}:${workspace.workspaceId}` ? t('settings.creating') : t('settings.newSession')}\n </button>\n </div>\n {open && (\n <div className=\"dshr-sessions\">\n {sessions[workspaceKey] === undefined\n ? <p className=\"dshr-empty\">{t('settings.readingSessions')}</p>\n : sessions[workspaceKey]?.length === 0\n ? <p className=\"dshr-empty\">{t('settings.noSessions')}</p>\n : sessions[workspaceKey]?.map(session => (\n <div key={session.sessionId} className=\"dshr-session\">\n <span className={session.live ? 'dshr-live' : 'dshr-idle'} />\n <code>{session.sessionId}</code>\n <span>{session.cwd ?? '\u2014'}</span>\n <span className=\"dshr-count\">{session.eventCount ?? '\u2014'} {t('settings.eventsUnit')}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )}\n </article>\n ))}\n </div>\n </section>\n\n </div>\n )\n}\n\nfunction useInjectedStyle(css: string): void {\n useEffect(() => {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-remote-local'\n tag.textContent = css\n document.head.appendChild(tag)\n return () => { tag.remove() }\n }, [css])\n}\n\nfunction messageOf(value: unknown, fallback: string): string {\n return value instanceof Error && value.message !== '' ? value.message : fallback\n}\n", ".dshr-root {\n --dshr-accent: #4f7cff;\n --dshr-danger: #d24b4b;\n --dshr-success: #2f9e63;\n --dshr-warning: #c98417;\n --dshr-border: color-mix(in srgb, currentColor 14%, transparent);\n --dshr-soft: color-mix(in srgb, currentColor 4%, transparent);\n --dshr-softer: color-mix(in srgb, currentColor 2.5%, transparent);\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 2px 32px;\n font-size: 13px;\n line-height: 1.5;\n}\n\n.dshr-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n}\n\n.dshr-header h2 {\n margin: 0 0 4px;\n font-size: 17px;\n font-weight: 650;\n}\n\n.dshr-subtitle {\n max-width: 760px;\n margin: 0;\n opacity: 0.72;\n}\n\n.dshr-subtitle code,\n.dshr-host-title code,\n.dshr-workspace-head code,\n.dshr-session code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.92em;\n}\n\n.dshr-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--dshr-border);\n border-radius: 12px;\n background: var(--dshr-softer);\n}\n\n.dshr-card h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 650;\n}\n\n.dshr-section-title {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n}\n\n.dshr-form {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n}\n\n.dshr-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.dshr-field-wide {\n grid-column: 1 / -1;\n}\n\n.dshr-field > span {\n font-size: 12px;\n opacity: 0.72;\n}\n\n.dshr-field input {\n width: 100%;\n box-sizing: border-box;\n padding: 7px 9px;\n border: 1px solid var(--dshr-border);\n border-radius: 8px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n outline: none;\n}\n\n.dshr-field input:focus {\n border-color: var(--dshr-accent);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dshr-accent) 22%, transparent);\n}\n\n.dshr-check {\n display: flex;\n align-items: center;\n gap: 7px;\n font-size: 12px;\n}\n\n.dshr-form-actions {\n display: flex;\n grid-column: 1 / -1;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.dshr-button {\n padding: 6px 12px;\n border: 1px solid var(--dshr-border);\n border-radius: 8px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.dshr-button:hover:not(:disabled) {\n background: color-mix(in srgb, currentColor 8%, transparent);\n}\n\n.dshr-button:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n.dshr-button-primary {\n border-color: color-mix(in srgb, var(--dshr-accent) 65%, transparent);\n background: var(--dshr-accent);\n color: #fff;\n}\n\n.dshr-button-primary:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dshr-accent) 84%, #000);\n}\n\n.dshr-button-danger {\n border-color: color-mix(in srgb, var(--dshr-danger) 45%, transparent);\n color: var(--dshr-danger);\n}\n\n.dshr-hint {\n font-size: 12px;\n opacity: 0.62;\n}\n\n.dshr-empty {\n margin: 0;\n padding: 10px 0;\n opacity: 0.62;\n}\n\n.dshr-banner {\n margin: 0;\n padding: 9px 12px;\n border-radius: 9px;\n border: 1px solid var(--dshr-border);\n}\n\n.dshr-banner-error {\n border-color: color-mix(in srgb, var(--dshr-danger) 45%, transparent);\n background: color-mix(in srgb, var(--dshr-danger) 10%, transparent);\n color: var(--dshr-danger);\n}\n\n.dshr-banner-info {\n border-color: color-mix(in srgb, var(--dshr-accent) 35%, transparent);\n background: color-mix(in srgb, var(--dshr-accent) 9%, transparent);\n}\n\n.dshr-hosts {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dshr-host {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dshr-border);\n border-radius: 10px;\n background: var(--dshr-soft);\n}\n\n.dshr-host-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n\n.dshr-host-title {\n display: flex;\n align-items: baseline;\n gap: 10px;\n flex-wrap: wrap;\n min-width: 0;\n}\n\n.dshr-host-title strong {\n font-size: 14px;\n}\n\n.dshr-phase {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n border: 1px solid currentColor;\n opacity: 0.9;\n}\n\n.dshr-phase-connected {\n color: var(--dshr-success);\n}\n\n.dshr-phase-discovering,\n.dshr-phase-connecting {\n color: var(--dshr-warning);\n}\n\n.dshr-phase-error {\n color: var(--dshr-danger);\n}\n\n.dshr-phase-idle,\n.dshr-phase-disconnected {\n opacity: 0.62;\n}\n\n.dshr-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 6px 20px;\n margin: 0;\n font-size: 12px;\n}\n\n.dshr-meta > div {\n display: flex;\n gap: 5px;\n}\n\n.dshr-meta dt {\n opacity: 0.58;\n}\n\n.dshr-meta dd {\n margin: 0;\n font-variant-numeric: tabular-nums;\n}\n\n.dshr-host-error {\n margin: 0;\n color: var(--dshr-danger);\n font-size: 12px;\n overflow-wrap: anywhere;\n}\n\n.dshr-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.dshr-workspaces {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding-top: 4px;\n border-top: 1px dashed var(--dshr-border);\n}\n\n.dshr-workspace {\n border-radius: 8px;\n background: var(--dshr-softer);\n}\n\n.dshr-workspace-head {\n display: flex;\n align-items: baseline;\n gap: 8px;\n width: 100%;\n box-sizing: border-box;\n padding: 8px 10px;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n flex-wrap: wrap;\n}\n\n.dshr-workspace-head:hover {\n background: var(--dshr-soft);\n}\n\n.dshr-workspace-head code {\n opacity: 0.6;\n}\n\n.dshr-caret {\n width: 12px;\n opacity: 0.6;\n}\n\n.dshr-count {\n margin-left: auto;\n font-size: 11px;\n opacity: 0.55;\n white-space: nowrap;\n}\n\n.dshr-sessions {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 0 10px 8px 30px;\n}\n\n.dshr-session {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 3px 0;\n font-size: 12px;\n flex-wrap: wrap;\n}\n\n.dshr-session > span:not(.dshr-live):not(.dshr-idle) {\n opacity: 0.62;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.dshr-live,\n.dshr-idle {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n transform: translateY(-1px);\n}\n\n.dshr-live {\n background: var(--dshr-success);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dshr-success) 20%, transparent);\n}\n\n.dshr-idle {\n background: color-mix(in srgb, currentColor 28%, transparent);\n}\n\n@media (max-width: 720px) {\n .dshr-form {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshr-header {\n flex-direction: column;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshr-button {\n transition: none;\n }\n}\n\n.dshr-detail {\n margin: 0;\n font-size: 12px;\n color: var(--dshr-warning);\n}\n\n.dshr-workspace-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-right: 6px;\n}\n\n.dshr-workspace-row .dshr-workspace-head {\n flex: 1;\n}\n\n.dshr-button-small {\n flex: none;\n padding: 3px 8px;\n font-size: 11px;\n}\n\n.dshr-workspace-add {\n display: flex;\n gap: 6px;\n padding: 4px 0 6px;\n}\n\n.dshr-workspace-add input {\n flex: 1;\n min-width: 0;\n padding: 5px 8px;\n border: 1px solid var(--dshr-border);\n border-radius: 7px;\n background: var(--dshr-soft);\n color: inherit;\n font: inherit;\n font-size: 12px;\n outline: none;\n}\n\n.dshr-workspace-add input:focus {\n border-color: var(--dshr-accent);\n}\n", "/**\n * Route ordinary sidebar \"new session\" actions for mirrored workspaces to the\n * remote agent instead of creating a local Agent in the mirror anchor.\n *\n * The Settings page has its own `+ \u65B0\u4F1A\u8BDD` flow. This adapter covers the\n * standard workspace-row action so the native sidebar behaves the same way.\n *\n * @module dsh-remote-local/client/routing\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostsApi } from './api.ts'\n\ninterface StartSessionOptions {\n readonly agentPreset?: string\n}\n\ninterface WorkspaceService {\n startSession(workspaceId?: unknown, options?: StartSessionOptions): void\n}\n\n/** Install the sidebar routing adapter once per client mount. */\nexport function installNativeWorkspaceRouting(ctx: Context, api: HostsApi): void {\n const workspace = ctx.uiWorkspace as unknown as WorkspaceService | undefined\n if (workspace === undefined || typeof workspace.startSession !== 'function') return\n const original = workspace.startSession.bind(workspace)\n workspace.startSession = (workspaceId, options) => {\n if (workspaceId === undefined) {\n original(workspaceId, options)\n return\n }\n void route(api, String(workspaceId)).then(routed => {\n if (!routed) original(workspaceId, options)\n }).catch(() => { original(workspaceId, options) })\n }\n}\n\nasync function route(api: HostsApi, localWorkspaceId: string): Promise<boolean> {\n const state = await api.state()\n for (const host of state.hosts) {\n if (host.phase !== 'connected') continue\n const result = await api.workspaces(host.id)\n const workspace = result.workspaces.find(item => item.localWorkspaceId === localWorkspaceId)\n if (workspace === undefined) continue\n const created = await api.createSession(host.id, { workspaceId: workspace.workspaceId })\n if (created.localSessionId !== undefined) {\n api.openSession(created.localSessionId)\n return true\n }\n }\n return false\n}\n", "/**\n * Client proxy for workspace-files calls on mirrored Sessions.\n *\n * The Host's generated Remote methods bind the stock workspace-files service\n * before an instance adapter can replace them. The sidebar tree and document\n * preview therefore call this proxy, which asks the local plugin's host API to\n * resolve the mirror and read the remote workspace.\n *\n * @module dsh-remote-local/client/remote-files\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostsApi } from './api.ts'\n\ninterface RemoteFace {\n list(sessionId: string, path: string, signal: AbortSignal): Promise<unknown>\n read(sessionId: string, path: string, range: { offset?: number; limit?: number }, signal: AbortSignal): Promise<unknown>\n stat(sessionId: string, path: string, signal: AbortSignal): Promise<unknown>\n readBytes(sessionId: string, path: string, options: { range?: { offset?: number; length?: number }; baseFile?: string }, signal: AbortSignal): Promise<unknown>\n changes(sessionId: string, path: string, signal: AbortSignal): AsyncIterable<unknown>\n}\n\n/** Install the proxy on the client Remote face. */\nexport function installRemoteFiles(ctx: Context, api: HostsApi): void {\n const remote = ctx.remote as unknown as { workspaceFiles?: RemoteFace } | undefined\n const face = remote?.workspaceFiles\n if (face === undefined) return\n\n const original = {\n list: face.list.bind(face),\n read: face.read.bind(face),\n stat: face.stat.bind(face),\n readBytes: face.readBytes.bind(face),\n }\n\n face.list = async (sessionId, path, signal) => {\n const result = await api.fileList(sessionId, path)\n return result.mirrored ? { ok: true, value: result.value } : original.list(sessionId, path, signal)\n }\n face.read = async (sessionId, path, range, signal) => {\n const result = await api.fileRead(sessionId, path, range.offset, range.limit)\n return result.mirrored ? { ok: true, value: result.value } : original.read(sessionId, path, range, signal)\n }\n face.stat = async (sessionId, path, signal) => {\n const result = await api.fileStat(sessionId, path)\n return result.mirrored ? { ok: true, value: result.value } : original.stat(sessionId, path, signal)\n }\n face.readBytes = async (sessionId, path, options, signal) => {\n const result = await api.fileBytes(sessionId, path, options.range?.offset, options.range?.length)\n return result.mirrored ? { ok: true, value: result.value } : original.readBytes(sessionId, path, options, signal)\n }\n}\n", "/**\n * Client copy for the remote-development surfaces.\n *\n * The dictionaries are registered into DSH's locale service; `ctx.locale.bind`\n * follows the language selected in DSH. Settings components also receive the\n * framework `t` seat, so language switches re-render them.\n */\n\nexport const NS = 'dshRemote'\n\nexport const zh = {\n 'settings.title': '\u8FDC\u7A0B\u5F00\u53D1',\n 'settings.subtitle.lead': '\u53EA\u9700\u586B\u5199 SSH \u76EE\u6807\u3002\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5B89\u88C5\u5E76\u542F\u52A8\u8FDC\u7AEF agent\uFF0C\u5EFA\u7ACB\u96A7\u9053\u3002',\n 'settings.subtitle.body': '\u8FDE\u63A5\u540E\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u548C\u4F1A\u8BDD\u4F1A\u540C\u6B65\u5230\u5DE6\u4FA7\uFF0C\u50CF\u672C\u5730\u4F1A\u8BDD\u4E00\u6837\u6253\u5F00\uFF1B\u6A21\u578B\u51ED\u636E\u9ED8\u8BA4\u5199\u5165\u8FDC\u7AEF\u670D\u52A1\u73AF\u5883\uFF1B\u4E5F\u53EF\u542F\u7528\u672C\u5730\u4EE3\u7406\u6A21\u5F0F\u3002',\n 'settings.refresh': '\u5237\u65B0',\n 'settings.addHost': '\u6DFB\u52A0\u4E3B\u673A',\n 'settings.sshTarget': 'SSH \u76EE\u6807',\n 'settings.sshPlaceholder': 'user@host \u6216 ssh://user@host:22',\n 'settings.label': '\u663E\u793A\u540D\u79F0\uFF08\u53EF\u9009\uFF09',\n 'settings.labelPlaceholder': '\u53EF\u9009\uFF0C\u4F8B\u5982 \u5F00\u53D1\u673A',\n 'settings.saveConnect': '\u4FDD\u5B58\u5E76\u8FDE\u63A5',\n 'settings.adding': '\u6DFB\u52A0\u4E2D\u2026',\n 'settings.sshHint': '\u9700\u8981\u5BC6\u94A5\u6216 ssh-agent \u514D\u4EA4\u4E92\u767B\u5F55\uFF1B\u9996\u6B21\u81EA\u52A8\u5B89\u88C5\u7EA6 1\u20133 \u5206\u949F\u3002',\n 'settings.hosts': '\u4E3B\u673A',\n 'settings.hostsUnit': '\u53F0',\n 'settings.noHosts': '\u8FD8\u6CA1\u6709\u8FDC\u7A0B\u4E3B\u673A\u3002\u5148\u5728\u4E0A\u65B9\u6DFB\u52A0\u4E00\u53F0\u3002',\n 'settings.refreshFailed': '\u5237\u65B0\u5931\u8D25',\n 'settings.unavailable': '\u65E0\u6CD5\u8FDE\u63A5\u672C\u5730\u8FDC\u7A0B\u5BBF\u4E3B\u670D\u52A1',\n 'settings.operationFailed': '\u64CD\u4F5C\u5931\u8D25',\n 'settings.sshRequired': '\u8BF7\u586B\u5199 SSH \u76EE\u6807\uFF0C\u4F8B\u5982 user@host \u6216 ssh://user@host:22',\n 'settings.hostSaved': '\u4E3B\u673A\u5DF2\u4FDD\u5B58\u3002\u63D2\u4EF6\u4F1A\u81EA\u52A8\u5B89\u88C5\u5E76\u542F\u52A8\u8FDC\u7AEF agent\uFF1B\u5B89\u88C5\u8FDB\u5EA6\u4F1A\u663E\u793A\u5728\u4E3B\u673A\u5361\u7247\u4E0A\u3002',\n 'settings.readWorkspacesFailed': '\u8BFB\u53D6\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'settings.readSessionsFailed': '\u8BFB\u53D6\u8FDC\u7AEF\u4F1A\u8BDD\u5931\u8D25',\n 'settings.pathRequired': '\u8BF7\u586B\u5199\u8FDC\u7AEF\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /home/user/project',\n 'settings.addWorkspaceFailed': '\u6DFB\u52A0\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'settings.sessionOpening': '\u8FDC\u7AEF\u4F1A\u8BDD\u5DF2\u521B\u5EFA\uFF0C\u6B63\u5728\u666E\u901A\u4F1A\u8BDD\u754C\u9762\u6253\u5F00\u2026',\n 'settings.sessionSyncing': '\u8FDC\u7AEF\u4F1A\u8BDD\u5DF2\u521B\u5EFA\uFF0C\u6B63\u5728\u540C\u6B65\u5230\u4FA7\u8FB9\u680F\u2026',\n 'settings.createSessionFailed': '\u521B\u5EFA\u8FDC\u7AEF\u4F1A\u8BDD\u5931\u8D25',\n 'settings.confirmRemovePrefix': '\u5220\u9664\u4E3B\u673A\u300C',\n 'settings.confirmRemoveSuffix': '\u300D\uFF1F\u8FDC\u7AEF\u6587\u4EF6\u4E0E\u4F1A\u8BDD\u4E0D\u4F1A\u88AB\u5220\u9664\u3002',\n 'settings.remotePort': '\u8FDC\u7AEF\u7AEF\u53E3',\n 'settings.localTunnel': '\u672C\u5730\u96A7\u9053',\n 'settings.workspaces': '\u5DE5\u4F5C\u533A',\n 'settings.token': 'Token',\n 'settings.saved': '\u5DF2\u4FDD\u5B58',\n 'settings.unsaved': '\u672A\u4FDD\u5B58',\n 'settings.modelProxy': '\u6A21\u578B\u4EE3\u7406',\n 'settings.localProxy': '\u672C\u5730\u4EE3\u7406',\n 'settings.direct': '\u8FDC\u7AEF\u76F4\u8FDE',\n 'settings.remoteDefault': '\u8FDC\u7AEF\u9ED8\u8BA4',\n 'settings.collapseWorkspaces': '\u6536\u8D77\u5DE5\u4F5C\u533A',\n 'settings.expandWorkspaces': '\u5DE5\u4F5C\u533A',\n 'settings.rediscover': '\u91CD\u65B0\u53D1\u73B0',\n 'settings.disconnect': '\u65AD\u5F00',\n 'settings.connect': '\u8FDE\u63A5',\n 'settings.installing': '\u6B63\u5728\u5B89\u88C5\u2026',\n 'settings.connecting': '\u6B63\u5728\u8FDE\u63A5\u2026',\n 'settings.reprovision': '\u91CD\u65B0\u5B89\u88C5',\n 'settings.remove': '\u5220\u9664',\n 'settings.workspacePathPlaceholder': '\u8FDC\u7AEF\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /home/user/project',\n 'settings.addWorkspace': '\u6DFB\u52A0\u5DE5\u4F5C\u533A',\n 'settings.addingWorkspace': '\u6DFB\u52A0\u4E2D\u2026',\n 'settings.readingWorkspaces': '\u6B63\u5728\u8BFB\u53D6\u5DE5\u4F5C\u533A\u2026',\n 'settings.noWorkspaces': '\u8FDC\u7AEF\u8FD8\u6CA1\u6709\u6CE8\u518C\u5DE5\u4F5C\u533A\u3002\u53EF\u5728\u8FDC\u7AEF DSH \u91CC\u6DFB\u52A0\u76EE\u5F55\u540E\u5237\u65B0\u3002',\n 'settings.sessionsUnit': '\u4E2A\u4F1A\u8BDD',\n 'settings.newSession': '+ \u65B0\u4F1A\u8BDD',\n 'settings.creating': '\u521B\u5EFA\u4E2D\u2026',\n 'settings.readingSessions': '\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u2026',\n 'settings.noSessions': '\u8BE5\u5DE5\u4F5C\u533A\u6682\u65E0\u4F1A\u8BDD\u3002\u70B9\u201C+ \u65B0\u4F1A\u8BDD\u201D\u5F00\u59CB\u3002',\n 'settings.eventsUnit': '\u4E8B\u4EF6',\n 'phase.idle': '\u672A\u8FDE\u63A5',\n 'phase.discovering': '\u53D1\u73B0\u4E2D',\n 'phase.installing': '\u5B89\u88C5\u4E2D',\n 'phase.connecting': '\u8FDE\u63A5\u4E2D',\n 'phase.connected': '\u5DF2\u8FDE\u63A5',\n 'phase.disconnected': '\u5DF2\u65AD\u5F00',\n 'phase.error': '\u5F02\u5E38',\n 'detail.discovering': '\u6B63\u5728\u901A\u8FC7 SSH \u53D1\u73B0\u8FDC\u7AEF agent\u2026',\n 'detail.installing': '\u6B63\u5728\u8FDC\u7AEF\u5B89\u88C5 DSH \u4E0E dsh-remote-agent\uFF0C\u9996\u6B21\u7EA6 1\u20133 \u5206\u949F\u2026',\n 'detail.connecting': '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u5E76\u6821\u9A8C\u8FDC\u7AEF agent\u2026',\n 'detail.reprovisioning': '\u6B63\u5728\u91CD\u65B0\u5B89\u88C5\u8FDC\u7AEF agent\u2026',\n 'detail.reconnecting': 'SSH \u96A7\u9053\u65AD\u5F00\uFF0C\u7B49\u5F85\u91CD\u8FDE\u2026',\n 'detail.connectedProxy': '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7ECF\u672C\u5730\u51ED\u636E\u4EE3\u7406\u8F6C\u53D1',\n 'detail.connectedDirect': '\u5DF2\u8FDE\u63A5\uFF1B\u6A21\u578B\u8BF7\u6C42\u7531\u8FDC\u7AEF\u76F4\u8FDE DeepSeek',\n 'detail.connectedRemote': '\u5DF2\u8FDE\u63A5\uFF1B\u8FDC\u7AEF\u4F7F\u7528\u81EA\u8EAB\u51ED\u636E\u6216\u672A\u914D\u7F6E\u6A21\u578B key',\n 'detail.preparing': '\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026',\n 'detail.proxyPreparing': '\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026',\n 'detail.proxy': '\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026',\n 'detail.uploadingAgent': '\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026',\n 'detail.uploaded': '\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026',\n 'detail.nodeDownloading': '\u6B63\u5728\u4E0B\u8F7D Node.js\u2026',\n 'detail.nodeInstalled': 'Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026',\n 'detail.nodeReady': 'Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026',\n 'detail.pnpmInstalling': '\u6B63\u5728\u5B89\u88C5 pnpm\u2026',\n 'detail.dshInstalling': '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF DSH\uFF08\u4E0B\u8F7D\u4F9D\u8D56\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF09\u2026',\n 'detail.agentInstalling': '\u6B63\u5728\u5B89\u88C5\u8FDC\u7AEF agent\u2026',\n 'detail.webStarting': '\u6B63\u5728\u542F\u52A8\u8FDC\u7AEF DSH Web \u670D\u52A1\u2026',\n 'detail.waitingState': '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u6587\u4EF6\u2026',\n 'detail.waitingAgent': '\u6B63\u5728\u7B49\u5F85\u8FDC\u7AEF agent \u72B6\u6001\u2026',\n 'detail.agentReady': '\u8FDC\u7AEF agent \u5DF2\u5C31\u7EEA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u8FDE\u63A5\u2026',\n 'detail.installed': '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\u2026',\n 'detail.waitingWeb': '\u8FDC\u7AEF\u5B89\u88C5\u5B8C\u6210\uFF0C\u6B63\u5728\u7B49\u5F85 DSH web \u542F\u52A8\u2026',\n 'detail.stillWaiting': '\u4ECD\u5728\u7B49\u5F85\u8FDC\u7AEF dsh web \u5C31\u7EEA\u2026',\n 'detail.readingState': '\u6B63\u5728\u8BFB\u53D6\u8FDC\u7AEF agent \u72B6\u6001\u2026',\n 'detail.tunnel': '\u6B63\u5728\u5EFA\u7ACB SSH \u96A7\u9053\u2026',\n 'detail.checkingAgent': '\u6B63\u5728\u6821\u9A8C\u8FDC\u7AEF agent\u2026',\n 'detail.reconcilingModel': '\u6B63\u5728\u540C\u6B65\u8FDC\u7AEF\u6A21\u578B\u73AF\u5883\u2026',\n 'dialog.title': '\u65B0\u5EFA\u5DE5\u4F5C\u533A',\n 'dialog.close': '\u5173\u95ED',\n 'dialog.name': '\u5DE5\u4F5C\u533A\u540D\u79F0',\n 'dialog.namePlaceholder': '\u5DE5\u4F5C\u533A\u540D\u79F0\uFF08\u53EF\u9009\uFF09',\n 'dialog.source': '\u6E90\u76EE\u5F55',\n 'dialog.addToPrefix': '\u5C06\u76EE\u5F55\u6DFB\u52A0\u5230 ',\n 'dialog.addToSuffix': '',\n 'dialog.add': '\u6DFB\u52A0',\n 'dialog.local': '\u672C\u673A',\n 'dialog.remoteDevices': '\u8FDC\u7AEF\u8BBE\u5907',\n 'dialog.addRemote': '+ \u6DFB\u52A0\u8FDC\u7AEF\u2026',\n 'dialog.addRemoteHint': '\u8BF7\u5148\u5728 Settings \u2192 \u8FDC\u7A0B\u5F00\u53D1 \u6DFB\u52A0\u5E76\u8FDE\u63A5\u8FDC\u7AEF\u4E3B\u673A\u3002',\n 'dialog.cancel': '\u53D6\u6D88',\n 'dialog.create': '\u521B\u5EFA\u5DE5\u4F5C\u533A',\n 'dialog.creating': '\u521B\u5EFA\u4E2D\u2026',\n 'dialog.createFailed': '\u65B0\u5EFA\u5DE5\u4F5C\u533A\u5931\u8D25',\n 'dialog.removeFolder': '\u79FB\u9664\u76EE\u5F55',\n 'dialog.selectedFallback': '\u8FDC\u7AEF workspace \u5DF2\u521B\u5EFA\uFF0C\u4F46\u672C\u5730\u955C\u50CF\u8FD8\u6CA1\u6709\u540C\u6B65\u5B8C\u6210',\n 'dialog.folderTitle': '\u9009\u62E9\u6E90\u76EE\u5F55',\n 'dialog.up': '\u4E0A\u4E00\u7EA7',\n 'dialog.selectFolder': '\u9009\u62E9\u5F53\u524D\u76EE\u5F55',\n 'dialog.reading': '\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026',\n 'dialog.emptyFolder': '\u6B64\u76EE\u5F55\u6CA1\u6709\u5B50\u76EE\u5F55',\n 'dialog.readFailed': '\u8BFB\u53D6\u76EE\u5F55\u5931\u8D25',\n 'dialog.nativePickerFailed': '\u65E0\u6CD5\u6253\u5F00\u7CFB\u7EDF\u76EE\u5F55\u9009\u62E9\u5668',\n 'dialog.useFolder': '\u4F7F\u7528\u6B64\u76EE\u5F55',\n} as const\n\nexport type CopyKey = keyof typeof zh\n\nexport const en: Record<CopyKey, string> = {\n 'settings.title': 'Remote development',\n 'settings.subtitle.lead': 'Enter an SSH target. The plugin installs and starts the remote agent and opens a tunnel.',\n 'settings.subtitle.body': 'Remote workspaces and sessions sync into the normal sidebar and open like local sessions. The model key is written into the remote service environment by default; local proxying remains optional.',\n 'settings.refresh': 'Refresh',\n 'settings.addHost': 'Add host',\n 'settings.sshTarget': 'SSH target',\n 'settings.sshPlaceholder': 'user@host or ssh://user@host:22',\n 'settings.label': 'Display name (optional)',\n 'settings.labelPlaceholder': 'Optional, e.g. dev box',\n 'settings.saveConnect': 'Save and connect',\n 'settings.adding': 'Adding\u2026',\n 'settings.sshHint': 'Requires key or ssh-agent authentication. First install takes about 1\u20133 minutes.',\n 'settings.hosts': 'Hosts',\n 'settings.hostsUnit': '',\n 'settings.noHosts': 'No remote hosts yet. Add one above.',\n 'settings.refreshFailed': 'Refresh failed',\n 'settings.unavailable': 'Cannot reach the local remote-host service',\n 'settings.operationFailed': 'Operation failed',\n 'settings.sshRequired': 'Enter an SSH target, e.g. user@host or ssh://user@host:22',\n 'settings.hostSaved': 'Host saved. The plugin will install and start the remote agent; progress appears on the host card.',\n 'settings.readWorkspacesFailed': 'Could not read remote workspaces',\n 'settings.readSessionsFailed': 'Could not read remote sessions',\n 'settings.pathRequired': 'Enter an absolute remote directory, e.g. /home/user/project',\n 'settings.addWorkspaceFailed': 'Could not add the remote workspace',\n 'settings.sessionOpening': 'Remote session created; opening it in the conversation view\u2026',\n 'settings.sessionSyncing': 'Remote session created; syncing it into the sidebar\u2026',\n 'settings.createSessionFailed': 'Could not create the remote session',\n 'settings.confirmRemovePrefix': 'Remove host \"',\n 'settings.confirmRemoveSuffix': '\"? Remote files and sessions are not deleted.',\n 'settings.remotePort': 'Remote port',\n 'settings.localTunnel': 'Local tunnel',\n 'settings.workspaces': 'Workspaces',\n 'settings.token': 'Token',\n 'settings.saved': 'Saved',\n 'settings.unsaved': 'Not saved',\n 'settings.modelProxy': 'Model credentials',\n 'settings.localProxy': 'Local proxy',\n 'settings.direct': 'Remote direct',\n 'settings.remoteDefault': 'Remote default',\n 'settings.collapseWorkspaces': 'Hide workspaces',\n 'settings.expandWorkspaces': 'Workspaces',\n 'settings.rediscover': 'Rediscover',\n 'settings.disconnect': 'Disconnect',\n 'settings.connect': 'Connect',\n 'settings.installing': 'Installing\u2026',\n 'settings.connecting': 'Connecting\u2026',\n 'settings.reprovision': 'Reinstall',\n 'settings.remove': 'Remove',\n 'settings.workspacePathPlaceholder': 'Absolute remote path, e.g. /home/user/project',\n 'settings.addWorkspace': 'Add workspace',\n 'settings.addingWorkspace': 'Adding\u2026',\n 'settings.readingWorkspaces': 'Reading workspaces\u2026',\n 'settings.noWorkspaces': 'No remote workspaces registered yet. Add a directory in the remote DSH, then refresh.',\n 'settings.sessionsUnit': 'sessions',\n 'settings.newSession': '+ New session',\n 'settings.creating': 'Creating\u2026',\n 'settings.readingSessions': 'Reading sessions\u2026',\n 'settings.noSessions': 'No sessions in this workspace. Start one with \u201C+ New session\u201D.',\n 'settings.eventsUnit': 'events',\n 'phase.idle': 'Idle',\n 'phase.discovering': 'Discovering',\n 'phase.installing': 'Installing',\n 'phase.connecting': 'Connecting',\n 'phase.connected': 'Connected',\n 'phase.disconnected': 'Disconnected',\n 'phase.error': 'Error',\n 'detail.discovering': 'Discovering the remote agent over SSH\u2026',\n 'detail.installing': 'Installing DSH and dsh-remote-agent remotely; this takes about 1\u20133 minutes\u2026',\n 'detail.connecting': 'Opening the SSH tunnel and checking the remote agent\u2026',\n 'detail.reprovisioning': 'Reinstalling the remote agent\u2026',\n 'detail.reconnecting': 'SSH tunnel closed; waiting to reconnect\u2026',\n 'detail.connectedProxy': 'Connected; model requests go through the local credential proxy',\n 'detail.connectedDirect': 'Connected; the remote host calls DeepSeek directly',\n 'detail.connectedRemote': 'Connected; the remote host uses its own credentials or has no model key',\n 'detail.preparing': 'Preparing the remote installation environment\u2026',\n 'detail.proxyPreparing': 'Configuring the remote installation proxy\u2026',\n 'detail.proxy': 'Remote installation proxy configured\u2026',\n 'detail.uploadingAgent': 'Uploading the remote agent package\u2026',\n 'detail.uploaded': 'Package uploaded; starting the remote installation\u2026',\n 'detail.nodeDownloading': 'Downloading Node.js\u2026',\n 'detail.nodeInstalled': 'Node.js installed; continuing with pnpm/DSH\u2026',\n 'detail.nodeReady': 'Node.js is ready; preparing pnpm/DSH\u2026',\n 'detail.pnpmInstalling': 'Installing pnpm\u2026',\n 'detail.dshInstalling': 'Installing remote DSH (dependency download may take several minutes)\u2026',\n 'detail.agentInstalling': 'Installing the remote agent\u2026',\n 'detail.webStarting': 'Starting the remote DSH Web service\u2026',\n 'detail.waitingState': 'Waiting for the remote agent state file\u2026',\n 'detail.waitingAgent': 'Waiting for the remote agent\u2026',\n 'detail.agentReady': 'Remote agent is ready; establishing the connection\u2026',\n 'detail.installed': 'Remote installation complete\u2026',\n 'detail.waitingWeb': 'Remote installation complete; waiting for DSH Web\u2026',\n 'detail.stillWaiting': 'Still waiting for remote DSH Web\u2026',\n 'detail.readingState': 'Reading the remote agent state\u2026',\n 'detail.tunnel': 'Establishing the SSH tunnel\u2026',\n 'detail.checkingAgent': 'Checking the remote agent\u2026',\n 'detail.reconcilingModel': 'Synchronizing the remote model environment\u2026',\n 'dialog.title': 'New workspace',\n 'dialog.close': 'Close',\n 'dialog.name': 'Workspace name',\n 'dialog.namePlaceholder': 'Workspace name (optional)',\n 'dialog.source': 'Source folder',\n 'dialog.addToPrefix': 'Add a folder on ',\n 'dialog.addToSuffix': '',\n 'dialog.add': 'Add',\n 'dialog.local': 'This computer',\n 'dialog.remoteDevices': 'Remote devices',\n 'dialog.addRemote': '+ Add remote\u2026',\n 'dialog.addRemoteHint': 'Add and connect a remote host in Settings \u2192 Remote development first.',\n 'dialog.cancel': 'Cancel',\n 'dialog.create': 'Create workspace',\n 'dialog.creating': 'Creating\u2026',\n 'dialog.createFailed': 'Could not create the workspace',\n 'dialog.removeFolder': 'Remove folder',\n 'dialog.selectedFallback': 'The remote workspace was created, but the local mirror has not synced yet',\n 'dialog.folderTitle': 'Choose a source folder',\n 'dialog.up': 'Parent folder',\n 'dialog.selectFolder': 'Select current folder',\n 'dialog.reading': 'Reading folder\u2026',\n 'dialog.emptyFolder': 'No subfolders here',\n 'dialog.readFailed': 'Could not read the folder',\n 'dialog.nativePickerFailed': 'Could not open the system folder picker',\n 'dialog.useFolder': 'Use folder',\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n dshRemote: CopyKey\n }\n}\n\nexport type Translate = (key: CopyKey) => string\n\nexport interface LocaleFace {\n register(namespace: string, dictionaries: { zh: Record<string, string>; en: Record<string, string> }): () => void\n bind(namespace: string): Translate\n}\n", "/**\n * Codex-style unified workspace creation dialog for the sidebar + button.\n *\n * One modal owns the destination (local or a connected remote host), the\n * optional workspace name, and the source folder browser. It is intentionally\n * not a separate local/remote menu.\n *\n * @module dsh-remote-local/client/workspace-add\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { HostView } from '../hosts/types.ts'\nimport type { HostsApi } from './api.ts'\nimport type { Translate } from './locale.ts'\n\nconst ADD_LABELS = new Set(['Add workspace', '\u6DFB\u52A0\u5DE5\u4F5C\u533A'])\nconst NATIVE_CLICK_FLAG = 'dshrNativeClick'\nconst DIALOG_CLASS = 'dshr-workspace-add-dialog'\nlet closeDialog: (() => void) | undefined\nlet closeBrowser: (() => void) | undefined\nlet closeMenu: (() => void) | undefined\n\ninterface WorkspaceFlowContext {\n readonly ctx: Context\n readonly api: HostsApi\n readonly t: Translate\n}\n\ntype Destination = { readonly kind: 'local' } | { readonly kind: 'remote'; readonly host: HostView }\n\ninterface HostDirectoryPicker {\n pick(): Promise<\n | { readonly ok: true; readonly value: string | null }\n | { readonly ok: false; readonly error: { readonly message: string } }\n >\n}\n\ninterface DesktopDirectoryPicker {\n pick(): Promise<string | null>\n}\n\nasync function pickLocalDirectory(ctx: Context): Promise<string | null> {\n // DSH Desktop installs this bridge before the client mounts; the stock\n // native directory-flow plugin uses exactly the same entry point.\n const desktop = (globalThis as unknown as { __DSH_DIRECTORY_PICKER__?: DesktopDirectoryPicker }).__DSH_DIRECTORY_PICKER__\n if (desktop !== undefined) return desktop.pick()\n const uiWorkspace = (ctx as unknown as { uiWorkspace?: { pickDirectory?: () => Promise<string | null> } }).uiWorkspace\n if (uiWorkspace?.pickDirectory !== undefined) return uiWorkspace.pickDirectory()\n const remote = (ctx as unknown as { remote?: { directoryPicker?: HostDirectoryPicker } }).remote\n if (remote?.directoryPicker === undefined) throw new Error('directory picker is unavailable')\n const result = await remote.directoryPicker.pick()\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\ninterface DirectoryListing {\n readonly path: string\n readonly parent: string\n readonly entries: readonly { readonly name: string; readonly path: string }[]\n readonly truncated: boolean\n}\n\n/** Install the sidebar add-workspace dialog once per client mount. */\nexport function installWorkspaceAddMenu(ctx: Context, api: HostsApi, t: Translate): void {\n if (typeof document === 'undefined') return\n ensureStyles()\n\n ctx.effect(() => {\n const onClick = (event: MouseEvent): void => {\n const target = event.target\n if (!(target instanceof Element)) return\n const button = target.closest<HTMLButtonElement>('button[aria-label]')\n if (button === null) return\n const label = button.getAttribute('aria-label') ?? ''\n if (!ADD_LABELS.has(label)) return\n if (button.closest('[class*=\"headerActions\"]') === null) return\n if (button.dataset[NATIVE_CLICK_FLAG] === '1') {\n delete button.dataset[NATIVE_CLICK_FLAG]\n return\n }\n event.preventDefault()\n event.stopImmediatePropagation()\n void openCreateDialog({ ctx, api, t }, button)\n }\n document.addEventListener('click', onClick, true)\n return () => {\n document.removeEventListener('click', onClick, true)\n closeTransient()\n }\n }, 'dsh-remote: workspace add dialog')\n}\n\nasync function openCreateDialog(flow: WorkspaceFlowContext, anchor: HTMLButtonElement): Promise<void> {\n closeTransient()\n const overlay = document.createElement('div')\n overlay.className = `${DIALOG_CLASS}-overlay`\n overlay.setAttribute('role', 'presentation')\n const dialog = document.createElement('div')\n dialog.className = DIALOG_CLASS\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('aria-label', flow.t('dialog.title'))\n\n const title = document.createElement('h2')\n title.className = `${DIALOG_CLASS}-title`\n title.textContent = flow.t('dialog.title')\n const header = document.createElement('div')\n header.className = `${DIALOG_CLASS}-header`\n const closeButton = document.createElement('button')\n closeButton.type = 'button'\n closeButton.className = `${DIALOG_CLASS}-close`\n closeButton.setAttribute('aria-label', flow.t('dialog.close'))\n closeButton.textContent = '\u00D7'\n header.append(title, closeButton)\n\n const nameLabel = document.createElement('label')\n nameLabel.className = `${DIALOG_CLASS}-field`\n const nameText = document.createElement('span')\n nameText.textContent = flow.t('dialog.name')\n const nameRow = document.createElement('div')\n nameRow.className = `${DIALOG_CLASS}-input-row`\n const nameIcon = document.createElement('span')\n nameIcon.className = `${DIALOG_CLASS}-input-icon`\n setFolderIcon(nameIcon)\n const nameInput = document.createElement('input')\n nameInput.className = `${DIALOG_CLASS}-input`\n nameInput.placeholder = flow.t('dialog.namePlaceholder')\n nameInput.autocomplete = 'off'\n nameRow.append(nameIcon, nameInput)\n nameLabel.append(nameText, nameRow)\n\n const sourceTitle = document.createElement('h3')\n sourceTitle.className = `${DIALOG_CLASS}-section-title`\n sourceTitle.textContent = flow.t('dialog.source')\n const sourceHeader = document.createElement('div')\n sourceHeader.className = `${DIALOG_CLASS}-source-header`\n const hostIndicator = document.createElement('span')\n hostIndicator.className = `${DIALOG_CLASS}-host-indicator`\n const hostIcon = document.createElement('span')\n hostIcon.className = `${DIALOG_CLASS}-host-icon`\n setComputerIcon(hostIcon)\n const hostLabelText = document.createElement('span')\n hostIndicator.append(hostIcon, hostLabelText)\n sourceHeader.append(sourceTitle, hostIndicator)\n const sourceBox = document.createElement('div')\n sourceBox.className = `${DIALOG_CLASS}-source-box`\n const sourceCenter = document.createElement('div')\n sourceCenter.className = `${DIALOG_CLASS}-source-center`\n const sourceTrigger = document.createElement('button')\n sourceTrigger.type = 'button'\n sourceTrigger.className = `${DIALOG_CLASS}-source-trigger`\n const sourceTriggerText = document.createElement('span')\n const sourceChevron = document.createElement('span')\n sourceChevron.className = `${DIALOG_CLASS}-chevron`\n sourceChevron.textContent = '\u2304'\n sourceTrigger.append(sourceTriggerText, sourceChevron)\n const addFolder = document.createElement('button')\n addFolder.type = 'button'\n addFolder.className = `${DIALOG_CLASS}-add-folder`\n const addFolderIcon = document.createElement('span')\n addFolderIcon.className = `${DIALOG_CLASS}-add-folder-icon`\n const addFolderText = document.createElement('span')\n addFolderText.textContent = flow.t('dialog.add')\n addFolder.append(addFolderIcon, addFolderText)\n sourceCenter.append(sourceTrigger, addFolder)\n const selectedFolder = document.createElement('div')\n selectedFolder.className = `${DIALOG_CLASS}-selected-folder`\n const selectedIcon = document.createElement('span')\n selectedIcon.textContent = '\uD83D\uDCC1'\n const selectedName = document.createElement('span')\n selectedName.className = `${DIALOG_CLASS}-selected-name`\n const removeFolder = document.createElement('button')\n removeFolder.type = 'button'\n removeFolder.className = `${DIALOG_CLASS}-remove-folder`\n removeFolder.setAttribute('aria-label', flow.t('dialog.removeFolder'))\n removeFolder.textContent = '\u00D7'\n selectedFolder.append(selectedIcon, selectedName, removeFolder)\n sourceBox.append(sourceCenter, selectedFolder)\n\n const error = document.createElement('p')\n error.className = `${DIALOG_CLASS}-error`\n error.setAttribute('role', 'alert')\n\n const actions = document.createElement('div')\n actions.className = `${DIALOG_CLASS}-actions`\n const cancel = document.createElement('button')\n cancel.type = 'button'\n cancel.className = `${DIALOG_CLASS}-button`\n cancel.textContent = flow.t('dialog.cancel')\n const create = document.createElement('button')\n create.type = 'button'\n create.className = `${DIALOG_CLASS}-button ${DIALOG_CLASS}-primary`\n create.textContent = flow.t('dialog.create')\n actions.append(cancel, create)\n\n dialog.append(header, nameLabel, sourceHeader, sourceBox, error, actions)\n overlay.append(dialog)\n document.body.append(overlay)\n\n let hosts: HostView[] = []\n let destination: Destination = { kind: 'local' }\n let selectedPath = ''\n const update = (): void => {\n const label = destination.kind === 'local' ? flow.t('dialog.local') : destination.host.label\n sourceTriggerText.textContent = `${flow.t('dialog.addToPrefix')}${label}${flow.t('dialog.addToSuffix')}`\n hostLabelText.textContent = label\n addFolderIcon.textContent = '+ '\n const hasFolder = selectedPath !== ''\n sourceCenter.style.display = hasFolder ? 'none' : 'flex'\n selectedFolder.style.display = hasFolder ? 'flex' : 'none'\n sourceBox.classList.toggle(`${DIALOG_CLASS}-source-box-selected`, hasFolder)\n selectedName.textContent = hasFolder ? folderName(selectedPath) : ''\n selectedFolder.title = hasFolder ? selectedPath : ''\n create.disabled = !hasFolder\n }\n const close = (): void => {\n closeBrowser?.()\n closeMenu?.()\n overlay.remove()\n window.removeEventListener('keydown', keyHandler, true)\n overlay.removeEventListener('pointerdown', outside, true)\n if (closeDialog === close) closeDialog = undefined\n }\n closeDialog = close\n const keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n const outside = (event: Event): void => {\n if (event.target === overlay) close()\n }\n window.addEventListener('keydown', keyHandler, true)\n overlay.addEventListener('pointerdown', outside, true)\n cancel.addEventListener('click', close)\n closeButton.addEventListener('click', close)\n\n sourceTrigger.addEventListener('click', () => {\n openDestinationMenu(sourceTrigger, hosts, destination, flow.t, next => {\n destination = next\n selectedPath = ''\n update()\n })\n })\n addFolder.addEventListener('click', () => {\n if (destination.kind === 'local') {\n addFolder.disabled = true\n void pickLocalDirectory(flow.ctx)\n .then(path => {\n if (path !== null) {\n selectedPath = path\n update()\n }\n })\n .catch(failure => { error.textContent = messageOf(failure, flow.t('dialog.nativePickerFailed')) })\n .finally(() => { addFolder.disabled = false })\n return\n }\n const initial = destination.host.hostInfo?.home ?? '~'\n openDirectoryBrowser(flow, destination, initial, path => {\n selectedPath = path\n update()\n })\n })\n removeFolder.addEventListener('click', () => {\n selectedPath = ''\n update()\n })\n nameInput.addEventListener('input', update)\n\n try {\n const state = await flow.api.state()\n hosts = state.hosts.filter(host => host.phase === 'connected')\n } catch {\n hosts = []\n }\n update()\n create.addEventListener('click', () => {\n if (selectedPath === '') return\n const title = nameInput.value.trim() || folderName(selectedPath)\n create.disabled = true\n cancel.disabled = true\n create.textContent = flow.t('dialog.creating')\n void (async () => {\n try {\n if (destination.kind === 'local') {\n const local = await flow.api.createLocalWorkspace({ path: selectedPath, title })\n close()\n flow.ctx.uiWorkspace.startSession(local.workspaceId as never)\n return\n }\n const workspace = await flow.api.createWorkspace(destination.host.id, {\n path: selectedPath,\n title,\n })\n const session = await flow.api.createSession(destination.host.id, {\n workspaceId: workspace.workspaceId,\n })\n if (session.localSessionId !== undefined) {\n close()\n flow.api.openSession(session.localSessionId)\n return\n }\n const localId = await waitForLocalWorkspace(flow.api, destination.host.id, workspace.workspaceId)\n if (localId === undefined) throw new Error(flow.t('dialog.selectedFallback'))\n close()\n flow.ctx.uiWorkspace.startSession(localId as never)\n } catch (failure) {\n error.textContent = messageOf(failure, flow.t('dialog.createFailed'))\n create.disabled = false\n cancel.disabled = false\n create.textContent = flow.t('dialog.create')\n }\n })()\n })\n\n nameInput.focus()\n}\n\nfunction openDestinationMenu(\n anchor: HTMLElement,\n hosts: readonly HostView[],\n current: Destination,\n t: Translate,\n onPick: (destination: Destination) => void,\n): void {\n closeMenu?.()\n const menu = document.createElement('div')\n menu.className = `${DIALOG_CLASS}-destination-menu`\n const add = (label: string, destination: Destination): void => {\n const item = document.createElement('button')\n item.type = 'button'\n item.className = `${DIALOG_CLASS}-destination-item`\n const text = document.createElement('span')\n text.textContent = label\n const check = document.createElement('span')\n check.className = `${DIALOG_CLASS}-destination-check`\n const selected = current.kind === destination.kind\n && (destination.kind === 'local' || (current.kind === 'remote' && current.host.id === destination.host.id))\n check.textContent = selected ? '\u2713' : ''\n item.append(text, check)\n item.addEventListener('click', () => {\n onPick(destination)\n close()\n })\n menu.append(item)\n }\n add(t('dialog.local'), { kind: 'local' })\n if (hosts.length > 0) {\n const section = document.createElement('div')\n section.className = `${DIALOG_CLASS}-destination-section`\n section.textContent = t('dialog.remoteDevices')\n menu.append(section)\n for (const host of hosts) add(host.label, { kind: 'remote', host })\n }\n const addRemote = document.createElement('button')\n addRemote.type = 'button'\n addRemote.className = `${DIALOG_CLASS}-destination-item ${DIALOG_CLASS}-destination-add`\n addRemote.textContent = t('dialog.addRemote')\n addRemote.addEventListener('click', () => {\n close()\n const error = document.querySelector(`.${DIALOG_CLASS}-error`)\n if (error !== null) error.textContent = t('dialog.addRemoteHint')\n })\n menu.append(addRemote)\n document.body.append(menu)\n const rect = anchor.getBoundingClientRect()\n menu.style.left = `${Math.min(rect.left, window.innerWidth - 260)}px`\n menu.style.top = `${rect.bottom + 6}px`\n const close = (): void => {\n menu.remove()\n window.removeEventListener('pointerdown', dismiss, true)\n if (closeMenu === close) closeMenu = undefined\n }\n closeMenu = close\n const dismiss = (event: Event): void => {\n if (event.target instanceof Node && menu.contains(event.target)) return\n close()\n }\n window.addEventListener('pointerdown', dismiss, true)\n}\n\nasync function openDirectoryBrowser(\n flow: WorkspaceFlowContext,\n destination: Destination,\n initialPath: string,\n onPick: (path: string) => void,\n): Promise<void> {\n closeBrowser?.()\n const overlay = document.createElement('div')\n overlay.className = `${DIALOG_CLASS}-browser-overlay`\n overlay.setAttribute('role', 'presentation')\n const dialog = document.createElement('div')\n dialog.className = `${DIALOG_CLASS} ${DIALOG_CLASS}-browser`\n dialog.setAttribute('role', 'dialog')\n dialog.setAttribute('aria-modal', 'true')\n dialog.setAttribute('aria-label', flow.t('dialog.folderTitle'))\n\n const title = document.createElement('h2')\n title.className = `${DIALOG_CLASS}-browser-title`\n title.textContent = flow.t('dialog.folderTitle')\n const browserHeader = document.createElement('div')\n browserHeader.className = `${DIALOG_CLASS}-browser-header`\n const browserClose = document.createElement('button')\n browserClose.type = 'button'\n browserClose.className = `${DIALOG_CLASS}-close`\n browserClose.setAttribute('aria-label', flow.t('dialog.close'))\n browserClose.textContent = '\u00D7'\n browserHeader.append(title, browserClose)\n const pathRow = document.createElement('div')\n pathRow.className = `${DIALOG_CLASS}-browser-path-row`\n const up = document.createElement('button')\n up.type = 'button'\n up.className = `${DIALOG_CLASS}-up`\n up.textContent = '\u2191'\n up.setAttribute('aria-label', flow.t('dialog.up'))\n const pathInput = document.createElement('input')\n pathInput.className = `${DIALOG_CLASS}-browser-path`\n pathInput.value = initialPath\n pathInput.autocomplete = 'off'\n pathRow.append(up, pathInput)\n const status = document.createElement('p')\n status.className = `${DIALOG_CLASS}-browser-status`\n status.textContent = flow.t('dialog.selectFolder')\n const list = document.createElement('div')\n list.className = `${DIALOG_CLASS}-browser-list`\n const actions = document.createElement('div')\n actions.className = `${DIALOG_CLASS}-actions`\n const cancel = document.createElement('button')\n cancel.type = 'button'\n cancel.className = `${DIALOG_CLASS}-button`\n cancel.textContent = flow.t('dialog.cancel')\n const use = document.createElement('button')\n use.type = 'button'\n use.className = `${DIALOG_CLASS}-button ${DIALOG_CLASS}-primary`\n use.textContent = flow.t('dialog.useFolder')\n actions.append(cancel, use)\n dialog.append(browserHeader, pathRow, status, list, actions)\n overlay.append(dialog)\n document.body.append(overlay)\n\n let current = initialPath\n let parent = initialPath\n let currentEntries: readonly { readonly name: string; readonly path: string }[] = []\n let requestSeq = 0\n let filterTimer: number | undefined\n\n const fetchListing = async (path: string): Promise<DirectoryListing | undefined> => {\n const sequence = ++requestSeq\n status.textContent = flow.t('dialog.reading')\n status.classList.remove(`${DIALOG_CLASS}-error-text`)\n try {\n const listing: DirectoryListing = destination.kind === 'local'\n ? await flow.api.listLocalDirectories(path)\n : await flow.api.listDirectories(destination.host.id, path)\n if (sequence !== requestSeq) return undefined\n return listing\n } catch (failure) {\n if (sequence === requestSeq) {\n status.textContent = messageOf(failure, flow.t('dialog.readFailed'))\n status.classList.add(`${DIALOG_CLASS}-error-text`)\n }\n return undefined\n }\n }\n\n const render = (entries: readonly { readonly name: string; readonly path: string }[]): void => {\n list.replaceChildren()\n if (entries.length === 0) {\n const empty = document.createElement('p')\n empty.className = `${DIALOG_CLASS}-browser-empty`\n empty.textContent = flow.t('dialog.emptyFolder')\n list.append(empty)\n return\n }\n for (const entry of entries) {\n const item = document.createElement('button')\n item.type = 'button'\n item.className = `${DIALOG_CLASS}-browser-entry`\n const icon = document.createElement('span')\n icon.textContent = '\uD83D\uDCC1'\n const label = document.createElement('span')\n label.textContent = entry.name\n item.append(icon, label)\n item.addEventListener('click', () => { void load(entry.path) })\n list.append(item)\n }\n }\n\n const load = async (path: string): Promise<void> => {\n const listing = await fetchListing(path)\n if (listing === undefined) return\n current = listing.path\n parent = listing.parent\n currentEntries = listing.entries\n pathInput.value = listing.path\n status.textContent = flow.t('dialog.selectFolder')\n render(listing.entries)\n }\n\n const applyInputFilter = async (raw: string): Promise<void> => {\n if (raw === '') return\n const slash = raw.lastIndexOf('/')\n const dir = slash < 0 ? current : (raw.slice(0, slash + 1) || '/')\n const query = slash < 0 ? raw : raw.slice(slash + 1)\n if (query === '') {\n // A trailing slash is an explicit directory navigation.\n await load(raw)\n return\n }\n const normalizedCurrent = current.replace(/\\/+$/u, '') || '/'\n const normalizedDir = dir.replace(/\\/+$/u, '') || '/'\n if (normalizedDir === normalizedCurrent) {\n const needle = query.toLocaleLowerCase()\n render(currentEntries.filter(entry => entry.name.toLocaleLowerCase().startsWith(needle)))\n status.textContent = flow.t('dialog.selectFolder')\n return\n }\n const listing = await fetchListing(dir)\n if (listing === undefined) return\n current = listing.path\n parent = listing.parent\n currentEntries = listing.entries\n const needle = query.toLocaleLowerCase()\n render(listing.entries.filter(entry => entry.name.toLocaleLowerCase().startsWith(needle)))\n status.textContent = flow.t('dialog.selectFolder')\n }\n\n const close = (): void => {\n overlay.remove()\n window.removeEventListener('keydown', keyHandler, true)\n overlay.removeEventListener('pointerdown', outside, true)\n if (closeBrowser === close) closeBrowser = undefined\n }\n closeBrowser = close\n const keyHandler = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n const outside = (event: Event): void => {\n if (event.target === overlay) close()\n }\n window.addEventListener('keydown', keyHandler, true)\n overlay.addEventListener('pointerdown', outside, true)\n cancel.addEventListener('click', close)\n browserClose.addEventListener('click', close)\n use.addEventListener('click', () => {\n onPick(current)\n close()\n })\n up.addEventListener('click', () => {\n if (parent !== '' && parent !== current) void load(parent)\n })\n pathInput.addEventListener('input', () => {\n if (filterTimer !== undefined) window.clearTimeout(filterTimer)\n const value = pathInput.value\n filterTimer = window.setTimeout(() => { void applyInputFilter(value) }, 140)\n })\n pathInput.addEventListener('keydown', event => {\n if (event.key !== 'Enter') return\n event.preventDefault()\n const value = pathInput.value.trim()\n if (value !== '') void applyInputFilter(value)\n })\n void load(initialPath)\n}\n\nasync function waitForLocalWorkspace(api: HostsApi, hostId: string, workspaceId: string): Promise<string | undefined> {\n for (let attempt = 0; attempt < 40; attempt += 1) {\n const result = await api.workspaces(hostId)\n const workspace = result.workspaces.find(item => item.workspaceId === workspaceId)\n if (workspace?.localWorkspaceId !== undefined) return workspace.localWorkspaceId\n await new Promise(resolve => setTimeout(resolve, 500))\n }\n return undefined\n}\n\nfunction closeTransient(): void {\n closeDialog?.()\n closeBrowser?.()\n closeMenu?.()\n}\n\nfunction messageOf(failure: unknown, fallback: string): string {\n if (failure instanceof Error && failure.message !== '') return failure.message\n return fallback\n}\n\nfunction setFolderIcon(icon: HTMLElement): void {\n icon.innerHTML = '<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><path d=\"M3.5 7.5A2.5 2.5 0 0 1 6 5h4l2 2h6a2.5 2.5 0 0 1 2.5 2.5v7A2.5 2.5 0 0 1 18 19H6a2.5 2.5 0 0 1-2.5-2.5v-9Z\" stroke=\"currentColor\" stroke-width=\"1.5\"/></svg>'\n}\n\nfunction folderName(path: string): string {\n const clean = path.replace(/[\\\\/]+$/u, '')\n const parts = clean.split(/[\\\\/]+/u)\n return parts[parts.length - 1] ?? clean\n}\n\nfunction setComputerIcon(icon: HTMLElement): void {\n icon.innerHTML = '<svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"12\" rx=\"1.7\" stroke=\"currentColor\" stroke-width=\"1.5\"/><path d=\"M8 20h8M12 17v3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>'\n}\n\nfunction ensureStyles(): void {\n const existing = document.getElementById('dshr-workspace-add-style')\n const style = existing instanceof HTMLStyleElement ? existing : document.createElement('style')\n style.id = 'dshr-workspace-add-style'\n style.textContent = `\n .${DIALOG_CLASS}-overlay {\n position: fixed; inset: 0; z-index: 100001; display: grid; place-items: center;\n padding: 24px; background: rgba(0,0,0,.55);\n }\n .${DIALOG_CLASS} {\n width: min(632px, calc(100vw - 48px));\n box-sizing: border-box; padding: 26px; display: flex; flex-direction: column;\n border-radius: 14px; border: 1px solid rgba(255,255,255,.1);\n background: #242424; color: #f2f2f2; box-shadow: 0 28px 80px rgba(0,0,0,.65);\n font: 14px/1.45 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n }\n .${DIALOG_CLASS}-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; }\n .${DIALOG_CLASS}-title { margin: 0; font-size: 28px; line-height: 1.1; font-weight: 700; letter-spacing: -.02em; }\n .${DIALOG_CLASS}-close { border: 0; background: transparent; color: rgba(255,255,255,.75); font-size: 30px; line-height: 1; cursor: pointer; padding: 0 2px; }\n .${DIALOG_CLASS}-close:hover { color: #fff; }\n .${DIALOG_CLASS}-field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }\n .${DIALOG_CLASS}-field > span { font-size: 13px; color: rgba(255,255,255,.72); }\n .${DIALOG_CLASS}-input-row { display: flex; align-items: center; gap: 10px; border: 1px solid rgba(255,255,255,.24); border-radius: 9px; padding: 0 12px; background: transparent; }\n .${DIALOG_CLASS}-input-icon { display: inline-flex; color: rgba(255,255,255,.7); }\n .${DIALOG_CLASS}-input { width: 100%; border: 0; outline: none; background: transparent; color: inherit; font: inherit; font-size: 14px; padding: 13px 0; }\n .${DIALOG_CLASS}-source-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 4px 0 10px; }\n .${DIALOG_CLASS}-section-title { margin: 0; font-size: 17px; font-weight: 600; color: rgba(255,255,255,.92); }\n .${DIALOG_CLASS}-host-indicator { display: inline-flex; align-items: center; gap: 8px; color: rgba(255,255,255,.62); font-size: 15px; }\n .${DIALOG_CLASS}-host-icon { display: inline-flex; }\n .${DIALOG_CLASS}-source-box { position: relative; border: 1px solid rgba(255,255,255,.16); border-radius: 9px; padding: 24px 16px; min-height: 150px; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; }\n .${DIALOG_CLASS}-source-center { display: flex; flex-direction: column; align-items: center; gap: 16px; }\n .${DIALOG_CLASS}-source-trigger { display: inline-flex; align-items: center; gap: 8px; border: 0; background: transparent; color: rgba(255,255,255,.75); font: inherit; font-size: 15px; cursor: pointer; }\n .${DIALOG_CLASS}-source-trigger span:first-child { color: #fff; font-weight: 600; }\n .${DIALOG_CLASS}-chevron { font-size: 18px; line-height: 1; }\n .${DIALOG_CLASS}-add-folder { display: inline-flex; align-items: center; gap: 8px; border: 0; border-radius: 8px; padding: 8px 14px; background: rgba(255,255,255,.12); color: #fff; font: inherit; font-size: 14px; cursor: pointer; }\n .${DIALOG_CLASS}-add-folder:hover { background: rgba(255,255,255,.18); }\n .${DIALOG_CLASS}-add-folder-icon { font-size: 18px; line-height: 1; }\n .${DIALOG_CLASS}-source-box-selected { padding: 0; min-height: 0; flex: none; justify-content: flex-start; }\n .${DIALOG_CLASS}-selected-folder { display: none; align-items: center; gap: 12px; width: 100%; box-sizing: border-box; padding: 12px 14px; color: rgba(255,255,255,.92); font-size: 16px; }\n .${DIALOG_CLASS}-selected-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .${DIALOG_CLASS}-remove-folder { flex: none; border: 0; background: transparent; color: rgba(255,255,255,.6); font-size: 24px; line-height: 1; cursor: pointer; padding: 0 2px; }\n .${DIALOG_CLASS}-remove-folder:hover { color: #fff; }\n .${DIALOG_CLASS}-error { margin: 6px 0 0; color: #ff8b8b; font-size: 12px; white-space: pre-wrap; }\n .${DIALOG_CLASS}-error:empty { display: none; }\n .${DIALOG_CLASS}-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }\n .${DIALOG_CLASS}-button { padding: 11px 18px; border-radius: 8px; border: 1px solid rgba(255,255,255,.18); background: transparent; color: #eee; cursor: pointer; font: inherit; font-size: 15px; }\n .${DIALOG_CLASS}-button:disabled { opacity: .45; cursor: default; }\n .${DIALOG_CLASS}-primary { border-color: #bdbdbd; background: #bdbdbd; color: #1a1a1a; font-weight: 600; }\n .${DIALOG_CLASS}-primary:hover:not(:disabled) { background: #d0d0d0; }\n .${DIALOG_CLASS}-destination-menu {\n position: fixed; z-index: 100010; min-width: 250px; padding: 6px;\n border-radius: 12px; border: 1px solid rgba(255,255,255,.14); background: #2a2a2a; color: #eee;\n box-shadow: 0 18px 48px rgba(0,0,0,.55); font: 14px/1.4 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n }\n .${DIALOG_CLASS}-destination-item { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 10px 12px; border: 0; border-radius: 8px; background: transparent; color: inherit; font: inherit; cursor: pointer; text-align: left; }\n .${DIALOG_CLASS}-destination-item:hover { background: rgba(255,255,255,.09); }\n .${DIALOG_CLASS}-destination-section { padding: 14px 12px 6px; color: rgba(255,255,255,.5); font-size: 13px; }\n .${DIALOG_CLASS}-destination-check { color: #bdbdbd; }\n .${DIALOG_CLASS}-destination-add { color: rgba(255,255,255,.75); }\n .${DIALOG_CLASS}-browser-overlay { position: fixed; inset: 0; z-index: 100002; display: grid; place-items: center; background: rgba(0,0,0,.6); padding: 24px; }\n .${DIALOG_CLASS}-browser { width: 640px; max-height: 86vh; display: flex; flex-direction: column; padding: 26px; }\n .${DIALOG_CLASS}-browser-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }\n .${DIALOG_CLASS}-browser-title { margin: 0; font-size: 30px; line-height: 1.15; font-weight: 700; }\n .${DIALOG_CLASS}-browser-path-row { display: flex; align-items: center; gap: 8px; }\n .${DIALOG_CLASS}-up { flex: none; width: 34px; height: 34px; border: 0; background: transparent; color: rgba(255,255,255,.65); font-size: 22px; cursor: pointer; }\n .${DIALOG_CLASS}-browser-path { flex: 1; border: 1px solid rgba(255,255,255,.22); border-radius: 9px; background: transparent; color: #fff; font: inherit; font-size: 16px; padding: 12px 14px; outline: none; }\n .${DIALOG_CLASS}-browser-path:focus { border-color: #4f8cff; }\n .${DIALOG_CLASS}-browser-status { margin: 14px 0 8px; color: rgba(255,255,255,.55); font-size: 13px; }\n .${DIALOG_CLASS}-browser-list { flex: 1; min-height: 220px; max-height: 420px; overflow: auto; border: 1px solid rgba(255,255,255,.16); border-radius: 12px; padding: 6px; }\n .${DIALOG_CLASS}-browser-entry { display: flex; align-items: center; gap: 12px; width: 100%; box-sizing: border-box; padding: 11px 12px; border: 0; border-radius: 8px; background: transparent; color: #fff; font: inherit; font-size: 16px; text-align: left; cursor: pointer; }\n .${DIALOG_CLASS}-browser-entry:hover { background: rgba(255,255,255,.08); }\n .${DIALOG_CLASS}-browser-empty { margin: 16px 12px; color: rgba(255,255,255,.5); font-size: 13px; }\n `\n if (existing === null) document.head.append(style)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["messageOf", "title", "needle"]
|
|
7
7
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* dsh-remote-local-plugin@0.8.
|
|
1
|
+
/* dsh-remote-local-plugin@0.8.3 — bundled host entry */
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
@@ -23,6 +23,8 @@ var Config = z.object({
|
|
|
23
23
|
remoteDshVersion: z.string().default("0.2.1-rc.2"),
|
|
24
24
|
remotePnpmVersion: z.string().default("11.21.0"),
|
|
25
25
|
remoteNodeVersion: z.string().default("22.19.0"),
|
|
26
|
+
remoteInstallProxy: z.string().default(""),
|
|
27
|
+
remoteInstallNoProxy: z.string().default("127.0.0.1,localhost"),
|
|
26
28
|
autoInstallNode: z.boolean().default(true),
|
|
27
29
|
remoteStart: z.string().default("systemd"),
|
|
28
30
|
provisionTimeoutMs: z.number().min(6e4).max(18e5).default(6e5),
|
|
@@ -80,6 +82,8 @@ function resolveConfig(config = {}, env = process.env) {
|
|
|
80
82
|
remoteDshVersion: config.remoteDshVersion ?? "0.2.1-rc.2",
|
|
81
83
|
remotePnpmVersion: config.remotePnpmVersion ?? "11.21.0",
|
|
82
84
|
remoteNodeVersion: config.remoteNodeVersion ?? "22.19.0",
|
|
85
|
+
remoteInstallProxy: config.remoteInstallProxy ?? "",
|
|
86
|
+
remoteInstallNoProxy: config.remoteInstallNoProxy ?? "127.0.0.1,localhost",
|
|
83
87
|
autoInstallNode: config.autoInstallNode ?? true,
|
|
84
88
|
remoteStart,
|
|
85
89
|
provisionTimeoutMs: config.provisionTimeoutMs ?? 6e5,
|
|
@@ -2793,12 +2797,67 @@ AUTO_INSTALL_NODE=${options.autoInstallNode ? "1" : "0"}
|
|
|
2793
2797
|
AGENT_TARBALL=${shellLiteral(options.agentTarball)}
|
|
2794
2798
|
MODEL_BASE_URL=${options.modelBaseUrl === void 0 ? "''" : shellLiteral(options.modelBaseUrl)}
|
|
2795
2799
|
MODEL_API_KEY=${options.modelApiKey === void 0 ? "''" : shellLiteral(options.modelApiKey)}
|
|
2800
|
+
PROXY_URL=${options.proxyUrl === void 0 ? "''" : shellLiteral(options.proxyUrl)}
|
|
2801
|
+
PROXY_NO_PROXY=${options.noProxy === void 0 ? "''" : shellLiteral(options.noProxy)}
|
|
2796
2802
|
STATE_FILE="$DSH_HOME/remote-agent/agent.json"
|
|
2797
2803
|
WAIT_FOR_STATE=${options.start === "none" ? 0 : 1}
|
|
2798
2804
|
|
|
2799
2805
|
export DSH_HOME
|
|
2800
2806
|
mkdir -p "$INSTALL_DIR" "$DSH_HOME/remote-agent"
|
|
2801
2807
|
echo "dsh-remote: preparing remote install"
|
|
2808
|
+
if [ -z "$PROXY_URL" ]; then
|
|
2809
|
+
# Reuse a proxy already configured by the account's actual login shell.
|
|
2810
|
+
LOGIN_SHELL="\${SHELL:-}"
|
|
2811
|
+
if [ -z "$LOGIN_SHELL" ] || [ ! -x "$LOGIN_SHELL" ]; then
|
|
2812
|
+
if command -v getent >/dev/null 2>&1; then
|
|
2813
|
+
LOGIN_SHELL="$(getent passwd "$(id -un)" 2>/dev/null | cut -d: -f7)"
|
|
2814
|
+
else
|
|
2815
|
+
LOGIN_SHELL="$(awk -F: -v u="$(id -un)" '$1 == u { print $7; exit }' /etc/passwd)"
|
|
2816
|
+
fi
|
|
2817
|
+
fi
|
|
2818
|
+
if [ -z "$LOGIN_SHELL" ] || [ ! -x "$LOGIN_SHELL" ]; then
|
|
2819
|
+
LOGIN_SHELL=/bin/sh
|
|
2820
|
+
fi
|
|
2821
|
+
PROXY_TIMEOUT=""
|
|
2822
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
2823
|
+
PROXY_TIMEOUT="timeout 5"
|
|
2824
|
+
fi
|
|
2825
|
+
read_proxy_env() {
|
|
2826
|
+
if [ -n "$PROXY_TIMEOUT" ]; then
|
|
2827
|
+
$PROXY_TIMEOUT "$LOGIN_SHELL" "$@" -c 'env' 2>/dev/null || true
|
|
2828
|
+
else
|
|
2829
|
+
"$LOGIN_SHELL" "$@" -c 'env' 2>/dev/null || true
|
|
2830
|
+
fi
|
|
2831
|
+
}
|
|
2832
|
+
proxy_from_env() {
|
|
2833
|
+
local proxy_value
|
|
2834
|
+
proxy_value="$(printf '%s\\n' "$1" | tr -d '\\r' | sed -n -e 's/^HTTPS_PROXY=//p' -e 's/^https_proxy=//p' | head -n 1)"
|
|
2835
|
+
if [ -z "$proxy_value" ]; then
|
|
2836
|
+
proxy_value="$(printf '%s\\n' "$1" | tr -d '\\r' | sed -n -e 's/^HTTP_PROXY=//p' -e 's/^http_proxy=//p' | head -n 1)"
|
|
2837
|
+
fi
|
|
2838
|
+
printf '%s' "$proxy_value"
|
|
2839
|
+
}
|
|
2840
|
+
PROXY_ENV="$(read_proxy_env -l -i)"
|
|
2841
|
+
PROXY_URL="$(proxy_from_env "$PROXY_ENV")"
|
|
2842
|
+
if [ -z "$PROXY_URL" ]; then
|
|
2843
|
+
PROXY_ENV="$(read_proxy_env -l)"
|
|
2844
|
+
PROXY_URL="$(proxy_from_env "$PROXY_ENV")"
|
|
2845
|
+
fi
|
|
2846
|
+
if [ -z "$PROXY_URL" ]; then
|
|
2847
|
+
PROXY_ENV="$(read_proxy_env -i)"
|
|
2848
|
+
PROXY_URL="$(proxy_from_env "$PROXY_ENV")"
|
|
2849
|
+
fi
|
|
2850
|
+
fi
|
|
2851
|
+
if [ -n "$PROXY_URL" ]; then
|
|
2852
|
+
export HTTP_PROXY="$PROXY_URL" http_proxy="$PROXY_URL"
|
|
2853
|
+
export HTTPS_PROXY="$PROXY_URL" https_proxy="$PROXY_URL"
|
|
2854
|
+
export ALL_PROXY="$PROXY_URL" all_proxy="$PROXY_URL"
|
|
2855
|
+
export npm_config_proxy="$PROXY_URL" npm_config_https_proxy="$PROXY_URL"
|
|
2856
|
+
if [ -n "$PROXY_NO_PROXY" ]; then
|
|
2857
|
+
export NO_PROXY="$PROXY_NO_PROXY" no_proxy="$PROXY_NO_PROXY"
|
|
2858
|
+
fi
|
|
2859
|
+
echo "dsh-remote: install proxy configured"
|
|
2860
|
+
fi
|
|
2802
2861
|
|
|
2803
2862
|
${nodePathPrelude()}
|
|
2804
2863
|
|
|
@@ -3030,8 +3089,13 @@ function runRemoteScript(target, script, options) {
|
|
|
3030
3089
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
3031
3090
|
code: code ?? (signal === null ? 1 : 137)
|
|
3032
3091
|
};
|
|
3033
|
-
if (result.code === 0)
|
|
3034
|
-
|
|
3092
|
+
if (result.code === 0) {
|
|
3093
|
+
resolve4(result);
|
|
3094
|
+
return;
|
|
3095
|
+
}
|
|
3096
|
+
const tail = result.stderr.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line !== "").slice(-2).join(" | ").slice(0, 500);
|
|
3097
|
+
const message = `remote bootstrap exited with ${String(result.code)}${tail === "" ? "" : `: ${tail}`}`;
|
|
3098
|
+
reject(Object.assign(new Error(message), { result }));
|
|
3035
3099
|
});
|
|
3036
3100
|
child.stdin.end(script);
|
|
3037
3101
|
});
|
|
@@ -3057,7 +3121,9 @@ async function provisionRemoteAgent(options) {
|
|
|
3057
3121
|
start: options.start,
|
|
3058
3122
|
agentTarball: remoteTarball,
|
|
3059
3123
|
...options.modelBaseUrl === void 0 ? {} : { modelBaseUrl: options.modelBaseUrl },
|
|
3060
|
-
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey }
|
|
3124
|
+
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey },
|
|
3125
|
+
...options.proxyUrl === void 0 ? {} : { proxyUrl: options.proxyUrl },
|
|
3126
|
+
...options.noProxy === void 0 ? {} : { noProxy: options.noProxy }
|
|
3061
3127
|
});
|
|
3062
3128
|
let stdoutBuffer = "";
|
|
3063
3129
|
let stderrBuffer = "";
|
|
@@ -3218,6 +3284,8 @@ var RemoteProvisioner = class {
|
|
|
3218
3284
|
async ensureInstalled(target, options = {}) {
|
|
3219
3285
|
const tarball = findAgentTarball();
|
|
3220
3286
|
options.onProgress?.("\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026");
|
|
3287
|
+
const proxyUrl = this.#config.remoteInstallProxy.trim() || void 0;
|
|
3288
|
+
if (proxyUrl !== void 0) options.onProgress?.("\u6B63\u5728\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026");
|
|
3221
3289
|
try {
|
|
3222
3290
|
await provisionRemoteAgent({
|
|
3223
3291
|
target: target.canonical,
|
|
@@ -3236,6 +3304,10 @@ var RemoteProvisioner = class {
|
|
|
3236
3304
|
...options.modelBaseUrl === void 0 ? {} : { modelBaseUrl: options.modelBaseUrl },
|
|
3237
3305
|
...options.modelApiKey === void 0 ? {} : { modelApiKey: options.modelApiKey },
|
|
3238
3306
|
verbose: false,
|
|
3307
|
+
...proxyUrl === void 0 ? {} : {
|
|
3308
|
+
proxyUrl,
|
|
3309
|
+
noProxy: this.#config.remoteInstallNoProxy
|
|
3310
|
+
},
|
|
3239
3311
|
onProgress: (line) => {
|
|
3240
3312
|
const message = progressForLine(line);
|
|
3241
3313
|
if (message !== void 0) options.onProgress?.(message);
|
|
@@ -3285,6 +3357,7 @@ var PROVISION_PROGRESS = [
|
|
|
3285
3357
|
["uploading agent package", "\u6B63\u5728\u4E0A\u4F20\u8FDC\u7AEF agent \u5B89\u88C5\u5305\u2026"],
|
|
3286
3358
|
["agent package uploaded", "\u5B89\u88C5\u5305\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5F00\u59CB\u8FDC\u7AEF\u5B89\u88C5\u2026"],
|
|
3287
3359
|
["preparing remote install", "\u6B63\u5728\u51C6\u5907\u8FDC\u7AEF\u5B89\u88C5\u73AF\u5883\u2026"],
|
|
3360
|
+
["install proxy configured", "\u5DF2\u914D\u7F6E\u8FDC\u7AEF\u5B89\u88C5\u4EE3\u7406\u2026"],
|
|
3288
3361
|
["downloading node.js", "\u6B63\u5728\u4E0B\u8F7D Node.js\u2026"],
|
|
3289
3362
|
["installed node.js", "Node.js \u5B89\u88C5\u5B8C\u6210\uFF0C\u7EE7\u7EED\u5B89\u88C5 pnpm/DSH\u2026"],
|
|
3290
3363
|
["node ready", "Node.js \u5DF2\u5C31\u7EEA\uFF0C\u51C6\u5907\u5B89\u88C5 pnpm/DSH\u2026"],
|
package/lib/types/config.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ export interface Config {
|
|
|
27
27
|
readonly remotePnpmVersion?: string;
|
|
28
28
|
/** Node.js version installed into the remote install dir when none is usable. */
|
|
29
29
|
readonly remoteNodeVersion?: string;
|
|
30
|
+
/** Optional HTTP(S) proxy for remote provisioning; empty means auto-detect. */
|
|
31
|
+
readonly remoteInstallProxy?: string;
|
|
32
|
+
/** Comma-separated proxy bypass list. */
|
|
33
|
+
readonly remoteInstallNoProxy?: string;
|
|
30
34
|
/** Download Node.js into the remote install dir when it is missing or too old. */
|
|
31
35
|
readonly autoInstallNode?: boolean;
|
|
32
36
|
/** `systemd`, `nohup`, or `none`. */
|
|
@@ -71,6 +75,8 @@ export interface ResolvedConfig {
|
|
|
71
75
|
readonly remoteDshVersion: string;
|
|
72
76
|
readonly remotePnpmVersion: string;
|
|
73
77
|
readonly remoteNodeVersion: string;
|
|
78
|
+
readonly remoteInstallProxy: string;
|
|
79
|
+
readonly remoteInstallNoProxy: string;
|
|
74
80
|
readonly autoInstallNode: boolean;
|
|
75
81
|
readonly remoteStart: RemoteStartMode;
|
|
76
82
|
readonly provisionTimeoutMs: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-local-plugin",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "DSH remote-development local plugin: host registry, SSH tunnels, remote workspace/session discovery, an authenticated Connection RPC surface, agent tools, and a Settings page.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|