@jingyi0605/codingns4dsh 0.1.0
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 +1114 -0
- package/assets/provider-icons/claude-code.png +0 -0
- package/assets/provider-icons/codex.png +0 -0
- package/assets/provider-icons/command-code.svg +5 -0
- package/assets/provider-icons/deepseek-harness.svg +9 -0
- package/assets/provider-icons/gemini.png +0 -0
- package/assets/provider-icons/grok.png +0 -0
- package/assets/provider-icons/kimi.png +0 -0
- package/assets/provider-icons/opencode.png +0 -0
- package/assets/provider-icons/pi.svg +7 -0
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +97 -0
- package/data/build/dist/bootstrap/dsh-connection-adapter.js +169 -0
- package/data/build/dist/bootstrap/index.d.ts +38 -0
- package/data/build/dist/bootstrap/index.js +44 -0
- package/data/build/dist/client/account-bar.d.ts +9 -0
- package/data/build/dist/client/account-bar.js +398 -0
- package/data/build/dist/client/bundle.js +26167 -0
- package/data/build/dist/client/cli-catalog.d.ts +24 -0
- package/data/build/dist/client/cli-catalog.js +108 -0
- package/data/build/dist/client/cli-slots.d.ts +38 -0
- package/data/build/dist/client/cli-slots.js +297 -0
- package/data/build/dist/client/debug/ui.d.ts +12 -0
- package/data/build/dist/client/debug/ui.js +451 -0
- package/data/build/dist/client/dsh-h5-bootstrap.d.ts +64 -0
- package/data/build/dist/client/dsh-h5-bootstrap.js +293 -0
- package/data/build/dist/client/dsh-runtime-version.d.ts +3 -0
- package/data/build/dist/client/dsh-runtime-version.js +11 -0
- package/data/build/dist/client/external-tool-stream.d.ts +24 -0
- package/data/build/dist/client/external-tool-stream.js +114 -0
- package/data/build/dist/client/features/cli-adapters.d.ts +7 -0
- package/data/build/dist/client/features/cli-adapters.js +215 -0
- package/data/build/dist/client/features/debug.d.ts +4 -0
- package/data/build/dist/client/features/debug.js +24 -0
- package/data/build/dist/client/features/index.d.ts +33 -0
- package/data/build/dist/client/features/index.js +44 -0
- package/data/build/dist/client/features/lan-access-panel.d.ts +5 -0
- package/data/build/dist/client/features/lan-access-panel.js +146 -0
- package/data/build/dist/client/features/lan-access.d.ts +9 -0
- package/data/build/dist/client/features/lan-access.js +30 -0
- package/data/build/dist/client/features/login-protection-panel.d.ts +5 -0
- package/data/build/dist/client/features/login-protection-panel.js +91 -0
- package/data/build/dist/client/features/login-protection-session.d.ts +6 -0
- package/data/build/dist/client/features/login-protection-session.js +25 -0
- package/data/build/dist/client/features/login-protection.d.ts +4 -0
- package/data/build/dist/client/features/login-protection.js +23 -0
- package/data/build/dist/client/features/reverse-proxy-panel.d.ts +9 -0
- package/data/build/dist/client/features/reverse-proxy-panel.js +159 -0
- package/data/build/dist/client/features/reverse-proxy.d.ts +12 -0
- package/data/build/dist/client/features/reverse-proxy.js +112 -0
- package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +5 -0
- package/data/build/dist/client/features/terminal-enhancement-panel.js +160 -0
- package/data/build/dist/client/features/terminal-enhancement.d.ts +4 -0
- package/data/build/dist/client/features/terminal-enhancement.js +24 -0
- package/data/build/dist/client/features/types.d.ts +58 -0
- package/data/build/dist/client/features/types.js +2 -0
- package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +5 -0
- package/data/build/dist/client/features/workspace-session-enhancement-panel.js +66 -0
- package/data/build/dist/client/features/workspace-session-enhancement.d.ts +4 -0
- package/data/build/dist/client/features/workspace-session-enhancement.js +101 -0
- package/data/build/dist/client/h5-bootstrap-entry.d.ts +2 -0
- package/data/build/dist/client/h5-bootstrap-entry.js +17 -0
- package/data/build/dist/client/index.d.ts +31 -0
- package/data/build/dist/client/index.js +98 -0
- package/data/build/dist/client/lan-access.d.ts +28 -0
- package/data/build/dist/client/lan-access.js +68 -0
- package/data/build/dist/client/locale.d.ts +20 -0
- package/data/build/dist/client/locale.js +393 -0
- package/data/build/dist/client/provider-icon-assets.d.ts +2 -0
- package/data/build/dist/client/provider-icon-assets.js +23 -0
- package/data/build/dist/client/provider-icons.d.ts +19 -0
- package/data/build/dist/client/provider-icons.js +39 -0
- package/data/build/dist/client/remote-web-context.d.ts +57 -0
- package/data/build/dist/client/remote-web-context.js +939 -0
- package/data/build/dist/client/session-adapter-cache.d.ts +18 -0
- package/data/build/dist/client/session-adapter-cache.js +84 -0
- package/data/build/dist/client/settings-bridge.d.ts +32 -0
- package/data/build/dist/client/settings-bridge.js +126 -0
- package/data/build/dist/client/settings-section.d.ts +30 -0
- package/data/build/dist/client/settings-section.js +93 -0
- package/data/build/dist/client/subscription-slot.d.ts +18 -0
- package/data/build/dist/client/subscription-slot.js +223 -0
- package/data/build/dist/client/terminal/index.d.ts +4 -0
- package/data/build/dist/client/terminal/index.js +3 -0
- package/data/build/dist/client/terminal/model.d.ts +116 -0
- package/data/build/dist/client/terminal/model.js +435 -0
- package/data/build/dist/client/terminal/styles.d.ts +21 -0
- package/data/build/dist/client/terminal/styles.js +51 -0
- package/data/build/dist/client/terminal/ui.d.ts +19 -0
- package/data/build/dist/client/terminal/ui.js +257 -0
- package/data/build/dist/client/terminal/xterm-view.d.ts +13 -0
- package/data/build/dist/client/terminal/xterm-view.js +213 -0
- package/data/build/dist/client/theme.d.ts +56 -0
- package/data/build/dist/client/theme.js +186 -0
- package/data/build/dist/client/workspace-session-archive-dom.d.ts +29 -0
- package/data/build/dist/client/workspace-session-archive-dom.js +525 -0
- package/data/build/dist/client/workspace-session-fiber.d.ts +3 -0
- package/data/build/dist/client/workspace-session-fiber.js +33 -0
- package/data/build/dist/client/workspace-session-logo-dom.d.ts +26 -0
- package/data/build/dist/client/workspace-session-logo-dom.js +128 -0
- package/data/build/dist/features/index.d.ts +3 -0
- package/data/build/dist/features/index.js +2 -0
- package/data/build/dist/features/registry.d.ts +74 -0
- package/data/build/dist/features/registry.js +382 -0
- package/data/build/dist/features/resource-scope/index.d.ts +39 -0
- package/data/build/dist/features/resource-scope/index.js +161 -0
- package/data/build/dist/host/auth-session.d.ts +42 -0
- package/data/build/dist/host/auth-session.js +186 -0
- package/data/build/dist/host/cli-adapters/claude-driver.d.ts +14 -0
- package/data/build/dist/host/cli-adapters/claude-driver.js +103 -0
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts +45 -0
- package/data/build/dist/host/cli-adapters/codex-driver.js +534 -0
- package/data/build/dist/host/cli-adapters/command-code-driver.d.ts +38 -0
- package/data/build/dist/host/cli-adapters/command-code-driver.js +394 -0
- package/data/build/dist/host/cli-adapters/command-code-subscription.d.ts +19 -0
- package/data/build/dist/host/cli-adapters/command-code-subscription.js +126 -0
- package/data/build/dist/host/cli-adapters/driver.d.ts +41 -0
- package/data/build/dist/host/cli-adapters/driver.js +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +37 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +180 -0
- package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +48 -0
- package/data/build/dist/host/cli-adapters/dsh-tool-history.js +373 -0
- package/data/build/dist/host/cli-adapters/feature.d.ts +7 -0
- package/data/build/dist/host/cli-adapters/feature.js +335 -0
- package/data/build/dist/host/cli-adapters/gemini-driver.d.ts +24 -0
- package/data/build/dist/host/cli-adapters/gemini-driver.js +427 -0
- package/data/build/dist/host/cli-adapters/grok-driver.d.ts +38 -0
- package/data/build/dist/host/cli-adapters/grok-driver.js +372 -0
- package/data/build/dist/host/cli-adapters/http-sse-client.d.ts +22 -0
- package/data/build/dist/host/cli-adapters/http-sse-client.js +99 -0
- package/data/build/dist/host/cli-adapters/interaction-events.d.ts +11 -0
- package/data/build/dist/host/cli-adapters/interaction-events.js +80 -0
- package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +65 -0
- package/data/build/dist/host/cli-adapters/json-rpc-process.js +256 -0
- package/data/build/dist/host/cli-adapters/kimi-driver.d.ts +21 -0
- package/data/build/dist/host/cli-adapters/kimi-driver.js +382 -0
- package/data/build/dist/host/cli-adapters/model-catalog.d.ts +22 -0
- package/data/build/dist/host/cli-adapters/model-catalog.js +89 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +55 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.js +728 -0
- package/data/build/dist/host/cli-adapters/pi-driver.d.ts +43 -0
- package/data/build/dist/host/cli-adapters/pi-driver.js +312 -0
- package/data/build/dist/host/cli-adapters/process-utils.d.ts +16 -0
- package/data/build/dist/host/cli-adapters/process-utils.js +27 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +82 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.js +610 -0
- package/data/build/dist/host/cli-adapters/registry.d.ts +95 -0
- package/data/build/dist/host/cli-adapters/registry.js +659 -0
- package/data/build/dist/host/cli-adapters/rpc-driver-utils.d.ts +24 -0
- package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +119 -0
- package/data/build/dist/host/cli-adapters/session-probe.d.ts +20 -0
- package/data/build/dist/host/cli-adapters/session-probe.js +139 -0
- package/data/build/dist/host/cli-adapters/session-store.d.ts +68 -0
- package/data/build/dist/host/cli-adapters/session-store.js +180 -0
- package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +45 -0
- package/data/build/dist/host/cli-adapters/standard-stream-driver.js +205 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +25 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.js +83 -0
- package/data/build/dist/host/cli-adapters/tool-observation.d.ts +9 -0
- package/data/build/dist/host/cli-adapters/tool-observation.js +39 -0
- package/data/build/dist/host/control-api-client.d.ts +84 -0
- package/data/build/dist/host/control-api-client.js +130 -0
- package/data/build/dist/host/credential-store.d.ts +54 -0
- package/data/build/dist/host/credential-store.js +114 -0
- package/data/build/dist/host/debug.d.ts +79 -0
- package/data/build/dist/host/debug.js +295 -0
- package/data/build/dist/host/dsh-device-runtime.d.ts +39 -0
- package/data/build/dist/host/dsh-device-runtime.js +118 -0
- package/data/build/dist/host/dsh-gateway-feature.d.ts +5 -0
- package/data/build/dist/host/dsh-gateway-feature.js +55 -0
- package/data/build/dist/host/dsh-runtime-version.d.ts +12 -0
- package/data/build/dist/host/dsh-runtime-version.js +69 -0
- package/data/build/dist/host/features/auth.d.ts +11 -0
- package/data/build/dist/host/features/auth.js +273 -0
- package/data/build/dist/host/features/debug.d.ts +5 -0
- package/data/build/dist/host/features/debug.js +90 -0
- package/data/build/dist/host/features/host-status.d.ts +12 -0
- package/data/build/dist/host/features/host-status.js +54 -0
- package/data/build/dist/host/features/index.d.ts +19 -0
- package/data/build/dist/host/features/index.js +29 -0
- package/data/build/dist/host/features/lan-access-dsh.d.ts +8 -0
- package/data/build/dist/host/features/lan-access-dsh.js +45 -0
- package/data/build/dist/host/features/terminal-process.d.ts +5 -0
- package/data/build/dist/host/features/terminal-process.js +110 -0
- package/data/build/dist/host/features/terminal-status.d.ts +18 -0
- package/data/build/dist/host/features/terminal-status.js +56 -0
- package/data/build/dist/host/features/types.d.ts +41 -0
- package/data/build/dist/host/features/types.js +2 -0
- package/data/build/dist/host/index.d.ts +43 -0
- package/data/build/dist/host/index.js +135 -0
- package/data/build/dist/host/lan-access-dsh.d.ts +83 -0
- package/data/build/dist/host/lan-access-dsh.js +831 -0
- package/data/build/dist/host/native-session-bridge.d.ts +130 -0
- package/data/build/dist/host/native-session-bridge.js +317 -0
- package/data/build/dist/host/relay-tunnel-runtime.d.ts +97 -0
- package/data/build/dist/host/relay-tunnel-runtime.js +361 -0
- package/data/build/dist/host/remote-web-runtime.d.ts +78 -0
- package/data/build/dist/host/remote-web-runtime.js +559 -0
- package/data/build/dist/host/rpc-table.d.ts +32 -0
- package/data/build/dist/host/rpc-table.js +47 -0
- package/data/build/dist/host/rpc.d.ts +18 -0
- package/data/build/dist/host/rpc.js +248 -0
- package/data/build/dist/host/settings.d.ts +19 -0
- package/data/build/dist/host/settings.js +80 -0
- package/data/build/dist/host/terminal/attachment-registry.d.ts +17 -0
- package/data/build/dist/host/terminal/attachment-registry.js +49 -0
- package/data/build/dist/host/terminal/backends/conpty-backend.d.ts +39 -0
- package/data/build/dist/host/terminal/backends/conpty-backend.js +160 -0
- package/data/build/dist/host/terminal/backends/local-pty-backend.d.ts +36 -0
- package/data/build/dist/host/terminal/backends/local-pty-backend.js +178 -0
- package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +40 -0
- package/data/build/dist/host/terminal/backends/tmux-backend.js +191 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-client.d.ts +27 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-client.js +154 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-process.d.ts +10 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-process.js +147 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-protocol.d.ts +92 -0
- package/data/build/dist/host/terminal/broker/conpty-broker-protocol.js +134 -0
- package/data/build/dist/host/terminal/controller-factory.d.ts +37 -0
- package/data/build/dist/host/terminal/controller-factory.js +82 -0
- package/data/build/dist/host/terminal/index.d.ts +17 -0
- package/data/build/dist/host/terminal/index.js +17 -0
- package/data/build/dist/host/terminal/runtime-adapter.d.ts +77 -0
- package/data/build/dist/host/terminal/runtime-adapter.js +18 -0
- package/data/build/dist/host/terminal/runtime-manager.d.ts +41 -0
- package/data/build/dist/host/terminal/runtime-manager.js +179 -0
- package/data/build/dist/host/terminal/shell-detection.d.ts +23 -0
- package/data/build/dist/host/terminal/shell-detection.js +105 -0
- package/data/build/dist/host/terminal/startup.d.ts +33 -0
- package/data/build/dist/host/terminal/startup.js +100 -0
- package/data/build/dist/host/terminal/terminal-controller.d.ts +78 -0
- package/data/build/dist/host/terminal/terminal-controller.js +324 -0
- package/data/build/dist/host/terminal/terminal-process-service.d.ts +30 -0
- package/data/build/dist/host/terminal/terminal-process-service.js +194 -0
- package/data/build/dist/host/terminal/terminal-process-store.d.ts +45 -0
- package/data/build/dist/host/terminal/terminal-process-store.js +183 -0
- package/data/build/dist/host/terminal/terminal-service.d.ts +87 -0
- package/data/build/dist/host/terminal/terminal-service.js +528 -0
- package/data/build/dist/host/terminal/terminal-store.d.ts +49 -0
- package/data/build/dist/host/terminal/terminal-store.js +242 -0
- package/data/build/dist/index.d.ts +37 -0
- package/data/build/dist/index.js +26 -0
- package/data/build/dist/shared/contracts/auth.d.ts +122 -0
- package/data/build/dist/shared/contracts/auth.js +8 -0
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +192 -0
- package/data/build/dist/shared/contracts/cli-adapter.js +2 -0
- package/data/build/dist/shared/contracts/command-code.d.ts +5 -0
- package/data/build/dist/shared/contracts/command-code.js +2 -0
- package/data/build/dist/shared/contracts/config.d.ts +113 -0
- package/data/build/dist/shared/contracts/config.js +86 -0
- package/data/build/dist/shared/contracts/debug-config.d.ts +28 -0
- package/data/build/dist/shared/contracts/debug-config.js +78 -0
- package/data/build/dist/shared/contracts/debug.d.ts +75 -0
- package/data/build/dist/shared/contracts/debug.js +121 -0
- package/data/build/dist/shared/contracts/dsh-device.d.ts +72 -0
- package/data/build/dist/shared/contracts/dsh-device.js +2 -0
- package/data/build/dist/shared/contracts/errors.d.ts +33 -0
- package/data/build/dist/shared/contracts/errors.js +41 -0
- package/data/build/dist/shared/contracts/feature.d.ts +71 -0
- package/data/build/dist/shared/contracts/feature.js +2 -0
- package/data/build/dist/shared/contracts/host-status.d.ts +14 -0
- package/data/build/dist/shared/contracts/host-status.js +2 -0
- package/data/build/dist/shared/contracts/lan-access-dsh.d.ts +30 -0
- package/data/build/dist/shared/contracts/lan-access-dsh.js +2 -0
- package/data/build/dist/shared/contracts/peer-host.d.ts +37 -0
- package/data/build/dist/shared/contracts/peer-host.js +9 -0
- package/data/build/dist/shared/contracts/signaling.d.ts +67 -0
- package/data/build/dist/shared/contracts/signaling.js +2 -0
- package/data/build/dist/shared/contracts/subscription.d.ts +69 -0
- package/data/build/dist/shared/contracts/subscription.js +2 -0
- package/data/build/dist/shared/contracts/terminal-process.d.ts +65 -0
- package/data/build/dist/shared/contracts/terminal-process.js +2 -0
- package/data/build/dist/shared/contracts/terminal.d.ts +127 -0
- package/data/build/dist/shared/contracts/terminal.js +2 -0
- package/data/build/dist/shared/contracts/transport.d.ts +45 -0
- package/data/build/dist/shared/contracts/transport.js +3 -0
- package/data/build/dist/shared/contracts/version.d.ts +19 -0
- package/data/build/dist/shared/contracts/version.js +74 -0
- package/data/build/dist/shared/index.d.ts +22 -0
- package/data/build/dist/shared/index.js +9 -0
- package/data/build/dist/transport/carrier.d.ts +38 -0
- package/data/build/dist/transport/carrier.js +268 -0
- package/data/build/dist/transport/debug.d.ts +22 -0
- package/data/build/dist/transport/debug.js +57 -0
- package/data/build/dist/transport/dsh-envelope.d.ts +41 -0
- package/data/build/dist/transport/dsh-envelope.js +107 -0
- package/data/build/dist/transport/dsh-gateway.d.ts +64 -0
- package/data/build/dist/transport/dsh-gateway.js +254 -0
- package/data/build/dist/transport/dsh-session.d.ts +55 -0
- package/data/build/dist/transport/dsh-session.js +256 -0
- package/data/build/dist/transport/dsh-transport.d.ts +57 -0
- package/data/build/dist/transport/dsh-transport.js +125 -0
- package/data/build/dist/transport/frame.d.ts +132 -0
- package/data/build/dist/transport/frame.js +168 -0
- package/data/build/dist/transport/index.d.ts +11 -0
- package/data/build/dist/transport/index.js +11 -0
- package/data/build/dist/transport/multiplexer.d.ts +63 -0
- package/data/build/dist/transport/multiplexer.js +323 -0
- package/data/build/dist/transport/webrtc-client.d.ts +65 -0
- package/data/build/dist/transport/webrtc-client.js +255 -0
- package/data/build/dist/transport/webrtc-host.d.ts +58 -0
- package/data/build/dist/transport/webrtc-host.js +252 -0
- package/data/build/dist/typert.host.d.ts +25 -0
- package/data/build/dist/typert.host.js +150 -0
- package/dsh.bundle.patch +12 -0
- package/package.json +135 -0
- package/profile/README.md +27 -0
- package/profile/cordis.patch.yml +2 -0
- package/profile/package.json +20 -0
- package/profile/scripts/check-dsh-install.mjs +71 -0
- package/profile/version.json +5 -0
- package/scripts/check-dsh-install.mjs +88 -0
- package/version.json +6 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CodingNsSessionAdapterBinding } from '../shared/contracts/cli-adapter.js';
|
|
2
|
+
import type { CodingNsRpcClient } from './features/types.js';
|
|
3
|
+
type CacheListener = () => void;
|
|
4
|
+
/** 返回一个会话当前绑定的适配器;查询成本为 O(1)。 */
|
|
5
|
+
export declare function sessionAdapterId(sessionId: string): string | undefined;
|
|
6
|
+
/** 同一浏览器内 Agent 选择变化时增量更新缓存。 */
|
|
7
|
+
export declare function publishSessionAdapter(sessionId: string, adapterId: string): void;
|
|
8
|
+
/** 用 Host 的一次脱敏快照替换缓存,不保留已经消失的旧绑定。 */
|
|
9
|
+
export declare function replaceSessionAdapters(bindings: readonly CodingNsSessionAdapterBinding[]): void;
|
|
10
|
+
/** 一次 RPC 读取全部脱敏绑定;不会按 DOM 行逐条请求。 */
|
|
11
|
+
export declare function fetchSessionAdapters(rpc: CodingNsRpcClient): Promise<readonly CodingNsSessionAdapterBinding[]>;
|
|
12
|
+
export declare function subscribeSessionAdapters(listener: CacheListener): () => void;
|
|
13
|
+
/** 模块停用时清空内存关系,避免跨 generation 使用旧绑定。 */
|
|
14
|
+
export declare function clearSessionAdapters(): void;
|
|
15
|
+
/** 只供测试和诊断读取的脱敏快照。 */
|
|
16
|
+
export declare function sessionAdapterSnapshot(): Readonly<Record<string, string>>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=session-adapter-cache.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { callCliRpc } from './cli-catalog.js';
|
|
2
|
+
const adaptersBySession = new Map();
|
|
3
|
+
const listeners = new Set();
|
|
4
|
+
/** 返回一个会话当前绑定的适配器;查询成本为 O(1)。 */
|
|
5
|
+
export function sessionAdapterId(sessionId) {
|
|
6
|
+
return adaptersBySession.get(sessionId);
|
|
7
|
+
}
|
|
8
|
+
/** 同一浏览器内 Agent 选择变化时增量更新缓存。 */
|
|
9
|
+
export function publishSessionAdapter(sessionId, adapterId) {
|
|
10
|
+
const normalizedSessionId = sessionId.trim();
|
|
11
|
+
const normalizedAdapterId = adapterId.trim();
|
|
12
|
+
if (normalizedSessionId === '' || normalizedAdapterId === '')
|
|
13
|
+
return;
|
|
14
|
+
if (adaptersBySession.get(normalizedSessionId) === normalizedAdapterId)
|
|
15
|
+
return;
|
|
16
|
+
adaptersBySession.set(normalizedSessionId, normalizedAdapterId);
|
|
17
|
+
notify();
|
|
18
|
+
}
|
|
19
|
+
/** 用 Host 的一次脱敏快照替换缓存,不保留已经消失的旧绑定。 */
|
|
20
|
+
export function replaceSessionAdapters(bindings) {
|
|
21
|
+
const next = new Map();
|
|
22
|
+
for (const binding of bindings) {
|
|
23
|
+
const sessionId = binding.sessionId.trim();
|
|
24
|
+
const adapterId = binding.adapterId.trim();
|
|
25
|
+
if (sessionId !== '' && adapterId !== '')
|
|
26
|
+
next.set(sessionId, adapterId);
|
|
27
|
+
}
|
|
28
|
+
if (sameBindings(next))
|
|
29
|
+
return;
|
|
30
|
+
adaptersBySession.clear();
|
|
31
|
+
for (const [sessionId, adapterId] of next)
|
|
32
|
+
adaptersBySession.set(sessionId, adapterId);
|
|
33
|
+
notify();
|
|
34
|
+
}
|
|
35
|
+
/** 一次 RPC 读取全部脱敏绑定;不会按 DOM 行逐条请求。 */
|
|
36
|
+
export async function fetchSessionAdapters(rpc) {
|
|
37
|
+
const value = await callCliRpc(rpc, 'session/adapter-map', {});
|
|
38
|
+
if (!Array.isArray(value))
|
|
39
|
+
return [];
|
|
40
|
+
return value
|
|
41
|
+
.filter(isSessionAdapterBinding)
|
|
42
|
+
.map((binding) => ({
|
|
43
|
+
sessionId: binding.sessionId.trim(),
|
|
44
|
+
adapterId: binding.adapterId.trim(),
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
export function subscribeSessionAdapters(listener) {
|
|
48
|
+
listeners.add(listener);
|
|
49
|
+
return () => listeners.delete(listener);
|
|
50
|
+
}
|
|
51
|
+
/** 模块停用时清空内存关系,避免跨 generation 使用旧绑定。 */
|
|
52
|
+
export function clearSessionAdapters() {
|
|
53
|
+
if (adaptersBySession.size === 0)
|
|
54
|
+
return;
|
|
55
|
+
adaptersBySession.clear();
|
|
56
|
+
notify();
|
|
57
|
+
}
|
|
58
|
+
/** 只供测试和诊断读取的脱敏快照。 */
|
|
59
|
+
export function sessionAdapterSnapshot() {
|
|
60
|
+
return Object.fromEntries(adaptersBySession);
|
|
61
|
+
}
|
|
62
|
+
function sameBindings(next) {
|
|
63
|
+
if (next.size !== adaptersBySession.size)
|
|
64
|
+
return false;
|
|
65
|
+
for (const [sessionId, adapterId] of next) {
|
|
66
|
+
if (adaptersBySession.get(sessionId) !== adapterId)
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
function notify() {
|
|
72
|
+
for (const listener of [...listeners])
|
|
73
|
+
listener();
|
|
74
|
+
}
|
|
75
|
+
function isSessionAdapterBinding(value) {
|
|
76
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
77
|
+
return false;
|
|
78
|
+
const record = value;
|
|
79
|
+
return typeof record.sessionId === 'string'
|
|
80
|
+
&& record.sessionId.trim() !== ''
|
|
81
|
+
&& typeof record.adapterId === 'string'
|
|
82
|
+
&& record.adapterId.trim() !== '';
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=session-adapter-cache.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
2
|
+
import type { CodingNsSettings } from '../shared/contracts/config.js';
|
|
3
|
+
import type { CodingNsRpcClient } from './features/types.js';
|
|
4
|
+
type SettingsMutation = Parameters<SettingsScope<CodingNsSettings>['mutate']>[0];
|
|
5
|
+
type SnapshotListener = () => void;
|
|
6
|
+
/**
|
|
7
|
+
* 把 DSH 本地设置和远程 Host 设置 RPC 统一成一个设置作用域。
|
|
8
|
+
* 非回环页面使用 RPC,回环页面完全复用 DSH 的原生设置传输。
|
|
9
|
+
*/
|
|
10
|
+
export declare class CodingNsSettingsBridge implements SettingsScope<CodingNsSettings> {
|
|
11
|
+
private readonly local;
|
|
12
|
+
private readonly rpc;
|
|
13
|
+
private snapshot;
|
|
14
|
+
private readonly listeners;
|
|
15
|
+
private readonly localUnsubscribe;
|
|
16
|
+
private remoteLoad;
|
|
17
|
+
private remoteLoaded;
|
|
18
|
+
constructor(local: SettingsScope<CodingNsSettings>, rpc: CodingNsRpcClient);
|
|
19
|
+
getSnapshot(): SettingsScopeSnapshot<CodingNsSettings>;
|
|
20
|
+
subscribe(listener: SnapshotListener): () => void;
|
|
21
|
+
load(): Promise<void>;
|
|
22
|
+
set(field: string, value: unknown): Promise<void>;
|
|
23
|
+
unset(field: string): Promise<void>;
|
|
24
|
+
mutate(ops: SettingsMutation, expectedRevision?: number): Promise<void>;
|
|
25
|
+
dispose(): void;
|
|
26
|
+
private call;
|
|
27
|
+
private publish;
|
|
28
|
+
private isRemote;
|
|
29
|
+
}
|
|
30
|
+
export declare function createCodingNsSettingsBridge(local: SettingsScope<CodingNsSettings>, rpc: CodingNsRpcClient): CodingNsSettingsBridge;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=settings-bridge.d.ts.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { CODINGNS_RPC_CHANNEL } from '../shared/contracts/transport.js';
|
|
2
|
+
/**
|
|
3
|
+
* 把 DSH 本地设置和远程 Host 设置 RPC 统一成一个设置作用域。
|
|
4
|
+
* 非回环页面使用 RPC,回环页面完全复用 DSH 的原生设置传输。
|
|
5
|
+
*/
|
|
6
|
+
export class CodingNsSettingsBridge {
|
|
7
|
+
local;
|
|
8
|
+
rpc;
|
|
9
|
+
snapshot;
|
|
10
|
+
listeners = new Set();
|
|
11
|
+
localUnsubscribe;
|
|
12
|
+
remoteLoad;
|
|
13
|
+
remoteLoaded = false;
|
|
14
|
+
constructor(local, rpc) {
|
|
15
|
+
this.local = local;
|
|
16
|
+
this.rpc = rpc;
|
|
17
|
+
this.snapshot = local.getSnapshot();
|
|
18
|
+
this.localUnsubscribe = local.subscribe(() => {
|
|
19
|
+
if (this.isRemote()) {
|
|
20
|
+
void this.load().catch(() => undefined);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.remoteLoaded = false;
|
|
24
|
+
this.publish(local.getSnapshot());
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
getSnapshot() { return this.snapshot; }
|
|
28
|
+
subscribe(listener) {
|
|
29
|
+
this.listeners.add(listener);
|
|
30
|
+
return () => this.listeners.delete(listener);
|
|
31
|
+
}
|
|
32
|
+
async load() {
|
|
33
|
+
if (!this.isRemote())
|
|
34
|
+
return;
|
|
35
|
+
if (this.remoteLoaded)
|
|
36
|
+
return;
|
|
37
|
+
if (this.remoteLoad !== undefined)
|
|
38
|
+
return this.remoteLoad;
|
|
39
|
+
this.remoteLoad = this.call('settings/get', {}).then((response) => {
|
|
40
|
+
this.remoteLoaded = true;
|
|
41
|
+
this.publish({
|
|
42
|
+
status: 'ready',
|
|
43
|
+
value: response.value,
|
|
44
|
+
base: undefined,
|
|
45
|
+
user: undefined,
|
|
46
|
+
revision: response.revision,
|
|
47
|
+
writable: true,
|
|
48
|
+
mode: 'host',
|
|
49
|
+
});
|
|
50
|
+
}).finally(() => {
|
|
51
|
+
this.remoteLoad = undefined;
|
|
52
|
+
});
|
|
53
|
+
return this.remoteLoad;
|
|
54
|
+
}
|
|
55
|
+
async set(field, value) {
|
|
56
|
+
if (!this.isRemote())
|
|
57
|
+
return this.local.set(field, value);
|
|
58
|
+
return this.mutate([{ op: 'set', path: [field], value: toJsonValue(value) }]);
|
|
59
|
+
}
|
|
60
|
+
async unset(field) {
|
|
61
|
+
if (!this.isRemote())
|
|
62
|
+
return this.local.unset(field);
|
|
63
|
+
return this.mutate([{ op: 'unset', path: [field] }]);
|
|
64
|
+
}
|
|
65
|
+
async mutate(ops, expectedRevision) {
|
|
66
|
+
if (!this.isRemote())
|
|
67
|
+
return this.local.mutate(ops, expectedRevision);
|
|
68
|
+
const payload = expectedRevision === undefined ? { ops } : { ops, expectedRevision };
|
|
69
|
+
const response = await this.call('settings/set', payload);
|
|
70
|
+
this.remoteLoaded = true;
|
|
71
|
+
this.publish({
|
|
72
|
+
...this.snapshot,
|
|
73
|
+
status: 'ready',
|
|
74
|
+
value: response.value,
|
|
75
|
+
revision: response.revision,
|
|
76
|
+
writable: true,
|
|
77
|
+
mode: 'host',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
dispose() { this.localUnsubscribe(); }
|
|
81
|
+
async call(endpoint, payload) {
|
|
82
|
+
let result;
|
|
83
|
+
try {
|
|
84
|
+
result = await this.rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// DSH 原生连接通常把自定义 RPC 映射到 /api;保留逻辑通道兼容
|
|
88
|
+
// Codingns4DSH Transport,同时在普通 Web Host 上回退到实际 Fetch 路由。
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
if (!/HTTP (?:404|405)\b/u.test(message))
|
|
91
|
+
throw error;
|
|
92
|
+
result = await this.rpc.call('/api', `codingns/${endpoint}`, payload);
|
|
93
|
+
}
|
|
94
|
+
if (!result.ok)
|
|
95
|
+
throw new Error(result.error.message);
|
|
96
|
+
return result.value;
|
|
97
|
+
}
|
|
98
|
+
publish(next) {
|
|
99
|
+
this.snapshot = next;
|
|
100
|
+
for (const listener of [...this.listeners])
|
|
101
|
+
listener();
|
|
102
|
+
}
|
|
103
|
+
isRemote() {
|
|
104
|
+
const snapshot = this.local.getSnapshot();
|
|
105
|
+
return snapshot.mode === 'memory' || snapshot.status === 'unavailable';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** 设置 RPC 只能传 JSON;在浏览器边界尽早拒绝函数、循环引用等无效值。 */
|
|
109
|
+
function toJsonValue(value) {
|
|
110
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
111
|
+
return value;
|
|
112
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
113
|
+
return value;
|
|
114
|
+
if (Array.isArray(value))
|
|
115
|
+
return value.map(toJsonValue);
|
|
116
|
+
if (typeof value !== 'object')
|
|
117
|
+
throw new TypeError('设置值必须是可序列化的 JSON');
|
|
118
|
+
const result = {};
|
|
119
|
+
for (const [key, entry] of Object.entries(value))
|
|
120
|
+
result[key] = toJsonValue(entry);
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
export function createCodingNsSettingsBridge(local, rpc) {
|
|
124
|
+
return new CodingNsSettingsBridge(local, rpc);
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=settings-bridge.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
import type { SettingsScope, SettingsSectionOwnerProps } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
4
|
+
import type { FeatureRegistry } from '../features/registry.js';
|
|
5
|
+
import { type RestartFeatureStates, type CodingNsSettings } from '../shared/contracts/config.js';
|
|
6
|
+
import type { CodingNsClientFeatureModule, CodingNsClientServices } from './features/types.js';
|
|
7
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
8
|
+
interface SlotMap {
|
|
9
|
+
'settings.section': {
|
|
10
|
+
kind: 'list';
|
|
11
|
+
scope: 'root';
|
|
12
|
+
owner: SettingsSectionOwnerProps;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export interface CodingNsSectionProps extends PropsRuntime<'settings.section'> {
|
|
17
|
+
readonly settings: SettingsScope<CodingNsSettings>;
|
|
18
|
+
readonly registry: FeatureRegistry<CodingNsClientServices, CodingNsClientFeatureModule>;
|
|
19
|
+
readonly services: CodingNsClientServices;
|
|
20
|
+
/** 当前 Client 进程启动时捕获的重启生效模块状态。 */
|
|
21
|
+
readonly restartStates?: RestartFeatureStates;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* DSH 设置页中的 Codingns4DSH 区块。
|
|
25
|
+
*
|
|
26
|
+
* 它只做一件事:遍历注册表中带界面描述的模块并渲染卡片。卡片内容来自模块
|
|
27
|
+
* 自己的 settingsPanel,所以新增模块不会在这里产生分支。
|
|
28
|
+
*/
|
|
29
|
+
export declare function CodingNsSettingsSection({ settings, registry, services, restartStates }: CodingNsSectionProps): ReactElement;
|
|
30
|
+
//# sourceMappingURL=settings-section.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createElement, useState, useSyncExternalStore } from 'react';
|
|
2
|
+
import { CODINGNS_MODULES_FIELD, isFeatureEnabled, isFeatureDshVersionCompatible, } from '../shared/contracts/config.js';
|
|
3
|
+
import { settingsModules } from './features/index.js';
|
|
4
|
+
import { dshSettingsBodyStyle, dshSettingsCardStyle, dshSettingsHeaderStyle, dshSettingsPageStyle, dshSettingsSubtitleStyle, dshSettingsSummaryDescriptionStyle, dshSettingsSummaryLabelStyle, dshSettingsSummaryStyle, dshSettingsSummaryTextStyle, dshSettingsTitleStyle, dshThemeColor, } from './theme.js';
|
|
5
|
+
import { useCodingNsTranslator } from './locale.js';
|
|
6
|
+
import { isLegacyDshVersion } from '../shared/contracts/version.js';
|
|
7
|
+
/**
|
|
8
|
+
* DSH 设置页中的 Codingns4DSH 区块。
|
|
9
|
+
*
|
|
10
|
+
* 它只做一件事:遍历注册表中带界面描述的模块并渲染卡片。卡片内容来自模块
|
|
11
|
+
* 自己的 settingsPanel,所以新增模块不会在这里产生分支。
|
|
12
|
+
*/
|
|
13
|
+
export function CodingNsSettingsSection({ settings, registry, services, restartStates = {} }) {
|
|
14
|
+
const snapshot = useSyncExternalStore((listener) => settings.subscribe(listener), () => settings.getSnapshot(), () => settings.getSnapshot());
|
|
15
|
+
const t = useCodingNsTranslator(services.locale);
|
|
16
|
+
return createElement('section', { style: dshSettingsPageStyle }, createElement('header', { style: dshSettingsHeaderStyle }, createElement('h2', { style: dshSettingsTitleStyle }, t('settings.title')), createElement('p', { style: dshSettingsSubtitleStyle }, t('settings.subtitle'))), createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 12 } }, settingsModules(registry).map((entry) => createElement(FeatureCard, {
|
|
17
|
+
key: entry.module.descriptor.name,
|
|
18
|
+
entry,
|
|
19
|
+
snapshot,
|
|
20
|
+
services,
|
|
21
|
+
restartStates,
|
|
22
|
+
}))));
|
|
23
|
+
}
|
|
24
|
+
/** 通用功能模块卡片:标题栏开关由 descriptor.ui 决定,内容由模块自己提供。 */
|
|
25
|
+
function FeatureCard({ entry, snapshot, services, restartStates }) {
|
|
26
|
+
const { module, ui } = entry;
|
|
27
|
+
const t = useCodingNsTranslator(services.locale);
|
|
28
|
+
const [writeError, setWriteError] = useState(null);
|
|
29
|
+
const versionCompatible = isFeatureDshVersionCompatible(module.descriptor, services.dshVersion);
|
|
30
|
+
const requestedEnabled = isFeatureEnabled(module.descriptor, snapshot.value);
|
|
31
|
+
const enabled = versionCompatible && requestedEnabled;
|
|
32
|
+
const effectiveEnabled = module.descriptor.activation === 'restart'
|
|
33
|
+
? versionCompatible && (restartStates[module.descriptor.name] ?? module.descriptor.enabledByDefault)
|
|
34
|
+
: enabled;
|
|
35
|
+
const panel = module.settingsPanel;
|
|
36
|
+
// 常驻模块不提供关闭入口;设置未就绪或只读时也不允许切换。
|
|
37
|
+
const switchDisabled = ui.alwaysEnabled === true || !versionCompatible || snapshot.status === 'loading' || !snapshot.writable;
|
|
38
|
+
const toggle = (next) => {
|
|
39
|
+
setWriteError(null);
|
|
40
|
+
if (!versionCompatible) {
|
|
41
|
+
setWriteError(t('settings.versionBlocked', {
|
|
42
|
+
version: services.dshVersion,
|
|
43
|
+
minimum: module.descriptor.minimumDshVersion ?? '未知版本',
|
|
44
|
+
}));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
void services.settings
|
|
48
|
+
.mutate([{ op: 'set', path: [CODINGNS_MODULES_FIELD, module.descriptor.name], value: next }])
|
|
49
|
+
.catch((cause) => {
|
|
50
|
+
setWriteError(cause instanceof Error ? cause.message : String(cause));
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
return createElement('details', {
|
|
54
|
+
defaultOpen: ui.defaultOpen === true,
|
|
55
|
+
style: dshSettingsCardStyle,
|
|
56
|
+
}, createElement('summary', {
|
|
57
|
+
style: dshSettingsSummaryStyle,
|
|
58
|
+
}, createElement('span', { style: dshSettingsSummaryTextStyle }, createElement('span', { style: dshSettingsSummaryLabelStyle }, t(ui.labelKey ?? ui.label)), createElement('span', { style: dshSettingsSummaryDescriptionStyle }, t(ui.descriptionKey ?? ui.description))), createElement(FeatureSwitch, {
|
|
59
|
+
label: t(ui.labelKey ?? ui.label),
|
|
60
|
+
checked: enabled,
|
|
61
|
+
disabled: switchDisabled,
|
|
62
|
+
onChange: toggle,
|
|
63
|
+
})), createElement('div', { style: dshSettingsBodyStyle }, versionCompatible && ui.legacyFallback === true && isLegacyDshVersion(services.dshVersion)
|
|
64
|
+
? createElement('div', { role: 'status', style: { marginBottom: 10, color: dshThemeColor.labelSecondary } }, t(ui.legacyFallbackKey ?? 'settings.legacyFallback'))
|
|
65
|
+
: null, !versionCompatible
|
|
66
|
+
? createElement('div', { role: 'alert', style: { marginBottom: 10, color: dshThemeColor.error } }, t('settings.versionBlocked', {
|
|
67
|
+
version: services.dshVersion,
|
|
68
|
+
minimum: module.descriptor.minimumDshVersion ?? '未知版本',
|
|
69
|
+
}))
|
|
70
|
+
: null, module.descriptor.activation !== 'restart' ? null : createElement('div', { role: 'status', style: { display: 'flex', flexDirection: 'column', gap: 4, padding: 10, border: `1px solid ${dshThemeColor.border}`, borderRadius: 6, fontSize: 13 } }, createElement('span', undefined, t('settings.restartTarget', { state: enabled ? t('settings.enabled') : t('settings.disabled') })), effectiveEnabled === enabled
|
|
71
|
+
? createElement('span', undefined, t('settings.runtimeReported'))
|
|
72
|
+
: createElement('strong', undefined, t('settings.restartRequired'))), panel === undefined ? null : createElement(panel, { services, enabled, snapshot }), writeError === null ? null : createElement('div', { role: 'alert', style: { color: dshThemeColor.error } }, writeError)));
|
|
73
|
+
}
|
|
74
|
+
/** 标题栏开关:真实 checkbox 语义,点击不会连带折叠卡片。 */
|
|
75
|
+
function FeatureSwitch({ label, checked, disabled, onChange }) {
|
|
76
|
+
return createElement('label', {
|
|
77
|
+
style: { position: 'relative', display: 'inline-flex', flex: '0 0 auto', width: 44, height: 24, opacity: disabled ? 0.55 : 1, cursor: disabled ? 'not-allowed' : 'pointer' },
|
|
78
|
+
onClick: (event) => event.stopPropagation(),
|
|
79
|
+
}, createElement('input', {
|
|
80
|
+
type: 'checkbox',
|
|
81
|
+
role: 'switch',
|
|
82
|
+
'aria-label': label,
|
|
83
|
+
checked,
|
|
84
|
+
disabled,
|
|
85
|
+
onChange: (event) => onChange(event.currentTarget.checked),
|
|
86
|
+
style: { position: 'absolute', inset: 0, width: '100%', height: '100%', margin: 0, opacity: 0, cursor: 'inherit', zIndex: 1 },
|
|
87
|
+
}), createElement('span', {
|
|
88
|
+
style: { position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', padding: 2, borderRadius: 999, background: checked ? dshThemeColor.accent : dshThemeColor.surfaceSubtle, border: `1px solid ${dshThemeColor.border}`, boxSizing: 'border-box', transition: 'background 160ms ease' },
|
|
89
|
+
}, createElement('span', {
|
|
90
|
+
style: { width: 18, height: 18, flex: '0 0 18px', borderRadius: '50%', background: dshThemeColor.switchThumb, boxShadow: dshThemeColor.subtleShadow, transform: `translateX(${checked ? 20 : 0}px)`, transition: 'transform 160ms ease' },
|
|
91
|
+
})));
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=settings-section.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client';
|
|
3
|
+
import type { CodingNsRpcClient } from './features/types.js';
|
|
4
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
5
|
+
interface SessionStandardProps {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
interface SubscriptionSlotProps {
|
|
10
|
+
readonly rpc: CodingNsRpcClient;
|
|
11
|
+
readonly sessionId?: string;
|
|
12
|
+
}
|
|
13
|
+
/** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
|
|
14
|
+
export declare function registerSubscriptionSlot(slots: SlotRegistry, rpc: CodingNsRpcClient): () => void;
|
|
15
|
+
declare function CommandCodeSubscriptionSlot(props: SubscriptionSlotProps): ReactElement | null;
|
|
16
|
+
export { CommandCodeSubscriptionSlot };
|
|
17
|
+
export declare const registerCommandCodeSubscriptionSlot: typeof registerSubscriptionSlot;
|
|
18
|
+
//# sourceMappingURL=subscription-slot.d.ts.map
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createElement, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { callCliRpc } from './cli-catalog.js';
|
|
3
|
+
import { dshPopupSurfaceStyle, dshThemeColor } from './theme.js';
|
|
4
|
+
/** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
|
|
5
|
+
export function registerSubscriptionSlot(slots, rpc) {
|
|
6
|
+
return slots.inject('conversation.composer.dock', () => slots.register({
|
|
7
|
+
name: 'conversation.composer.dock',
|
|
8
|
+
id: 'codingns4dsh-subscription',
|
|
9
|
+
order: -20,
|
|
10
|
+
label: 'Agent 订阅余量',
|
|
11
|
+
inject: (sessionId) => ({ rpc, sessionId }),
|
|
12
|
+
}, CommandCodeSubscriptionSlot));
|
|
13
|
+
}
|
|
14
|
+
function CommandCodeSubscriptionSlot(props) {
|
|
15
|
+
const [usage, setUsage] = useState(null);
|
|
16
|
+
const [adapterId, setAdapterId] = useState(null);
|
|
17
|
+
const [eligible, setEligible] = useState(false);
|
|
18
|
+
const [open, setOpen] = useState(false);
|
|
19
|
+
const [loading, setLoading] = useState(false);
|
|
20
|
+
const [clock, setClock] = useState(() => Date.now());
|
|
21
|
+
const rootRef = useRef(null);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const sessionId = props.sessionId?.trim();
|
|
24
|
+
if (!sessionId) {
|
|
25
|
+
setEligible(false);
|
|
26
|
+
setUsage(null);
|
|
27
|
+
setAdapterId(null);
|
|
28
|
+
setOpen(false);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
let active = true;
|
|
32
|
+
setEligible(false);
|
|
33
|
+
setUsage(null);
|
|
34
|
+
setAdapterId(null);
|
|
35
|
+
setOpen(false);
|
|
36
|
+
const refresh = async () => {
|
|
37
|
+
setLoading(true);
|
|
38
|
+
try {
|
|
39
|
+
const selection = await callCliRpc(props.rpc, 'session/get', { sessionId });
|
|
40
|
+
const adapterId = selection.adapterId;
|
|
41
|
+
if (!active || !isSubscriptionAdapter(adapterId)) {
|
|
42
|
+
if (active) {
|
|
43
|
+
setEligible(false);
|
|
44
|
+
setUsage(null);
|
|
45
|
+
setAdapterId(null);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (active) {
|
|
50
|
+
setEligible(true);
|
|
51
|
+
setAdapterId(adapterId);
|
|
52
|
+
}
|
|
53
|
+
const next = await callCliRpc(props.rpc, 'subscription', { adapterId });
|
|
54
|
+
if (active)
|
|
55
|
+
setUsage(next);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
if (active) {
|
|
59
|
+
setEligible(false);
|
|
60
|
+
setUsage(null);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
if (active)
|
|
65
|
+
setLoading(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
void refresh();
|
|
69
|
+
const timer = globalThis.setInterval(() => { void refresh(); }, 5 * 60_000);
|
|
70
|
+
return () => {
|
|
71
|
+
active = false;
|
|
72
|
+
globalThis.clearInterval(timer);
|
|
73
|
+
};
|
|
74
|
+
}, [props.rpc, props.sessionId]);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!eligible || usage === null)
|
|
77
|
+
return;
|
|
78
|
+
const timer = globalThis.setInterval(() => setClock(Date.now()), 60_000);
|
|
79
|
+
return () => globalThis.clearInterval(timer);
|
|
80
|
+
}, [eligible, usage]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!open)
|
|
83
|
+
return;
|
|
84
|
+
const closeOnPointerDown = (event) => {
|
|
85
|
+
const target = event.target;
|
|
86
|
+
if (target instanceof Node && !rootRef.current?.contains(target))
|
|
87
|
+
setOpen(false);
|
|
88
|
+
};
|
|
89
|
+
const closeOnEscape = (event) => {
|
|
90
|
+
if (event.key === 'Escape')
|
|
91
|
+
setOpen(false);
|
|
92
|
+
};
|
|
93
|
+
document.addEventListener('pointerdown', closeOnPointerDown);
|
|
94
|
+
document.addEventListener('keydown', closeOnEscape);
|
|
95
|
+
return () => {
|
|
96
|
+
document.removeEventListener('pointerdown', closeOnPointerDown);
|
|
97
|
+
document.removeEventListener('keydown', closeOnEscape);
|
|
98
|
+
};
|
|
99
|
+
}, [open]);
|
|
100
|
+
// 未拿到真实订阅数据时不占用底部栏空间;加载状态不能伪装成订阅存在。
|
|
101
|
+
if (!eligible || usage === null || (usage.sub2api === undefined && resolveDisplayWindow(usage) === null))
|
|
102
|
+
return null;
|
|
103
|
+
const sub2api = usage.sub2api;
|
|
104
|
+
const displayWindow = sub2api === undefined ? resolveDisplayWindow(usage) : null;
|
|
105
|
+
const remaining = displayWindow?.remainingPercent ?? null;
|
|
106
|
+
const resetLabel = displayWindow === null ? null : formatCountdown(displayWindow.resetsAt, clock);
|
|
107
|
+
const providerName = subscriptionProviderName(adapterId);
|
|
108
|
+
const label = sub2api === undefined
|
|
109
|
+
? `${providerName} 订阅余量 ${formatPercent(remaining ?? 0)}%`
|
|
110
|
+
: `${providerName} 上游余额 ${formatSub2ApiMoney(sub2api.balance, sub2api.unit)}`;
|
|
111
|
+
const logoSource = sub2api === undefined ? '' : (sub2api.logoDataUrl ?? (isRemoteWebContext() ? '' : sub2api.logoUrl));
|
|
112
|
+
return createElement('div', { ref: rootRef, style: subscriptionRootStyle }, createElement('button', {
|
|
113
|
+
type: 'button',
|
|
114
|
+
onClick: () => setOpen((value) => !value),
|
|
115
|
+
disabled: loading && usage === null,
|
|
116
|
+
'aria-label': label,
|
|
117
|
+
'aria-expanded': open,
|
|
118
|
+
style: subscriptionTriggerStyle,
|
|
119
|
+
}, sub2api === undefined
|
|
120
|
+
? createElement('span', { 'aria-hidden': true, style: progressRingStyle() }, createElement('span', { style: { ...progressRingVisualStyle, background: progressRingVisualBackground(remaining === null ? 0 : remaining / 100, false) } }, createElement('span', { style: progressRingValueStyle }, createElement('span', undefined, formatRingPercentage(remaining ?? 0)), createElement('span', { style: progressRingSuffixStyle }, '%'))))
|
|
121
|
+
: createElement('span', { 'aria-hidden': true, style: sub2apiIdentityStyle }, logoSource !== '' && createElement('img', { src: logoSource, alt: '', width: 20, height: 20, style: sub2apiLogoStyle }), createElement('span', undefined, formatSub2ApiMoney(sub2api.balance, sub2api.unit))), createElement('span', { className: 'bOPqQW_label', style: subscriptionLabelStyle }, sub2api === undefined ? (resetLabel ?? '订阅余量') : `今日 ${formatSub2ApiMoney(sub2api.today.cost, sub2api.unit)}`)), open && createElement(SubscriptionPopover, { usage, providerName }));
|
|
122
|
+
}
|
|
123
|
+
function SubscriptionPopover({ usage, providerName }) {
|
|
124
|
+
if (usage.sub2api !== undefined)
|
|
125
|
+
return createElement(Sub2ApiPopover, { usage: usage.sub2api, providerName });
|
|
126
|
+
const windows = [
|
|
127
|
+
['5 小时额度', usage.primary],
|
|
128
|
+
['周额度', usage.secondary],
|
|
129
|
+
['月额度', usage.monthly],
|
|
130
|
+
];
|
|
131
|
+
return createElement('div', { role: 'dialog', 'aria-label': `${providerName} 订阅使用情况`, style: subscriptionPopoverStyle }, createElement('div', { style: popoverHeadingStyle }, createElement('strong', undefined, `${providerName} 订阅`), usage.planType && createElement('span', { style: { color: dshThemeColor.labelTertiary } }, formatPlanType(usage.planType))), ...windows.map(([label, window]) => window === null ? null : createElement('section', { key: label, style: windowStyle }, createElement('div', { style: windowHeadingStyle }, createElement('span', undefined, label), createElement('span', undefined, `${formatPercent(window.remainingPercent)}%`)), createElement('div', { role: 'progressbar', 'aria-label': `${label}剩余 ${formatPercent(window.remainingPercent)}%`, 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-valuenow': window.remainingPercent, style: barStyle }, createElement('span', { style: { ...barFillStyle, width: `${window.remainingPercent}%` } })), window.resetsAt !== null && createElement('div', { style: resetStyle }, `重置于 ${formatCountdown(window.resetsAt)}`))));
|
|
132
|
+
}
|
|
133
|
+
function Sub2ApiPopover({ usage, providerName }) {
|
|
134
|
+
return createElement('div', { role: 'dialog', 'aria-label': `${providerName} 上游用量`, style: subscriptionPopoverStyle }, createElement('div', { style: popoverHeadingStyle }, createElement('strong', undefined, `${providerName} 上游用量`), createElement('span', { style: { color: dshThemeColor.labelTertiary } }, formatSub2ApiMoney(usage.balance, usage.unit))), createElement('div', { style: upstreamMetaStyle }, createElement('span', { style: upstreamTypeStyle }, usage.upstreamType), usage.upstreamUrl === ''
|
|
135
|
+
? createElement('span', { style: upstreamMutedStyle }, '地址未提供')
|
|
136
|
+
: createElement('a', { href: usage.upstreamUrl, target: '_blank', rel: 'noreferrer', title: usage.upstreamUrl, style: upstreamLinkStyle }, usage.upstreamUrl)), createElement('div', { style: sub2apiStatsGridStyle }, createSub2ApiStat('今日请求数', formatInteger(usage.today.requests)), createSub2ApiStat('今日 Token 用量', formatSub2ApiTokens(usage.today.totalTokens)), createSub2ApiStat('今日费用', formatSub2ApiMoney(usage.today.cost, usage.unit)), createSub2ApiStat('累计请求数', formatInteger(usage.total.requests)), createSub2ApiStat('累计 Token 用量', formatSub2ApiTokens(usage.total.totalTokens)), createSub2ApiStat('累计费用', formatSub2ApiMoney(usage.total.cost, usage.unit)), createSub2ApiStat('今日缓存命中率', formatSub2ApiPercent(usage.today.cacheHitRate)), createSub2ApiStat('累计缓存命中率', formatSub2ApiPercent(usage.total.cacheHitRate))), createElement('section', { style: sub2apiSectionStyle }, createElement('strong', { style: sub2apiSectionTitleStyle }, '按模型统计'), usage.models.length === 0
|
|
137
|
+
? createElement('div', { style: resetStyle }, '暂无按模型统计')
|
|
138
|
+
: createElement('div', { style: sub2apiTableScrollStyle }, createElement('table', { style: sub2apiTableStyle }, createElement('thead', undefined, createElement('tr', undefined, createElement('th', { style: sub2apiThStyle }, '模型'), createElement('th', { style: sub2apiThStyle }, '请求'), createElement('th', { style: sub2apiThStyle }, 'Token'), createElement('th', { style: sub2apiThStyle }, '费用'), createElement('th', { style: sub2apiThStyle }, '缓存'))), createElement('tbody', undefined, ...usage.models.map((model) => createModelRow(model, usage.unit)))))));
|
|
139
|
+
}
|
|
140
|
+
function createSub2ApiStat(label, value) {
|
|
141
|
+
return createElement('div', { style: sub2apiStatStyle }, createElement('span', { style: sub2apiStatLabelStyle }, label), createElement('strong', undefined, value));
|
|
142
|
+
}
|
|
143
|
+
function createModelRow(model, unit) {
|
|
144
|
+
return createElement('tr', { key: model.model }, createElement('td', { style: sub2apiTdStyle }, model.model), createElement('td', { style: sub2apiTdStyle }, formatInteger(model.requests)), createElement('td', { style: sub2apiTdStyle }, formatSub2ApiTokens(model.totalTokens)), createElement('td', { style: sub2apiTdStyle }, formatSub2ApiMoney(model.cost, unit)), createElement('td', { style: sub2apiTdStyle }, formatSub2ApiPercent(model.cacheHitRate)));
|
|
145
|
+
}
|
|
146
|
+
function resolveDisplayWindow(usage) {
|
|
147
|
+
return usage.primary ?? usage.secondary ?? usage.monthly;
|
|
148
|
+
}
|
|
149
|
+
function isSubscriptionAdapter(adapterId) {
|
|
150
|
+
return adapterId === 'command-code' || adapterId === 'codex' || adapterId === 'claude-code' || adapterId === 'dsh' || adapterId === 'grok' || adapterId === 'opencode';
|
|
151
|
+
}
|
|
152
|
+
function isRemoteWebContext() {
|
|
153
|
+
return globalThis.__CODINGNS4DSH_REMOTE_WEB_CONTEXT__ === true;
|
|
154
|
+
}
|
|
155
|
+
function subscriptionProviderName(adapterId) {
|
|
156
|
+
switch (adapterId) {
|
|
157
|
+
case 'command-code': return 'Command Code';
|
|
158
|
+
case 'codex': return 'Codex';
|
|
159
|
+
case 'claude-code': return 'Claude Code';
|
|
160
|
+
case 'dsh': return 'DSH';
|
|
161
|
+
case 'grok': return 'Grok';
|
|
162
|
+
case 'opencode': return 'OpenCode';
|
|
163
|
+
default: return 'Agent';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function formatPercent(value) { return Math.max(0, Math.min(100, value)).toFixed(0); }
|
|
167
|
+
function formatRingPercentage(value) { return String(Math.floor(Math.max(0, Math.min(100, value)))); }
|
|
168
|
+
function formatSub2ApiMoney(value, unit) {
|
|
169
|
+
const normalizedUnit = unit.trim().toUpperCase();
|
|
170
|
+
if (normalizedUnit === 'USD')
|
|
171
|
+
return `$${value.toFixed(2)}`;
|
|
172
|
+
return `${value.toFixed(2)}${normalizedUnit === '' ? '' : ` ${normalizedUnit}`}`;
|
|
173
|
+
}
|
|
174
|
+
function formatSub2ApiTokens(value) { return new Intl.NumberFormat('zh-CN', { notation: 'compact', maximumFractionDigits: 1 }).format(value); }
|
|
175
|
+
function formatSub2ApiPercent(value) { return `${Math.max(0, Math.min(100, value)).toFixed(1)}%`; }
|
|
176
|
+
function formatInteger(value) { return new Intl.NumberFormat('zh-CN').format(Math.max(0, Math.round(value))); }
|
|
177
|
+
function formatPlanType(value) { return value.replace(/^individual-/u, '').replace(/(^|-)([a-z])/gu, (_match, _separator, letter) => ` ${letter.toUpperCase()}`).trim(); }
|
|
178
|
+
function formatCountdown(timestampSeconds, nowMs = Date.now()) {
|
|
179
|
+
if (timestampSeconds === null)
|
|
180
|
+
return null;
|
|
181
|
+
const minutes = Math.max(0, Math.ceil((timestampSeconds * 1000 - nowMs) / 60_000));
|
|
182
|
+
const days = Math.floor(minutes / 1440);
|
|
183
|
+
const hours = Math.floor((minutes % 1440) / 60);
|
|
184
|
+
const remainder = minutes % 60;
|
|
185
|
+
if (days > 0)
|
|
186
|
+
return `${days}天${hours}小时后`;
|
|
187
|
+
if (hours > 0)
|
|
188
|
+
return `${hours}小时${remainder > 0 ? `${remainder}分钟` : ''}后`;
|
|
189
|
+
return `${remainder}分钟后`;
|
|
190
|
+
}
|
|
191
|
+
const subscriptionRootStyle = { position: 'relative', minWidth: 0, display: 'inline-flex', alignItems: 'center' };
|
|
192
|
+
const subscriptionTriggerStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, height: 28, border: 0, borderRadius: 14, padding: '0 8px 0 4px', color: dshThemeColor.labelSecondary, background: 'transparent', cursor: 'pointer', fontSize: 13, lineHeight: '20px' };
|
|
193
|
+
const subscriptionLabelStyle = { whiteSpace: 'nowrap' };
|
|
194
|
+
const sub2apiIdentityStyle = { display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };
|
|
195
|
+
const sub2apiLogoStyle = { display: 'block', borderRadius: 4, objectFit: 'contain' };
|
|
196
|
+
const progressRingVisualStyle = { boxSizing: 'border-box', width: '100%', height: '100%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', padding: 2, borderRadius: 'inherit' };
|
|
197
|
+
const progressRingValueStyle = { boxSizing: 'border-box', width: '100%', height: '100%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 0.5, borderRadius: 'inherit', background: dshThemeColor.menuBackground, fontSize: 7, lineHeight: 1, fontWeight: 700, color: dshThemeColor.labelPrimary, whiteSpace: 'nowrap' };
|
|
198
|
+
const progressRingSuffixStyle = { fontSize: 5.5, lineHeight: 1, color: dshThemeColor.labelTertiary, transform: 'translateY(1px)' };
|
|
199
|
+
const popoverHeadingStyle = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 18, paddingBottom: 10, borderBottom: `1px solid ${dshThemeColor.border}`, fontSize: 14 };
|
|
200
|
+
const upstreamMetaStyle = { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0, paddingTop: 8, color: dshThemeColor.labelTertiary, fontSize: 11, lineHeight: '16px' };
|
|
201
|
+
const upstreamTypeStyle = { flex: '0 0 auto', color: dshThemeColor.labelSecondary, fontWeight: 600 };
|
|
202
|
+
const upstreamLinkStyle = { minWidth: 0, overflow: 'hidden', color: dshThemeColor.accent, textOverflow: 'ellipsis', whiteSpace: 'nowrap', textDecoration: 'none' };
|
|
203
|
+
const upstreamMutedStyle = { flex: '0 0 auto', whiteSpace: 'nowrap' };
|
|
204
|
+
const windowStyle = { display: 'grid', gap: 6, paddingTop: 10 };
|
|
205
|
+
const windowHeadingStyle = { display: 'flex', justifyContent: 'space-between', gap: 12, color: dshThemeColor.labelSecondary, fontSize: 13 };
|
|
206
|
+
const barStyle = { height: 7, overflow: 'hidden', borderRadius: 4, background: dshThemeColor.border };
|
|
207
|
+
const barFillStyle = { display: 'block', height: '100%', borderRadius: 4, background: dshThemeColor.accent, transition: 'width .2s ease' };
|
|
208
|
+
const resetStyle = { color: dshThemeColor.labelTertiary, fontSize: 12 };
|
|
209
|
+
const subscriptionPopoverStyle = { ...dshPopupSurfaceStyle, position: 'absolute', zIndex: 1200, bottom: 'calc(100% + 8px)', left: 0, width: 'max-content', minWidth: 280, maxWidth: 'min(400px, calc(100vw - 24px))', boxSizing: 'border-box', padding: 14, borderRadius: 12 };
|
|
210
|
+
const sub2apiStatsGridStyle = { display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 8, paddingTop: 12 };
|
|
211
|
+
const sub2apiStatStyle = { display: 'grid', gap: 2, minWidth: 0 };
|
|
212
|
+
const sub2apiStatLabelStyle = { color: dshThemeColor.labelTertiary, fontSize: 11 };
|
|
213
|
+
const sub2apiSectionStyle = { display: 'grid', gap: 8, paddingTop: 14 };
|
|
214
|
+
const sub2apiSectionTitleStyle = { fontSize: 12, color: dshThemeColor.labelSecondary };
|
|
215
|
+
const sub2apiTableScrollStyle = { maxWidth: '100%', overflow: 'visible' };
|
|
216
|
+
const sub2apiTableStyle = { width: '100%', tableLayout: 'fixed', borderCollapse: 'collapse', fontSize: 11 };
|
|
217
|
+
const sub2apiThStyle = { padding: '4px 5px', textAlign: 'left', color: dshThemeColor.labelTertiary, fontWeight: 500 };
|
|
218
|
+
const sub2apiTdStyle = { padding: '5px', borderTop: `1px solid ${dshThemeColor.border}`, color: dshThemeColor.labelSecondary, overflowWrap: 'anywhere' };
|
|
219
|
+
function progressRingStyle() { return { position: 'relative', display: 'inline-flex', flex: '0 0 28px', width: 28, height: 28, alignItems: 'center', justifyContent: 'center', borderRadius: '50%', padding: 0, border: 0, boxShadow: `inset 0 0 0 1px ${dshThemeColor.border}`, background: 'transparent' }; }
|
|
220
|
+
function progressRingVisualBackground(progress, loading) { return loading ? dshThemeColor.border : `conic-gradient(${dshThemeColor.accent} ${Math.max(0, Math.min(1, progress)) * 360}deg, ${dshThemeColor.border} 0deg)`; }
|
|
221
|
+
export { CommandCodeSubscriptionSlot };
|
|
222
|
+
export const registerCommandCodeSubscriptionSlot = registerSubscriptionSlot;
|
|
223
|
+
//# sourceMappingURL=subscription-slot.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CodingNsWebTerminals, CodingNsTerminalView } from './model.js';
|
|
2
|
+
export type { TerminalCloseFailure, TerminalLaunchShells, TerminalObservable, TerminalRemote, TerminalRemoteSource, TerminalViewState } from './model.js';
|
|
3
|
+
export { registerCodingNsTerminalUi, TERMINAL_KIND, TERMINAL_PROVIDER_ID } from './ui.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|