@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,147 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:net';
|
|
3
|
+
import { spawn } from '@lydell/node-pty';
|
|
4
|
+
import { BoundedTerminalBuffer, ExclusiveAttachmentLease, createJsonLineParser, parseBrokerRequest, writeBrokerMessage, } from './conpty-broker-protocol.js';
|
|
5
|
+
import { normalizeTerminalSize } from '../runtime-adapter.js';
|
|
6
|
+
export function runConptyBroker(args) {
|
|
7
|
+
if (process.platform !== 'win32')
|
|
8
|
+
throw new Error('ConPTY broker 只能在 Windows 上运行');
|
|
9
|
+
const pty = spawn(args.shellPath, [...args.shellArgs], {
|
|
10
|
+
cwd: args.cwd,
|
|
11
|
+
env: process.env,
|
|
12
|
+
cols: 120,
|
|
13
|
+
rows: 30,
|
|
14
|
+
name: 'xterm-256color',
|
|
15
|
+
});
|
|
16
|
+
const outputBuffer = new BoundedTerminalBuffer();
|
|
17
|
+
const attachmentLease = new ExclusiveAttachmentLease();
|
|
18
|
+
const attachedSockets = new Set();
|
|
19
|
+
const terminationWaiters = new Set();
|
|
20
|
+
let exited = false;
|
|
21
|
+
const server = createServer((socket) => {
|
|
22
|
+
let attached = false;
|
|
23
|
+
const parser = createJsonLineParser((value) => {
|
|
24
|
+
const request = parseBrokerRequest(value);
|
|
25
|
+
if (request === null)
|
|
26
|
+
return fail(socket, 'INVALID_PROTOCOL', '无效的 broker 请求');
|
|
27
|
+
if (!sameSecret(request.auth, args.auth))
|
|
28
|
+
return fail(socket, 'UNAUTHORIZED', 'broker 认证失败');
|
|
29
|
+
if (request.type === 'inspect') {
|
|
30
|
+
writeBrokerMessage(socket, { version: 1, type: 'inspect-result', alive: !exited, brokerPid: process.pid, shellPid: pty.pid });
|
|
31
|
+
socket.end();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (request.type === 'terminate') {
|
|
35
|
+
if (exited) {
|
|
36
|
+
writeBrokerMessage(socket, { version: 1, type: 'terminated' });
|
|
37
|
+
socket.end();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
terminationWaiters.add(socket);
|
|
41
|
+
try {
|
|
42
|
+
pty.kill();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
terminationWaiters.delete(socket);
|
|
46
|
+
fail(socket, 'TERMINATE_FAILED', 'ConPTY shell 终止失败');
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (request.type === 'attach') {
|
|
51
|
+
const size = normalizeTerminalSize(request.cols, request.rows);
|
|
52
|
+
attached = true;
|
|
53
|
+
attachedSockets.add(socket);
|
|
54
|
+
attachmentLease.takeover(socket);
|
|
55
|
+
pty.resize(size.cols, size.rows);
|
|
56
|
+
writeBrokerMessage(socket, { version: 1, type: 'attached', brokerPid: process.pid, shellPid: pty.pid });
|
|
57
|
+
const buffered = outputBuffer.snapshot();
|
|
58
|
+
if (buffered !== '')
|
|
59
|
+
writeBrokerMessage(socket, { version: 1, type: 'output', data: buffered });
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!attached || !attachmentLease.owns(socket))
|
|
63
|
+
return fail(socket, 'NOT_ATTACHED', '连接尚未 attach');
|
|
64
|
+
if (request.type === 'input')
|
|
65
|
+
pty.write(request.data);
|
|
66
|
+
if (request.type === 'resize') {
|
|
67
|
+
const size = normalizeTerminalSize(request.cols, request.rows);
|
|
68
|
+
pty.resize(size.cols, size.rows);
|
|
69
|
+
}
|
|
70
|
+
if (request.type === 'detach')
|
|
71
|
+
socket.end();
|
|
72
|
+
});
|
|
73
|
+
socket.on('data', (chunk) => {
|
|
74
|
+
try {
|
|
75
|
+
parser.push(chunk);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
fail(socket, 'INVALID_PROTOCOL', 'broker 控制帧无法解析');
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const release = () => {
|
|
82
|
+
attachmentLease.release(socket);
|
|
83
|
+
attachedSockets.delete(socket);
|
|
84
|
+
};
|
|
85
|
+
socket.once('close', release);
|
|
86
|
+
socket.once('error', release);
|
|
87
|
+
});
|
|
88
|
+
pty.onData((data) => {
|
|
89
|
+
outputBuffer.push(data);
|
|
90
|
+
for (const socket of attachedSockets)
|
|
91
|
+
writeBrokerMessage(socket, { version: 1, type: 'output', data });
|
|
92
|
+
});
|
|
93
|
+
pty.onExit(({ exitCode }) => {
|
|
94
|
+
exited = true;
|
|
95
|
+
for (const socket of attachedSockets) {
|
|
96
|
+
writeBrokerMessage(socket, { version: 1, type: 'exit', exitCode });
|
|
97
|
+
socket.end();
|
|
98
|
+
}
|
|
99
|
+
attachedSockets.clear();
|
|
100
|
+
for (const waiter of terminationWaiters) {
|
|
101
|
+
writeBrokerMessage(waiter, { version: 1, type: 'terminated' });
|
|
102
|
+
waiter.end();
|
|
103
|
+
}
|
|
104
|
+
terminationWaiters.clear();
|
|
105
|
+
server.close(() => undefined);
|
|
106
|
+
});
|
|
107
|
+
// readableAll/writableAll=false 明确要求 Windows 使用当前用户的默认 Named Pipe ACL。
|
|
108
|
+
server.listen({ path: args.pipeName, readableAll: false, writableAll: false });
|
|
109
|
+
}
|
|
110
|
+
function fail(socket, code, message) {
|
|
111
|
+
writeBrokerMessage(socket, { version: 1, type: 'error', code, message });
|
|
112
|
+
socket.end();
|
|
113
|
+
}
|
|
114
|
+
function sameSecret(actual, expected) {
|
|
115
|
+
const encoder = new TextEncoder();
|
|
116
|
+
const left = encoder.encode(actual);
|
|
117
|
+
const right = encoder.encode(expected);
|
|
118
|
+
return left.byteLength === right.byteLength && timingSafeEqual(left, right);
|
|
119
|
+
}
|
|
120
|
+
function readArguments(argv) {
|
|
121
|
+
const values = new Map();
|
|
122
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
123
|
+
const name = argv[index];
|
|
124
|
+
const value = argv[index + 1];
|
|
125
|
+
if (name?.startsWith('--') && value !== undefined)
|
|
126
|
+
values.set(name.slice(2), value);
|
|
127
|
+
}
|
|
128
|
+
const pipeName = values.get('pipe');
|
|
129
|
+
const auth = values.get('auth') ?? process.env.CODINGNS4DSH_TERMINAL_AUTH;
|
|
130
|
+
const shellPath = values.get('shell');
|
|
131
|
+
const cwd = values.get('cwd');
|
|
132
|
+
const shellArgs = parseShellArgs(process.env.CODINGNS4DSH_TERMINAL_ARGS);
|
|
133
|
+
if (!pipeName || !auth || !shellPath || !cwd)
|
|
134
|
+
throw new Error('ConPTY broker 启动参数不完整');
|
|
135
|
+
return { pipeName, auth, shellPath, shellArgs, cwd };
|
|
136
|
+
}
|
|
137
|
+
function parseShellArgs(value) {
|
|
138
|
+
if (value === undefined)
|
|
139
|
+
return [];
|
|
140
|
+
const parsed = JSON.parse(value);
|
|
141
|
+
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== 'string')) {
|
|
142
|
+
throw new Error('ConPTY shell 参数无效');
|
|
143
|
+
}
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
runConptyBroker(readArguments(process.argv.slice(2)));
|
|
147
|
+
//# sourceMappingURL=conpty-broker-process.js.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export declare const CONPTY_BROKER_PROTOCOL_VERSION: 1;
|
|
2
|
+
export declare const CONPTY_BROKER_MAX_BUFFERED_BYTES: number;
|
|
3
|
+
export type ConptyBrokerRequest = {
|
|
4
|
+
readonly version: 1;
|
|
5
|
+
readonly auth: string;
|
|
6
|
+
readonly type: 'inspect';
|
|
7
|
+
} | {
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly auth: string;
|
|
10
|
+
readonly type: 'attach';
|
|
11
|
+
readonly cols: number;
|
|
12
|
+
readonly rows: number;
|
|
13
|
+
} | {
|
|
14
|
+
readonly version: 1;
|
|
15
|
+
readonly auth: string;
|
|
16
|
+
readonly type: 'input';
|
|
17
|
+
readonly data: string;
|
|
18
|
+
} | {
|
|
19
|
+
readonly version: 1;
|
|
20
|
+
readonly auth: string;
|
|
21
|
+
readonly type: 'resize';
|
|
22
|
+
readonly cols: number;
|
|
23
|
+
readonly rows: number;
|
|
24
|
+
} | {
|
|
25
|
+
readonly version: 1;
|
|
26
|
+
readonly auth: string;
|
|
27
|
+
readonly type: 'detach';
|
|
28
|
+
} | {
|
|
29
|
+
readonly version: 1;
|
|
30
|
+
readonly auth: string;
|
|
31
|
+
readonly type: 'terminate';
|
|
32
|
+
};
|
|
33
|
+
export type ConptyBrokerMessage = {
|
|
34
|
+
readonly version: 1;
|
|
35
|
+
readonly type: 'inspect-result';
|
|
36
|
+
readonly alive: boolean;
|
|
37
|
+
readonly brokerPid: number;
|
|
38
|
+
readonly shellPid: number;
|
|
39
|
+
} | {
|
|
40
|
+
readonly version: 1;
|
|
41
|
+
readonly type: 'attached';
|
|
42
|
+
readonly brokerPid: number;
|
|
43
|
+
readonly shellPid: number;
|
|
44
|
+
} | {
|
|
45
|
+
readonly version: 1;
|
|
46
|
+
readonly type: 'output';
|
|
47
|
+
readonly data: string;
|
|
48
|
+
} | {
|
|
49
|
+
readonly version: 1;
|
|
50
|
+
readonly type: 'exit';
|
|
51
|
+
readonly exitCode: number | null;
|
|
52
|
+
} | {
|
|
53
|
+
readonly version: 1;
|
|
54
|
+
readonly type: 'terminated';
|
|
55
|
+
} | {
|
|
56
|
+
readonly version: 1;
|
|
57
|
+
readonly type: 'error';
|
|
58
|
+
readonly code: string;
|
|
59
|
+
readonly message: string;
|
|
60
|
+
};
|
|
61
|
+
export interface JsonLineTarget {
|
|
62
|
+
write(data: string): unknown;
|
|
63
|
+
}
|
|
64
|
+
/** broker 同时只允许一个 attach;重复连接不能抢占当前终端。 */
|
|
65
|
+
export declare class ExclusiveAttachmentLease<T extends object> {
|
|
66
|
+
private owner;
|
|
67
|
+
acquire(candidate: T): boolean;
|
|
68
|
+
/** 新 attach 接管输入控制权;旧 attach 保持只读输出。 */
|
|
69
|
+
takeover(candidate: T): T | null;
|
|
70
|
+
release(candidate: T): void;
|
|
71
|
+
owns(candidate: T): boolean;
|
|
72
|
+
get current(): T | null;
|
|
73
|
+
}
|
|
74
|
+
/** 每条消息一个 JSON 行,避免终端输出与控制帧混在同一字节流中。 */
|
|
75
|
+
export declare function writeBrokerMessage(target: JsonLineTarget, message: ConptyBrokerMessage | ConptyBrokerRequest): void;
|
|
76
|
+
export declare function createJsonLineParser(onValue: (value: unknown) => void): {
|
|
77
|
+
push(chunk: string | Uint8Array): void;
|
|
78
|
+
};
|
|
79
|
+
export declare function parseBrokerRequest(value: unknown): ConptyBrokerRequest | null;
|
|
80
|
+
export declare function parseBrokerMessage(value: unknown): ConptyBrokerMessage | null;
|
|
81
|
+
/** 无 attach 时只保留最后一段有界输出,避免常驻 broker 无限吃内存。 */
|
|
82
|
+
export declare class BoundedTerminalBuffer {
|
|
83
|
+
readonly maxBytes: number;
|
|
84
|
+
private value;
|
|
85
|
+
constructor(maxBytes?: number);
|
|
86
|
+
push(data: string): void;
|
|
87
|
+
drain(): string;
|
|
88
|
+
/** 返回有界输出副本但不清空,供 DSH 重启后的新 attach 回放。 */
|
|
89
|
+
snapshot(): string;
|
|
90
|
+
get byteLength(): number;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=conpty-broker-protocol.d.ts.map
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export const CONPTY_BROKER_PROTOCOL_VERSION = 1;
|
|
2
|
+
export const CONPTY_BROKER_MAX_BUFFERED_BYTES = 1024 * 1024;
|
|
3
|
+
/** broker 同时只允许一个 attach;重复连接不能抢占当前终端。 */
|
|
4
|
+
export class ExclusiveAttachmentLease {
|
|
5
|
+
owner = null;
|
|
6
|
+
acquire(candidate) {
|
|
7
|
+
if (this.owner !== null && this.owner !== candidate)
|
|
8
|
+
return false;
|
|
9
|
+
this.owner = candidate;
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
/** 新 attach 接管输入控制权;旧 attach 保持只读输出。 */
|
|
13
|
+
takeover(candidate) {
|
|
14
|
+
const previous = this.owner;
|
|
15
|
+
this.owner = candidate;
|
|
16
|
+
return previous;
|
|
17
|
+
}
|
|
18
|
+
release(candidate) {
|
|
19
|
+
if (this.owner === candidate)
|
|
20
|
+
this.owner = null;
|
|
21
|
+
}
|
|
22
|
+
owns(candidate) {
|
|
23
|
+
return this.owner === candidate;
|
|
24
|
+
}
|
|
25
|
+
get current() {
|
|
26
|
+
return this.owner;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** 每条消息一个 JSON 行,避免终端输出与控制帧混在同一字节流中。 */
|
|
30
|
+
export function writeBrokerMessage(target, message) {
|
|
31
|
+
target.write(`${JSON.stringify(message)}\n`);
|
|
32
|
+
}
|
|
33
|
+
export function createJsonLineParser(onValue) {
|
|
34
|
+
const decoder = new TextDecoder();
|
|
35
|
+
let pending = '';
|
|
36
|
+
return {
|
|
37
|
+
push(chunk) {
|
|
38
|
+
pending += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });
|
|
39
|
+
let boundary = pending.indexOf('\n');
|
|
40
|
+
while (boundary >= 0) {
|
|
41
|
+
const line = pending.slice(0, boundary).trim();
|
|
42
|
+
pending = pending.slice(boundary + 1);
|
|
43
|
+
if (line !== '')
|
|
44
|
+
onValue(JSON.parse(line));
|
|
45
|
+
boundary = pending.indexOf('\n');
|
|
46
|
+
}
|
|
47
|
+
if (pending.length > 2 * 1024 * 1024)
|
|
48
|
+
throw new Error('broker 控制帧超过限制');
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function parseBrokerRequest(value) {
|
|
53
|
+
if (!isRecord(value) || value.version !== 1 || typeof value.auth !== 'string' || typeof value.type !== 'string')
|
|
54
|
+
return null;
|
|
55
|
+
if (value.type === 'inspect' || value.type === 'detach' || value.type === 'terminate') {
|
|
56
|
+
return { version: 1, auth: value.auth, type: value.type };
|
|
57
|
+
}
|
|
58
|
+
if (value.type === 'attach' || value.type === 'resize') {
|
|
59
|
+
if (typeof value.cols !== 'number' || typeof value.rows !== 'number')
|
|
60
|
+
return null;
|
|
61
|
+
return { version: 1, auth: value.auth, type: value.type, cols: value.cols, rows: value.rows };
|
|
62
|
+
}
|
|
63
|
+
if (value.type === 'input' && typeof value.data === 'string') {
|
|
64
|
+
return { version: 1, auth: value.auth, type: 'input', data: value.data };
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
export function parseBrokerMessage(value) {
|
|
69
|
+
if (!isRecord(value) || value.version !== 1 || typeof value.type !== 'string')
|
|
70
|
+
return null;
|
|
71
|
+
if (value.type === 'output' && typeof value.data === 'string')
|
|
72
|
+
return { version: 1, type: 'output', data: value.data };
|
|
73
|
+
if (value.type === 'exit' && (typeof value.exitCode === 'number' || value.exitCode === null)) {
|
|
74
|
+
return { version: 1, type: 'exit', exitCode: value.exitCode };
|
|
75
|
+
}
|
|
76
|
+
if (value.type === 'terminated')
|
|
77
|
+
return { version: 1, type: 'terminated' };
|
|
78
|
+
if (value.type === 'error' && typeof value.code === 'string' && typeof value.message === 'string') {
|
|
79
|
+
return { version: 1, type: 'error', code: value.code, message: value.message };
|
|
80
|
+
}
|
|
81
|
+
if ((value.type === 'inspect-result' || value.type === 'attached')
|
|
82
|
+
&& typeof value.brokerPid === 'number' && typeof value.shellPid === 'number') {
|
|
83
|
+
if (value.type === 'inspect-result' && typeof value.alive === 'boolean') {
|
|
84
|
+
return { version: 1, type: 'inspect-result', alive: value.alive, brokerPid: value.brokerPid, shellPid: value.shellPid };
|
|
85
|
+
}
|
|
86
|
+
if (value.type === 'attached') {
|
|
87
|
+
return { version: 1, type: 'attached', brokerPid: value.brokerPid, shellPid: value.shellPid };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/** 无 attach 时只保留最后一段有界输出,避免常驻 broker 无限吃内存。 */
|
|
93
|
+
export class BoundedTerminalBuffer {
|
|
94
|
+
maxBytes;
|
|
95
|
+
value = '';
|
|
96
|
+
constructor(maxBytes = CONPTY_BROKER_MAX_BUFFERED_BYTES) {
|
|
97
|
+
this.maxBytes = maxBytes;
|
|
98
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1)
|
|
99
|
+
throw new Error('缓冲上限必须是正整数');
|
|
100
|
+
}
|
|
101
|
+
push(data) {
|
|
102
|
+
this.value += data;
|
|
103
|
+
while (byteLength(this.value) > this.maxBytes && this.value.length > 0) {
|
|
104
|
+
const overflow = byteLength(this.value) - this.maxBytes;
|
|
105
|
+
// 先按 UTF-16 字符估计裁剪,再校正;不会从半个代理对开始输出。
|
|
106
|
+
let cut = Math.max(1, Math.min(this.value.length, overflow));
|
|
107
|
+
if (cut < this.value.length && isLowSurrogate(this.value.charCodeAt(cut)))
|
|
108
|
+
cut += 1;
|
|
109
|
+
this.value = this.value.slice(cut);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
drain() {
|
|
113
|
+
const output = this.value;
|
|
114
|
+
this.value = '';
|
|
115
|
+
return output;
|
|
116
|
+
}
|
|
117
|
+
/** 返回有界输出副本但不清空,供 DSH 重启后的新 attach 回放。 */
|
|
118
|
+
snapshot() {
|
|
119
|
+
return this.value;
|
|
120
|
+
}
|
|
121
|
+
get byteLength() {
|
|
122
|
+
return byteLength(this.value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function byteLength(value) {
|
|
126
|
+
return new TextEncoder().encode(value).byteLength;
|
|
127
|
+
}
|
|
128
|
+
function isLowSurrogate(value) {
|
|
129
|
+
return value >= 0xdc00 && value <= 0xdfff;
|
|
130
|
+
}
|
|
131
|
+
function isRecord(value) {
|
|
132
|
+
return typeof value === 'object' && value !== null;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=conpty-broker-protocol.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { TerminalEnhancementSettings } from '../../shared/contracts/config.js';
|
|
3
|
+
import { CodingNsTerminalController, type DshTerminalAgent } from './terminal-controller.js';
|
|
4
|
+
import type { TerminalRuntimeAdapter } from './runtime-adapter.js';
|
|
5
|
+
import { CodingNsTerminalService } from './terminal-service.js';
|
|
6
|
+
import { TerminalProcessService } from './terminal-process-service.js';
|
|
7
|
+
interface TerminalControllerFactoryCommonOptions {
|
|
8
|
+
readonly settings: () => TerminalEnhancementSettings;
|
|
9
|
+
readonly platform?: string;
|
|
10
|
+
readonly generation?: (agent: DshTerminalAgent, attachmentId: string) => string;
|
|
11
|
+
readonly workspaceId?: (agent: DshTerminalAgent, cwd: string) => string;
|
|
12
|
+
readonly resolveWorkspaceRoot?: (workspaceId: string) => string | null;
|
|
13
|
+
}
|
|
14
|
+
export type TerminalControllerFactoryOptions = TerminalControllerFactoryCommonOptions & ({
|
|
15
|
+
readonly enhancedEnabled: false;
|
|
16
|
+
readonly baselineBackend?: TerminalRuntimeAdapter;
|
|
17
|
+
} | {
|
|
18
|
+
readonly enhancedEnabled: true;
|
|
19
|
+
readonly hostId: string;
|
|
20
|
+
readonly storeFilename: string;
|
|
21
|
+
readonly processStoreFilename?: string;
|
|
22
|
+
});
|
|
23
|
+
export interface TerminalControllerFactoryResult {
|
|
24
|
+
readonly mode: 'baseline' | 'enhanced';
|
|
25
|
+
readonly controller: CodingNsTerminalController;
|
|
26
|
+
readonly service: CodingNsTerminalService;
|
|
27
|
+
readonly processService: TerminalProcessService;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 启动时一次性选择 controller 模式。
|
|
31
|
+
*
|
|
32
|
+
* 开关写入只影响下一次调用;当前进程绝不热切同名 Cordis 服务。两个模式共用
|
|
33
|
+
* 插件自有 controller,区别只在 backend 和 store 的生命周期。
|
|
34
|
+
*/
|
|
35
|
+
export declare function createTerminalController(ctx: Context, options: TerminalControllerFactoryOptions): Promise<TerminalControllerFactoryResult>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=controller-factory.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ConptyTerminalBackend } from './backends/conpty-backend.js';
|
|
2
|
+
import { LocalPtyTerminalBackend } from './backends/local-pty-backend.js';
|
|
3
|
+
import { TmuxTerminalBackend } from './backends/tmux-backend.js';
|
|
4
|
+
import { CodingNsTerminalController } from './terminal-controller.js';
|
|
5
|
+
import { TerminalRuntimeManager } from './runtime-manager.js';
|
|
6
|
+
import { CodingNsTerminalService } from './terminal-service.js';
|
|
7
|
+
import { CodingNsTerminalStore, InMemoryTerminalStorePersistence, JsonFileTerminalStorePersistence, } from './terminal-store.js';
|
|
8
|
+
import { InMemoryTerminalProcessStorePersistence, JsonFileTerminalProcessStorePersistence, TerminalProcessStore, } from './terminal-process-store.js';
|
|
9
|
+
import { TerminalProcessService } from './terminal-process-service.js';
|
|
10
|
+
/**
|
|
11
|
+
* 启动时一次性选择 controller 模式。
|
|
12
|
+
*
|
|
13
|
+
* 开关写入只影响下一次调用;当前进程绝不热切同名 Cordis 服务。两个模式共用
|
|
14
|
+
* 插件自有 controller,区别只在 backend 和 store 的生命周期。
|
|
15
|
+
*/
|
|
16
|
+
export async function createTerminalController(ctx, options) {
|
|
17
|
+
const platform = options.platform ?? process.platform;
|
|
18
|
+
if (!options.enhancedEnabled) {
|
|
19
|
+
const backend = options.baselineBackend ?? new LocalPtyTerminalBackend({ platform });
|
|
20
|
+
return assembleController(ctx, {
|
|
21
|
+
mode: 'baseline',
|
|
22
|
+
hostId: 'local-baseline',
|
|
23
|
+
store: new CodingNsTerminalStore(new InMemoryTerminalStorePersistence()),
|
|
24
|
+
backend,
|
|
25
|
+
processStore: new TerminalProcessStore(new InMemoryTerminalProcessStorePersistence()),
|
|
26
|
+
settings: options.settings,
|
|
27
|
+
platform,
|
|
28
|
+
runtimeType: () => 'local-pty',
|
|
29
|
+
...(options.generation === undefined ? {} : { generation: options.generation }),
|
|
30
|
+
...(options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }),
|
|
31
|
+
...(options.resolveWorkspaceRoot === undefined ? {} : { resolveWorkspaceRoot: options.resolveWorkspaceRoot }),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const backend = platform === 'win32'
|
|
35
|
+
? new ConptyTerminalBackend({ platform })
|
|
36
|
+
: new TmuxTerminalBackend({ platform });
|
|
37
|
+
return assembleController(ctx, {
|
|
38
|
+
mode: 'enhanced',
|
|
39
|
+
hostId: options.hostId,
|
|
40
|
+
store: new CodingNsTerminalStore(new JsonFileTerminalStorePersistence(options.storeFilename)),
|
|
41
|
+
processStore: new TerminalProcessStore(new JsonFileTerminalProcessStorePersistence(options.processStoreFilename ?? `${options.storeFilename}.processes`)),
|
|
42
|
+
backend,
|
|
43
|
+
settings: options.settings,
|
|
44
|
+
platform,
|
|
45
|
+
...(options.generation === undefined ? {} : { generation: options.generation }),
|
|
46
|
+
...(options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }),
|
|
47
|
+
...(options.resolveWorkspaceRoot === undefined ? {} : { resolveWorkspaceRoot: options.resolveWorkspaceRoot }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function assembleController(ctx, options) {
|
|
51
|
+
const service = new CodingNsTerminalService(options.store, new TerminalRuntimeManager([options.backend]));
|
|
52
|
+
await service.initialize();
|
|
53
|
+
if (options.mode === 'enhanced')
|
|
54
|
+
await service.recover();
|
|
55
|
+
const controller = new CodingNsTerminalController(ctx, {
|
|
56
|
+
hostId: options.hostId,
|
|
57
|
+
service,
|
|
58
|
+
settings: options.settings,
|
|
59
|
+
...(options.platform === undefined ? {} : { platform: options.platform }),
|
|
60
|
+
...(options.generation === undefined ? {} : { generation: options.generation }),
|
|
61
|
+
...(options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }),
|
|
62
|
+
...(options.runtimeType === undefined ? {} : { runtimeType: options.runtimeType }),
|
|
63
|
+
});
|
|
64
|
+
const processService = new TerminalProcessService(options.processStore, {
|
|
65
|
+
hostId: options.hostId,
|
|
66
|
+
terminalService: service,
|
|
67
|
+
resolveWorkspaceRoot: options.resolveWorkspaceRoot ?? ((workspaceId) => workspaceId),
|
|
68
|
+
});
|
|
69
|
+
await processService.initialize();
|
|
70
|
+
if (options.mode === 'enhanced')
|
|
71
|
+
await processService.recover();
|
|
72
|
+
ctx.effect(() => () => service.dispose(), options.mode === 'baseline'
|
|
73
|
+
? 'codingns4dsh: 本机 PTY 与终端 attach 清理'
|
|
74
|
+
: 'codingns4dsh: 持久终端 attach 清理');
|
|
75
|
+
return {
|
|
76
|
+
mode: options.mode,
|
|
77
|
+
controller,
|
|
78
|
+
service,
|
|
79
|
+
processService,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=controller-factory.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './runtime-adapter.js';
|
|
2
|
+
export * from './runtime-manager.js';
|
|
3
|
+
export * from './attachment-registry.js';
|
|
4
|
+
export * from './terminal-store.js';
|
|
5
|
+
export * from './terminal-service.js';
|
|
6
|
+
export * from './terminal-process-store.js';
|
|
7
|
+
export * from './terminal-process-service.js';
|
|
8
|
+
export * from './terminal-controller.js';
|
|
9
|
+
export * from './controller-factory.js';
|
|
10
|
+
export * from './startup.js';
|
|
11
|
+
export * from './shell-detection.js';
|
|
12
|
+
export * from './backends/tmux-backend.js';
|
|
13
|
+
export * from './backends/conpty-backend.js';
|
|
14
|
+
export * from './backends/local-pty-backend.js';
|
|
15
|
+
export * from './broker/conpty-broker-client.js';
|
|
16
|
+
export * from './broker/conpty-broker-protocol.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './runtime-adapter.js';
|
|
2
|
+
export * from './runtime-manager.js';
|
|
3
|
+
export * from './attachment-registry.js';
|
|
4
|
+
export * from './terminal-store.js';
|
|
5
|
+
export * from './terminal-service.js';
|
|
6
|
+
export * from './terminal-process-store.js';
|
|
7
|
+
export * from './terminal-process-service.js';
|
|
8
|
+
export * from './terminal-controller.js';
|
|
9
|
+
export * from './controller-factory.js';
|
|
10
|
+
export * from './startup.js';
|
|
11
|
+
export * from './shell-detection.js';
|
|
12
|
+
export * from './backends/tmux-backend.js';
|
|
13
|
+
export * from './backends/conpty-backend.js';
|
|
14
|
+
export * from './backends/local-pty-backend.js';
|
|
15
|
+
export * from './broker/conpty-broker-client.js';
|
|
16
|
+
export * from './broker/conpty-broker-protocol.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CodingNsTerminalRuntimeType } from '../../shared/contracts/terminal.js';
|
|
2
|
+
/** Host backend 直接复用共享持久记录的运行时枚举,避免 controller 做无意义转换。 */
|
|
3
|
+
export type TerminalRuntimeType = CodingNsTerminalRuntimeType;
|
|
4
|
+
/** 持久运行时只保存可在 DSH 重启后重新定位会话的字段。 */
|
|
5
|
+
export interface TerminalRuntimeSession {
|
|
6
|
+
readonly runtimeSessionKey: string;
|
|
7
|
+
readonly runtimeType: TerminalRuntimeType;
|
|
8
|
+
readonly shellPath: string;
|
|
9
|
+
readonly shellArgs: readonly string[];
|
|
10
|
+
/** 启动项 PTY 的实际命令;未设置时使用 shellPath/shellArgs。 */
|
|
11
|
+
readonly commandPath?: string;
|
|
12
|
+
readonly commandArgs?: readonly string[];
|
|
13
|
+
readonly commandEnv?: Readonly<Record<string, string>>;
|
|
14
|
+
readonly cwd: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TerminalRuntimeIdentity {
|
|
17
|
+
readonly alive: boolean;
|
|
18
|
+
readonly runtimeSessionKey: string;
|
|
19
|
+
readonly runtimePid: number | null;
|
|
20
|
+
readonly shellPid: number | null;
|
|
21
|
+
readonly detail?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TerminalRuntimeCreateInput {
|
|
24
|
+
readonly session: TerminalRuntimeSession;
|
|
25
|
+
readonly cols?: number;
|
|
26
|
+
readonly rows?: number;
|
|
27
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
28
|
+
}
|
|
29
|
+
export interface TerminalRuntimeAttachInput {
|
|
30
|
+
readonly session: TerminalRuntimeSession;
|
|
31
|
+
readonly cols: number;
|
|
32
|
+
readonly rows: number;
|
|
33
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
34
|
+
readonly onData: (data: string) => void;
|
|
35
|
+
readonly onExit?: (exitCode: number | null) => void;
|
|
36
|
+
}
|
|
37
|
+
export interface TerminalRuntimeAttachment {
|
|
38
|
+
readonly attachmentId: string;
|
|
39
|
+
readonly identity: TerminalRuntimeIdentity;
|
|
40
|
+
}
|
|
41
|
+
export interface TerminalRuntimeWriteInput {
|
|
42
|
+
readonly attachmentId: string;
|
|
43
|
+
readonly data: string;
|
|
44
|
+
}
|
|
45
|
+
export interface TerminalRuntimeResizeInput {
|
|
46
|
+
readonly attachmentId: string;
|
|
47
|
+
readonly cols: number;
|
|
48
|
+
readonly rows: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* controller 只依赖这个接口。持久 session 与短命 attachment 使用不同标识,
|
|
52
|
+
* 因而卸载插件或切换 generation 时不会误杀 tmux/ConPTY。
|
|
53
|
+
*/
|
|
54
|
+
export interface TerminalRuntimeAdapter {
|
|
55
|
+
readonly runtimeTypes: readonly TerminalRuntimeType[];
|
|
56
|
+
create(input: TerminalRuntimeCreateInput): Promise<TerminalRuntimeIdentity>;
|
|
57
|
+
inspect(session: TerminalRuntimeSession): Promise<TerminalRuntimeIdentity>;
|
|
58
|
+
attach(input: TerminalRuntimeAttachInput): Promise<TerminalRuntimeAttachment>;
|
|
59
|
+
write(input: TerminalRuntimeWriteInput): Promise<void>;
|
|
60
|
+
resize(input: TerminalRuntimeResizeInput): Promise<void>;
|
|
61
|
+
detach(attachmentId: string): Promise<void>;
|
|
62
|
+
terminate(session: TerminalRuntimeSession): Promise<void>;
|
|
63
|
+
/** 仅供进程内 backend 释放自身拥有的运行时;持久 backend 不实现此方法。 */
|
|
64
|
+
dispose?(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
export type TerminalRuntimeErrorCode = 'TERMINAL_PLATFORM_UNSUPPORTED' | 'TERMINAL_RUNTIME_UNAVAILABLE' | 'TERMINAL_RUNTIME_CREATE_FAILED' | 'TERMINAL_RUNTIME_LOST' | 'TERMINAL_ATTACHMENT_NOT_FOUND' | 'TERMINAL_ALREADY_ATTACHED' | 'TERMINAL_BROKER_PROTOCOL_INVALID' | 'TERMINAL_BROKER_UNAUTHORIZED';
|
|
67
|
+
export declare class TerminalRuntimeError extends Error {
|
|
68
|
+
readonly code: TerminalRuntimeErrorCode;
|
|
69
|
+
constructor(code: TerminalRuntimeErrorCode, message: string, options?: {
|
|
70
|
+
readonly cause?: unknown;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export declare function normalizeTerminalSize(cols: number, rows: number): {
|
|
74
|
+
cols: number;
|
|
75
|
+
rows: number;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=runtime-adapter.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class TerminalRuntimeError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.name = 'TerminalRuntimeError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function normalizeTerminalSize(cols, rows) {
|
|
10
|
+
return {
|
|
11
|
+
cols: normalizeDimension(cols, 20, 500, 120),
|
|
12
|
+
rows: normalizeDimension(rows, 5, 300, 30),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function normalizeDimension(value, minimum, maximum, fallback) {
|
|
16
|
+
return Number.isFinite(value) ? Math.min(maximum, Math.max(minimum, Math.trunc(value))) : fallback;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=runtime-adapter.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PersistentTerminalRecord, TerminalRecordIdentity } from '../../shared/contracts/terminal.js';
|
|
2
|
+
import { type ManagedTerminalAttachment } from './attachment-registry.js';
|
|
3
|
+
import type { TerminalRuntimeAdapter, TerminalRuntimeIdentity } from './runtime-adapter.js';
|
|
4
|
+
export interface RuntimeAttachmentInput {
|
|
5
|
+
readonly identity: TerminalRecordIdentity;
|
|
6
|
+
readonly generation: string;
|
|
7
|
+
readonly streamId: string;
|
|
8
|
+
readonly requestedAttachmentId: string;
|
|
9
|
+
readonly cols: number;
|
|
10
|
+
readonly rows: number;
|
|
11
|
+
readonly onData: (data: string) => void;
|
|
12
|
+
readonly onExit: (exitCode: number | null) => void;
|
|
13
|
+
}
|
|
14
|
+
/** 统一选择 backend,并确保停用插件时只清理 attach,不结束持久进程。 */
|
|
15
|
+
export declare class TerminalRuntimeManager {
|
|
16
|
+
private readonly adapters;
|
|
17
|
+
private readonly registry;
|
|
18
|
+
private readonly monitors;
|
|
19
|
+
constructor(adapters: readonly TerminalRuntimeAdapter[]);
|
|
20
|
+
create(record: PersistentTerminalRecord): Promise<TerminalRuntimeIdentity>;
|
|
21
|
+
inspect(record: PersistentTerminalRecord): Promise<TerminalRuntimeIdentity>;
|
|
22
|
+
attach(record: PersistentTerminalRecord, input: RuntimeAttachmentInput): Promise<ManagedTerminalAttachment>;
|
|
23
|
+
write(subscriptionId: string, data: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* 在不抢占浏览器 attach 控制权的前提下,向持久终端写入一次启动命令。
|
|
26
|
+
* 这是调试快捷启动所需的“先开 Shell、再发送命令”路径。
|
|
27
|
+
*/
|
|
28
|
+
writeSession(record: PersistentTerminalRecord, data: string): Promise<void>;
|
|
29
|
+
resize(subscriptionId: string, cols: number, rows: number): Promise<void>;
|
|
30
|
+
detach(subscriptionId: string): Promise<void>;
|
|
31
|
+
detachGeneration(generation: string): Promise<void>;
|
|
32
|
+
detachTerminal(identity: TerminalRecordIdentity): Promise<void>;
|
|
33
|
+
/** 为 Host 进程状态提供退出监听,不获取终端输入控制权。 */
|
|
34
|
+
monitor(record: PersistentTerminalRecord, onExit: (exitCode: number | null) => void): Promise<void>;
|
|
35
|
+
detachMonitor(record: PersistentTerminalRecord): Promise<void>;
|
|
36
|
+
dispose(): Promise<void>;
|
|
37
|
+
terminate(record: PersistentTerminalRecord): Promise<void>;
|
|
38
|
+
private adapter;
|
|
39
|
+
private requireAttachment;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=runtime-manager.d.ts.map
|