@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.
Files changed (312) hide show
  1. package/README.md +1114 -0
  2. package/assets/provider-icons/claude-code.png +0 -0
  3. package/assets/provider-icons/codex.png +0 -0
  4. package/assets/provider-icons/command-code.svg +5 -0
  5. package/assets/provider-icons/deepseek-harness.svg +9 -0
  6. package/assets/provider-icons/gemini.png +0 -0
  7. package/assets/provider-icons/grok.png +0 -0
  8. package/assets/provider-icons/kimi.png +0 -0
  9. package/assets/provider-icons/opencode.png +0 -0
  10. package/assets/provider-icons/pi.svg +7 -0
  11. package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +97 -0
  12. package/data/build/dist/bootstrap/dsh-connection-adapter.js +169 -0
  13. package/data/build/dist/bootstrap/index.d.ts +38 -0
  14. package/data/build/dist/bootstrap/index.js +44 -0
  15. package/data/build/dist/client/account-bar.d.ts +9 -0
  16. package/data/build/dist/client/account-bar.js +398 -0
  17. package/data/build/dist/client/bundle.js +26167 -0
  18. package/data/build/dist/client/cli-catalog.d.ts +24 -0
  19. package/data/build/dist/client/cli-catalog.js +108 -0
  20. package/data/build/dist/client/cli-slots.d.ts +38 -0
  21. package/data/build/dist/client/cli-slots.js +297 -0
  22. package/data/build/dist/client/debug/ui.d.ts +12 -0
  23. package/data/build/dist/client/debug/ui.js +451 -0
  24. package/data/build/dist/client/dsh-h5-bootstrap.d.ts +64 -0
  25. package/data/build/dist/client/dsh-h5-bootstrap.js +293 -0
  26. package/data/build/dist/client/dsh-runtime-version.d.ts +3 -0
  27. package/data/build/dist/client/dsh-runtime-version.js +11 -0
  28. package/data/build/dist/client/external-tool-stream.d.ts +24 -0
  29. package/data/build/dist/client/external-tool-stream.js +114 -0
  30. package/data/build/dist/client/features/cli-adapters.d.ts +7 -0
  31. package/data/build/dist/client/features/cli-adapters.js +215 -0
  32. package/data/build/dist/client/features/debug.d.ts +4 -0
  33. package/data/build/dist/client/features/debug.js +24 -0
  34. package/data/build/dist/client/features/index.d.ts +33 -0
  35. package/data/build/dist/client/features/index.js +44 -0
  36. package/data/build/dist/client/features/lan-access-panel.d.ts +5 -0
  37. package/data/build/dist/client/features/lan-access-panel.js +146 -0
  38. package/data/build/dist/client/features/lan-access.d.ts +9 -0
  39. package/data/build/dist/client/features/lan-access.js +30 -0
  40. package/data/build/dist/client/features/login-protection-panel.d.ts +5 -0
  41. package/data/build/dist/client/features/login-protection-panel.js +91 -0
  42. package/data/build/dist/client/features/login-protection-session.d.ts +6 -0
  43. package/data/build/dist/client/features/login-protection-session.js +25 -0
  44. package/data/build/dist/client/features/login-protection.d.ts +4 -0
  45. package/data/build/dist/client/features/login-protection.js +23 -0
  46. package/data/build/dist/client/features/reverse-proxy-panel.d.ts +9 -0
  47. package/data/build/dist/client/features/reverse-proxy-panel.js +159 -0
  48. package/data/build/dist/client/features/reverse-proxy.d.ts +12 -0
  49. package/data/build/dist/client/features/reverse-proxy.js +112 -0
  50. package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +5 -0
  51. package/data/build/dist/client/features/terminal-enhancement-panel.js +160 -0
  52. package/data/build/dist/client/features/terminal-enhancement.d.ts +4 -0
  53. package/data/build/dist/client/features/terminal-enhancement.js +24 -0
  54. package/data/build/dist/client/features/types.d.ts +58 -0
  55. package/data/build/dist/client/features/types.js +2 -0
  56. package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +5 -0
  57. package/data/build/dist/client/features/workspace-session-enhancement-panel.js +66 -0
  58. package/data/build/dist/client/features/workspace-session-enhancement.d.ts +4 -0
  59. package/data/build/dist/client/features/workspace-session-enhancement.js +101 -0
  60. package/data/build/dist/client/h5-bootstrap-entry.d.ts +2 -0
  61. package/data/build/dist/client/h5-bootstrap-entry.js +17 -0
  62. package/data/build/dist/client/index.d.ts +31 -0
  63. package/data/build/dist/client/index.js +98 -0
  64. package/data/build/dist/client/lan-access.d.ts +28 -0
  65. package/data/build/dist/client/lan-access.js +68 -0
  66. package/data/build/dist/client/locale.d.ts +20 -0
  67. package/data/build/dist/client/locale.js +393 -0
  68. package/data/build/dist/client/provider-icon-assets.d.ts +2 -0
  69. package/data/build/dist/client/provider-icon-assets.js +23 -0
  70. package/data/build/dist/client/provider-icons.d.ts +19 -0
  71. package/data/build/dist/client/provider-icons.js +39 -0
  72. package/data/build/dist/client/remote-web-context.d.ts +57 -0
  73. package/data/build/dist/client/remote-web-context.js +939 -0
  74. package/data/build/dist/client/session-adapter-cache.d.ts +18 -0
  75. package/data/build/dist/client/session-adapter-cache.js +84 -0
  76. package/data/build/dist/client/settings-bridge.d.ts +32 -0
  77. package/data/build/dist/client/settings-bridge.js +126 -0
  78. package/data/build/dist/client/settings-section.d.ts +30 -0
  79. package/data/build/dist/client/settings-section.js +93 -0
  80. package/data/build/dist/client/subscription-slot.d.ts +18 -0
  81. package/data/build/dist/client/subscription-slot.js +223 -0
  82. package/data/build/dist/client/terminal/index.d.ts +4 -0
  83. package/data/build/dist/client/terminal/index.js +3 -0
  84. package/data/build/dist/client/terminal/model.d.ts +116 -0
  85. package/data/build/dist/client/terminal/model.js +435 -0
  86. package/data/build/dist/client/terminal/styles.d.ts +21 -0
  87. package/data/build/dist/client/terminal/styles.js +51 -0
  88. package/data/build/dist/client/terminal/ui.d.ts +19 -0
  89. package/data/build/dist/client/terminal/ui.js +257 -0
  90. package/data/build/dist/client/terminal/xterm-view.d.ts +13 -0
  91. package/data/build/dist/client/terminal/xterm-view.js +213 -0
  92. package/data/build/dist/client/theme.d.ts +56 -0
  93. package/data/build/dist/client/theme.js +186 -0
  94. package/data/build/dist/client/workspace-session-archive-dom.d.ts +29 -0
  95. package/data/build/dist/client/workspace-session-archive-dom.js +525 -0
  96. package/data/build/dist/client/workspace-session-fiber.d.ts +3 -0
  97. package/data/build/dist/client/workspace-session-fiber.js +33 -0
  98. package/data/build/dist/client/workspace-session-logo-dom.d.ts +26 -0
  99. package/data/build/dist/client/workspace-session-logo-dom.js +128 -0
  100. package/data/build/dist/features/index.d.ts +3 -0
  101. package/data/build/dist/features/index.js +2 -0
  102. package/data/build/dist/features/registry.d.ts +74 -0
  103. package/data/build/dist/features/registry.js +382 -0
  104. package/data/build/dist/features/resource-scope/index.d.ts +39 -0
  105. package/data/build/dist/features/resource-scope/index.js +161 -0
  106. package/data/build/dist/host/auth-session.d.ts +42 -0
  107. package/data/build/dist/host/auth-session.js +186 -0
  108. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +14 -0
  109. package/data/build/dist/host/cli-adapters/claude-driver.js +103 -0
  110. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +45 -0
  111. package/data/build/dist/host/cli-adapters/codex-driver.js +534 -0
  112. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts +38 -0
  113. package/data/build/dist/host/cli-adapters/command-code-driver.js +394 -0
  114. package/data/build/dist/host/cli-adapters/command-code-subscription.d.ts +19 -0
  115. package/data/build/dist/host/cli-adapters/command-code-subscription.js +126 -0
  116. package/data/build/dist/host/cli-adapters/driver.d.ts +41 -0
  117. package/data/build/dist/host/cli-adapters/driver.js +2 -0
  118. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +37 -0
  119. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +180 -0
  120. package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +48 -0
  121. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +373 -0
  122. package/data/build/dist/host/cli-adapters/feature.d.ts +7 -0
  123. package/data/build/dist/host/cli-adapters/feature.js +335 -0
  124. package/data/build/dist/host/cli-adapters/gemini-driver.d.ts +24 -0
  125. package/data/build/dist/host/cli-adapters/gemini-driver.js +427 -0
  126. package/data/build/dist/host/cli-adapters/grok-driver.d.ts +38 -0
  127. package/data/build/dist/host/cli-adapters/grok-driver.js +372 -0
  128. package/data/build/dist/host/cli-adapters/http-sse-client.d.ts +22 -0
  129. package/data/build/dist/host/cli-adapters/http-sse-client.js +99 -0
  130. package/data/build/dist/host/cli-adapters/interaction-events.d.ts +11 -0
  131. package/data/build/dist/host/cli-adapters/interaction-events.js +80 -0
  132. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +65 -0
  133. package/data/build/dist/host/cli-adapters/json-rpc-process.js +256 -0
  134. package/data/build/dist/host/cli-adapters/kimi-driver.d.ts +21 -0
  135. package/data/build/dist/host/cli-adapters/kimi-driver.js +382 -0
  136. package/data/build/dist/host/cli-adapters/model-catalog.d.ts +22 -0
  137. package/data/build/dist/host/cli-adapters/model-catalog.js +89 -0
  138. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +55 -0
  139. package/data/build/dist/host/cli-adapters/opencode-driver.js +728 -0
  140. package/data/build/dist/host/cli-adapters/pi-driver.d.ts +43 -0
  141. package/data/build/dist/host/cli-adapters/pi-driver.js +312 -0
  142. package/data/build/dist/host/cli-adapters/process-utils.d.ts +16 -0
  143. package/data/build/dist/host/cli-adapters/process-utils.js +27 -0
  144. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +82 -0
  145. package/data/build/dist/host/cli-adapters/provider-subscription.js +610 -0
  146. package/data/build/dist/host/cli-adapters/registry.d.ts +95 -0
  147. package/data/build/dist/host/cli-adapters/registry.js +659 -0
  148. package/data/build/dist/host/cli-adapters/rpc-driver-utils.d.ts +24 -0
  149. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +119 -0
  150. package/data/build/dist/host/cli-adapters/session-probe.d.ts +20 -0
  151. package/data/build/dist/host/cli-adapters/session-probe.js +139 -0
  152. package/data/build/dist/host/cli-adapters/session-store.d.ts +68 -0
  153. package/data/build/dist/host/cli-adapters/session-store.js +180 -0
  154. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +45 -0
  155. package/data/build/dist/host/cli-adapters/standard-stream-driver.js +205 -0
  156. package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +25 -0
  157. package/data/build/dist/host/cli-adapters/stream-normalizer.js +83 -0
  158. package/data/build/dist/host/cli-adapters/tool-observation.d.ts +9 -0
  159. package/data/build/dist/host/cli-adapters/tool-observation.js +39 -0
  160. package/data/build/dist/host/control-api-client.d.ts +84 -0
  161. package/data/build/dist/host/control-api-client.js +130 -0
  162. package/data/build/dist/host/credential-store.d.ts +54 -0
  163. package/data/build/dist/host/credential-store.js +114 -0
  164. package/data/build/dist/host/debug.d.ts +79 -0
  165. package/data/build/dist/host/debug.js +295 -0
  166. package/data/build/dist/host/dsh-device-runtime.d.ts +39 -0
  167. package/data/build/dist/host/dsh-device-runtime.js +118 -0
  168. package/data/build/dist/host/dsh-gateway-feature.d.ts +5 -0
  169. package/data/build/dist/host/dsh-gateway-feature.js +55 -0
  170. package/data/build/dist/host/dsh-runtime-version.d.ts +12 -0
  171. package/data/build/dist/host/dsh-runtime-version.js +69 -0
  172. package/data/build/dist/host/features/auth.d.ts +11 -0
  173. package/data/build/dist/host/features/auth.js +273 -0
  174. package/data/build/dist/host/features/debug.d.ts +5 -0
  175. package/data/build/dist/host/features/debug.js +90 -0
  176. package/data/build/dist/host/features/host-status.d.ts +12 -0
  177. package/data/build/dist/host/features/host-status.js +54 -0
  178. package/data/build/dist/host/features/index.d.ts +19 -0
  179. package/data/build/dist/host/features/index.js +29 -0
  180. package/data/build/dist/host/features/lan-access-dsh.d.ts +8 -0
  181. package/data/build/dist/host/features/lan-access-dsh.js +45 -0
  182. package/data/build/dist/host/features/terminal-process.d.ts +5 -0
  183. package/data/build/dist/host/features/terminal-process.js +110 -0
  184. package/data/build/dist/host/features/terminal-status.d.ts +18 -0
  185. package/data/build/dist/host/features/terminal-status.js +56 -0
  186. package/data/build/dist/host/features/types.d.ts +41 -0
  187. package/data/build/dist/host/features/types.js +2 -0
  188. package/data/build/dist/host/index.d.ts +43 -0
  189. package/data/build/dist/host/index.js +135 -0
  190. package/data/build/dist/host/lan-access-dsh.d.ts +83 -0
  191. package/data/build/dist/host/lan-access-dsh.js +831 -0
  192. package/data/build/dist/host/native-session-bridge.d.ts +130 -0
  193. package/data/build/dist/host/native-session-bridge.js +317 -0
  194. package/data/build/dist/host/relay-tunnel-runtime.d.ts +97 -0
  195. package/data/build/dist/host/relay-tunnel-runtime.js +361 -0
  196. package/data/build/dist/host/remote-web-runtime.d.ts +78 -0
  197. package/data/build/dist/host/remote-web-runtime.js +559 -0
  198. package/data/build/dist/host/rpc-table.d.ts +32 -0
  199. package/data/build/dist/host/rpc-table.js +47 -0
  200. package/data/build/dist/host/rpc.d.ts +18 -0
  201. package/data/build/dist/host/rpc.js +248 -0
  202. package/data/build/dist/host/settings.d.ts +19 -0
  203. package/data/build/dist/host/settings.js +80 -0
  204. package/data/build/dist/host/terminal/attachment-registry.d.ts +17 -0
  205. package/data/build/dist/host/terminal/attachment-registry.js +49 -0
  206. package/data/build/dist/host/terminal/backends/conpty-backend.d.ts +39 -0
  207. package/data/build/dist/host/terminal/backends/conpty-backend.js +160 -0
  208. package/data/build/dist/host/terminal/backends/local-pty-backend.d.ts +36 -0
  209. package/data/build/dist/host/terminal/backends/local-pty-backend.js +178 -0
  210. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +40 -0
  211. package/data/build/dist/host/terminal/backends/tmux-backend.js +191 -0
  212. package/data/build/dist/host/terminal/broker/conpty-broker-client.d.ts +27 -0
  213. package/data/build/dist/host/terminal/broker/conpty-broker-client.js +154 -0
  214. package/data/build/dist/host/terminal/broker/conpty-broker-process.d.ts +10 -0
  215. package/data/build/dist/host/terminal/broker/conpty-broker-process.js +147 -0
  216. package/data/build/dist/host/terminal/broker/conpty-broker-protocol.d.ts +92 -0
  217. package/data/build/dist/host/terminal/broker/conpty-broker-protocol.js +134 -0
  218. package/data/build/dist/host/terminal/controller-factory.d.ts +37 -0
  219. package/data/build/dist/host/terminal/controller-factory.js +82 -0
  220. package/data/build/dist/host/terminal/index.d.ts +17 -0
  221. package/data/build/dist/host/terminal/index.js +17 -0
  222. package/data/build/dist/host/terminal/runtime-adapter.d.ts +77 -0
  223. package/data/build/dist/host/terminal/runtime-adapter.js +18 -0
  224. package/data/build/dist/host/terminal/runtime-manager.d.ts +41 -0
  225. package/data/build/dist/host/terminal/runtime-manager.js +179 -0
  226. package/data/build/dist/host/terminal/shell-detection.d.ts +23 -0
  227. package/data/build/dist/host/terminal/shell-detection.js +105 -0
  228. package/data/build/dist/host/terminal/startup.d.ts +33 -0
  229. package/data/build/dist/host/terminal/startup.js +100 -0
  230. package/data/build/dist/host/terminal/terminal-controller.d.ts +78 -0
  231. package/data/build/dist/host/terminal/terminal-controller.js +324 -0
  232. package/data/build/dist/host/terminal/terminal-process-service.d.ts +30 -0
  233. package/data/build/dist/host/terminal/terminal-process-service.js +194 -0
  234. package/data/build/dist/host/terminal/terminal-process-store.d.ts +45 -0
  235. package/data/build/dist/host/terminal/terminal-process-store.js +183 -0
  236. package/data/build/dist/host/terminal/terminal-service.d.ts +87 -0
  237. package/data/build/dist/host/terminal/terminal-service.js +528 -0
  238. package/data/build/dist/host/terminal/terminal-store.d.ts +49 -0
  239. package/data/build/dist/host/terminal/terminal-store.js +242 -0
  240. package/data/build/dist/index.d.ts +37 -0
  241. package/data/build/dist/index.js +26 -0
  242. package/data/build/dist/shared/contracts/auth.d.ts +122 -0
  243. package/data/build/dist/shared/contracts/auth.js +8 -0
  244. package/data/build/dist/shared/contracts/cli-adapter.d.ts +192 -0
  245. package/data/build/dist/shared/contracts/cli-adapter.js +2 -0
  246. package/data/build/dist/shared/contracts/command-code.d.ts +5 -0
  247. package/data/build/dist/shared/contracts/command-code.js +2 -0
  248. package/data/build/dist/shared/contracts/config.d.ts +113 -0
  249. package/data/build/dist/shared/contracts/config.js +86 -0
  250. package/data/build/dist/shared/contracts/debug-config.d.ts +28 -0
  251. package/data/build/dist/shared/contracts/debug-config.js +78 -0
  252. package/data/build/dist/shared/contracts/debug.d.ts +75 -0
  253. package/data/build/dist/shared/contracts/debug.js +121 -0
  254. package/data/build/dist/shared/contracts/dsh-device.d.ts +72 -0
  255. package/data/build/dist/shared/contracts/dsh-device.js +2 -0
  256. package/data/build/dist/shared/contracts/errors.d.ts +33 -0
  257. package/data/build/dist/shared/contracts/errors.js +41 -0
  258. package/data/build/dist/shared/contracts/feature.d.ts +71 -0
  259. package/data/build/dist/shared/contracts/feature.js +2 -0
  260. package/data/build/dist/shared/contracts/host-status.d.ts +14 -0
  261. package/data/build/dist/shared/contracts/host-status.js +2 -0
  262. package/data/build/dist/shared/contracts/lan-access-dsh.d.ts +30 -0
  263. package/data/build/dist/shared/contracts/lan-access-dsh.js +2 -0
  264. package/data/build/dist/shared/contracts/peer-host.d.ts +37 -0
  265. package/data/build/dist/shared/contracts/peer-host.js +9 -0
  266. package/data/build/dist/shared/contracts/signaling.d.ts +67 -0
  267. package/data/build/dist/shared/contracts/signaling.js +2 -0
  268. package/data/build/dist/shared/contracts/subscription.d.ts +69 -0
  269. package/data/build/dist/shared/contracts/subscription.js +2 -0
  270. package/data/build/dist/shared/contracts/terminal-process.d.ts +65 -0
  271. package/data/build/dist/shared/contracts/terminal-process.js +2 -0
  272. package/data/build/dist/shared/contracts/terminal.d.ts +127 -0
  273. package/data/build/dist/shared/contracts/terminal.js +2 -0
  274. package/data/build/dist/shared/contracts/transport.d.ts +45 -0
  275. package/data/build/dist/shared/contracts/transport.js +3 -0
  276. package/data/build/dist/shared/contracts/version.d.ts +19 -0
  277. package/data/build/dist/shared/contracts/version.js +74 -0
  278. package/data/build/dist/shared/index.d.ts +22 -0
  279. package/data/build/dist/shared/index.js +9 -0
  280. package/data/build/dist/transport/carrier.d.ts +38 -0
  281. package/data/build/dist/transport/carrier.js +268 -0
  282. package/data/build/dist/transport/debug.d.ts +22 -0
  283. package/data/build/dist/transport/debug.js +57 -0
  284. package/data/build/dist/transport/dsh-envelope.d.ts +41 -0
  285. package/data/build/dist/transport/dsh-envelope.js +107 -0
  286. package/data/build/dist/transport/dsh-gateway.d.ts +64 -0
  287. package/data/build/dist/transport/dsh-gateway.js +254 -0
  288. package/data/build/dist/transport/dsh-session.d.ts +55 -0
  289. package/data/build/dist/transport/dsh-session.js +256 -0
  290. package/data/build/dist/transport/dsh-transport.d.ts +57 -0
  291. package/data/build/dist/transport/dsh-transport.js +125 -0
  292. package/data/build/dist/transport/frame.d.ts +132 -0
  293. package/data/build/dist/transport/frame.js +168 -0
  294. package/data/build/dist/transport/index.d.ts +11 -0
  295. package/data/build/dist/transport/index.js +11 -0
  296. package/data/build/dist/transport/multiplexer.d.ts +63 -0
  297. package/data/build/dist/transport/multiplexer.js +323 -0
  298. package/data/build/dist/transport/webrtc-client.d.ts +65 -0
  299. package/data/build/dist/transport/webrtc-client.js +255 -0
  300. package/data/build/dist/transport/webrtc-host.d.ts +58 -0
  301. package/data/build/dist/transport/webrtc-host.js +252 -0
  302. package/data/build/dist/typert.host.d.ts +25 -0
  303. package/data/build/dist/typert.host.js +150 -0
  304. package/dsh.bundle.patch +12 -0
  305. package/package.json +135 -0
  306. package/profile/README.md +27 -0
  307. package/profile/cordis.patch.yml +2 -0
  308. package/profile/package.json +20 -0
  309. package/profile/scripts/check-dsh-install.mjs +71 -0
  310. package/profile/version.json +5 -0
  311. package/scripts/check-dsh-install.mjs +88 -0
  312. package/version.json +6 -0
@@ -0,0 +1,248 @@
1
+ import { CODINGNS_SETTINGS_NAMESPACE } from '../shared/contracts/config.js';
2
+ import { CodingNsRpcError } from './rpc-table.js';
3
+ /**
4
+ * 创建 Codingns4DSH Host RPC 主处理器。
5
+ *
6
+ * 它只做一次 `namespace/action` 前缀解析,具体动作由各功能模块在启动时登记的
7
+ * 命名空间处理器实现;新增模块不需要修改这个文件。这是浏览器表单与 Host 能力
8
+ * 之间的唯一边界:密码只在一次 RPC 请求中经过 Host,refresh token 只进入 Host
9
+ * 凭据存储。
10
+ */
11
+ export function createCodingNsRpcHandler(table) {
12
+ return async (endpoint, payload) => {
13
+ const target = table.resolve(endpoint);
14
+ if (target === null) {
15
+ return failure('CODINGNS_RPC_NOT_FOUND', `未知 Codingns4DSH RPC: ${endpoint}`);
16
+ }
17
+ try {
18
+ return success(await target.handler(target.action, payload));
19
+ }
20
+ catch (error) {
21
+ return failure(errorCode(error), error instanceof Error ? error.message : String(error));
22
+ }
23
+ };
24
+ }
25
+ /** 在当前 Connection 上挂载 Codingns4DSH RPC 主处理器;注销由调用方的 effect 负责。 */
26
+ export function registerCodingNsRpc(ctx, table, settingsProvider) {
27
+ // 连接服务的 rpc.handle 内部会把路由注册延迟到另一个 effect;该 effect 的 owner
28
+ // 不携带本插件的 webServer 注入,在部分 DSH 版本中会直接失败。因此这里捕获已经
29
+ // 注入的服务实例,挂载同协议的前缀路由,避免把 RPC 请求落到 SPA fallback。
30
+ const webServer = ctx.webServer;
31
+ const connection = ctx.connection;
32
+ ctx.effect(() => {
33
+ const unregisterSettings = settingsProvider === undefined
34
+ ? undefined
35
+ : table.register('settings', createCodingNsSettingsRpcHandler(settingsProvider));
36
+ const handler = createCodingNsRpcHandler(table);
37
+ const unregisterChannel = webServer.register({
38
+ kind: 'prefix',
39
+ path: '/codingns',
40
+ handler: (request, response) => handleChannelRequest(request, response, connection, handler),
41
+ });
42
+ // 保留旧的精确 Fetch 路由,兼容早期 H5/桌面载体直接访问 `/api/codingns/*`
43
+ // 的调用方。两条入口共享同一个 handler,不复制任何业务逻辑。
44
+ const disposeFetch = CODINGNS_RPC_ENDPOINTS.map((endpoint) => ctx.connection.fetch.register({
45
+ path: `/api/codingns/${endpoint}`,
46
+ methods: ['POST'],
47
+ requestBody: 'buffered',
48
+ fetch: async (request) => handleFetchRpc(request, endpoint, handler),
49
+ }));
50
+ return async () => {
51
+ for (const dispose of disposeFetch.reverse())
52
+ await dispose();
53
+ unregisterChannel();
54
+ unregisterSettings?.();
55
+ };
56
+ }, 'codingns4dsh: Host RPC');
57
+ }
58
+ async function handleChannelRequest(request, response, connection, handler) {
59
+ const abortController = new AbortController();
60
+ request.once('close', () => abortController.abort());
61
+ const rejection = connection.requestRejection({ headers: request.headers });
62
+ if (rejection !== undefined) {
63
+ response.statusCode = rejection;
64
+ response.end(rejection === 401 ? 'unauthorized' : 'forbidden');
65
+ return;
66
+ }
67
+ const endpoint = endpointFromChannelUrl(request.url);
68
+ if (request.method !== 'POST' || endpoint === undefined) {
69
+ response.statusCode = 404;
70
+ response.end('not found');
71
+ return;
72
+ }
73
+ const contentType = request.headers['content-type']?.split(';', 1)[0]?.trim().toLowerCase();
74
+ if (contentType !== 'application/json') {
75
+ response.statusCode = 415;
76
+ response.end('content type must be application/json');
77
+ return;
78
+ }
79
+ let body;
80
+ try {
81
+ body = JSON.parse(await readRequestBody(request));
82
+ }
83
+ catch {
84
+ response.statusCode = 400;
85
+ response.end('body is not JSON');
86
+ return;
87
+ }
88
+ if (!isRecord(body) || body.type !== 'client-request' || typeof body.rpcId !== 'string' || typeof body.method !== 'string') {
89
+ writeRpcResponse(response, typeof body?.rpcId === 'string' ? body.rpcId : 'invalid-request', {
90
+ ok: false,
91
+ error: { code: 'gateway/bad-request', message: 'invalid client-request message', details: {} },
92
+ });
93
+ return;
94
+ }
95
+ if (body.method !== endpoint) {
96
+ writeRpcResponse(response, body.rpcId, {
97
+ ok: false,
98
+ error: { code: 'gateway/bad-request', message: `method ${JSON.stringify(body.method)} does not match endpoint ${JSON.stringify(endpoint)}`, details: {} },
99
+ });
100
+ return;
101
+ }
102
+ try {
103
+ writeRpcResponse(response, body.rpcId, await handler(endpoint, body.payload, abortController.signal));
104
+ }
105
+ catch (error) {
106
+ response.statusCode = 500;
107
+ response.end(`handler failure: ${String(error)}`);
108
+ }
109
+ }
110
+ function endpointFromChannelUrl(rawUrl) {
111
+ if (rawUrl === undefined)
112
+ return undefined;
113
+ const pathname = new URL(rawUrl, 'http://127.0.0.1').pathname;
114
+ if (!pathname.startsWith('/codingns/'))
115
+ return undefined;
116
+ const endpoint = pathname.slice('/codingns/'.length);
117
+ if (endpoint === '' || endpoint.split('/').some((segment) => segment === '' || segment === '.' || segment === '..' || !/^[A-Za-z0-9_$.-]+$/u.test(segment)))
118
+ return undefined;
119
+ return endpoint;
120
+ }
121
+ async function readRequestBody(request) {
122
+ const chunks = [];
123
+ let size = 0;
124
+ for await (const chunk of request) {
125
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
126
+ size += buffer.byteLength;
127
+ if (size > 4 * 1024 * 1024)
128
+ throw new Error('request body too large');
129
+ chunks.push(buffer);
130
+ }
131
+ return Buffer.concat(chunks).toString('utf8');
132
+ }
133
+ function writeRpcResponse(response, rpcId, result) {
134
+ const body = JSON.stringify({ type: 'server-response', rpcId, result });
135
+ response.statusCode = 200;
136
+ response.setHeader('content-type', 'application/json; charset=utf-8');
137
+ response.end(body);
138
+ }
139
+ const CODINGNS_RPC_ENDPOINTS = [
140
+ 'auth/snapshot', 'auth/login', 'auth/logout', 'auth/devices', 'auth/bind', 'auth/unbind', 'auth/signalingTicket', 'auth/dsh/device/list', 'auth/dsh/device/start', 'auth/dsh/device/stop', 'auth/dsh/device/status', 'auth/dsh/relayTicket',
141
+ 'host/status',
142
+ 'settings/get', 'settings/set',
143
+ 'terminal/status',
144
+ 'terminalProcess/profile/list', 'terminalProcess/profile/create', 'terminalProcess/profile/delete',
145
+ 'terminalProcess/launch', 'terminalProcess/runtime/list', 'terminalProcess/runtime/get', 'terminalProcess/runtime/stop',
146
+ 'debug/config/get', 'debug/config/save', 'debug/config/update', 'debug/config/delete', 'debug/profile/list', 'debug/profile/launch',
147
+ 'debug/runtime/get', 'debug/runtime/list', 'debug/runtime/stop',
148
+ 'debug/port/check', 'debug/port/terminate', 'debug/port/kill', 'debug/proxy/get', 'debug/proxy/enable', 'debug/proxy/disable',
149
+ 'lanAccessDsh/addresses', 'lanAccessDsh/detect', 'lanAccessDsh/get', 'lanAccessDsh/settings/get', 'lanAccessDsh/settings/set', 'lanAccessDsh/login/get', 'lanAccessDsh/login/set', 'lanAccessDsh/login/session/open', 'lanAccessDsh/start', 'lanAccessDsh/stop',
150
+ 'cli/catalog', 'cli/models', 'cli/adapter/set', 'cli/session/get', 'cli/session/set', 'cli/session/list', 'cli/session/adapter-map', 'cli/session/archive', 'cli/session/steer', 'cli/session/follow-up', 'cli/session/interrupt', 'cli/subscription',
151
+ ];
152
+ /** 创建远程设置处理器;只允许 Codingns4DSH 自己的 namespace 和路径编辑。 */
153
+ export function createCodingNsSettingsRpcHandler(provider) {
154
+ return async (action, payload) => {
155
+ if (action === 'get')
156
+ return readCodingNsSettings(provider);
157
+ if (action === 'set') {
158
+ if (!provider.writable)
159
+ throw new CodingNsRpcError('CODINGNS_SETTINGS_READ_ONLY', 'Host 设置提供器当前只读');
160
+ const input = parseSettingsMutation(payload);
161
+ await provider.mutate(CODINGNS_SETTINGS_NAMESPACE, input.ops, input.expectedRevision);
162
+ return readCodingNsSettings(provider);
163
+ }
164
+ throw new CodingNsRpcError('CODINGNS_RPC_NOT_FOUND', `未知 Codingns4DSH RPC: settings/${action}`);
165
+ };
166
+ }
167
+ function readCodingNsSettings(provider) {
168
+ const descriptor = provider.describe({ redactSecrets: true }).find((item) => item.ns === CODINGNS_SETTINGS_NAMESPACE);
169
+ if (descriptor === undefined)
170
+ throw new CodingNsRpcError('CODINGNS_SETTINGS_UNAVAILABLE', 'Codingns4DSH 设置尚未注册');
171
+ const value = provider.get(CODINGNS_SETTINGS_NAMESPACE);
172
+ // cliSessions 是 Host-only 索引,包含 providerSessionId/rawStoreRef,不能通过设置 RPC
173
+ // 暴露给浏览器。外部会话列表必须走 cli/session/list,由 Host 按需返回摘要。
174
+ const { cliSessions: _cliSessions, ...clientValue } = value;
175
+ return { value: clientValue, revision: descriptor.revision };
176
+ }
177
+ function parseSettingsMutation(value) {
178
+ if (!isRecord(value) || !Array.isArray(value.ops) || value.ops.length === 0 || value.ops.length > 8) {
179
+ throw new TypeError('settings/set 参数必须包含 1 到 8 个 ops');
180
+ }
181
+ const expectedRevisionValue = value.expectedRevision;
182
+ if (expectedRevisionValue !== undefined && (typeof expectedRevisionValue !== 'number' || !Number.isInteger(expectedRevisionValue) || expectedRevisionValue < 0)) {
183
+ throw new TypeError('expectedRevision 必须是非负整数');
184
+ }
185
+ const ops = value.ops.map(parseSettingsOp);
186
+ return expectedRevisionValue === undefined ? { ops } : { ops, expectedRevision: expectedRevisionValue };
187
+ }
188
+ function parseSettingsOp(value) {
189
+ if (!isRecord(value) || (value.op !== 'set' && value.op !== 'unset') || !Array.isArray(value.path)) {
190
+ throw new TypeError('设置操作必须是 { op, path, value? }');
191
+ }
192
+ const path = value.path;
193
+ if (path.length === 0 || path.length > 3 || path.some((part) => typeof part !== 'string' || !/^[A-Za-z][A-Za-z0-9_-]*$/u.test(part))) {
194
+ throw new TypeError('设置路径非法');
195
+ }
196
+ if (!isAllowedSettingsPath(path))
197
+ throw new CodingNsRpcError('CODINGNS_SETTINGS_FIELD_FORBIDDEN', `禁止修改设置字段: ${path.join('.')}`);
198
+ if (value.op === 'unset')
199
+ return { op: 'unset', path };
200
+ if (!('value' in value))
201
+ throw new TypeError('set 操作缺少 value');
202
+ return { op: 'set', path, value: value.value };
203
+ }
204
+ function isAllowedSettingsPath(path) {
205
+ if (path.length === 1)
206
+ return ['controlBaseUrl', 'controlBaseUrls', 'terminalEnhancement', 'workspaceSessionEnhancement'].includes(path[0] ?? '');
207
+ if (path[0] === 'modules')
208
+ return path.length === 2 && ['lanAccess', 'reverseProxy', 'cliAdapters', 'terminalEnhancement', 'workspaceSessionEnhancement', 'debug'].includes(path[1] ?? '');
209
+ if (path[0] === 'workspaceSessionEnhancement') {
210
+ return path.length === 2 && ['showAdapterLogo', 'showArchivedSessions', 'showSubscriptionUsage'].includes(path[1] ?? '');
211
+ }
212
+ return path[0] === 'lanAccessDsh' && path.length === 2 && ['autoStart', 'listenHost', 'listenPort', 'dshPort'].includes(path[1] ?? '');
213
+ }
214
+ function isRecord(value) {
215
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
216
+ }
217
+ async function handleFetchRpc(request, endpoint, handler) {
218
+ let body;
219
+ try {
220
+ body = await request.json();
221
+ }
222
+ catch {
223
+ return new Response('body is not JSON', { status: 400 });
224
+ }
225
+ if (!body || typeof body !== 'object')
226
+ return new Response('invalid RPC envelope', { status: 400 });
227
+ const envelope = body;
228
+ const method = envelope.method;
229
+ if (typeof envelope.rpcId !== 'string' || (method !== endpoint && method !== `codingns/${endpoint}`)) {
230
+ return new Response('invalid RPC envelope', { status: 400 });
231
+ }
232
+ const result = await handler(endpoint, envelope.payload, request.signal);
233
+ return Response.json({ type: 'server-response', rpcId: envelope.rpcId, result });
234
+ }
235
+ function success(value) {
236
+ return { ok: true, value };
237
+ }
238
+ function failure(code, message) {
239
+ return { ok: false, error: { code, message, details: {} } };
240
+ }
241
+ function errorCode(error) {
242
+ if (error && typeof error === 'object' && 'errorCode' in error && typeof error.errorCode === 'string')
243
+ return error.errorCode;
244
+ if (error instanceof Error && error.name)
245
+ return error.name;
246
+ return 'CODINGNS_RPC_FAILED';
247
+ }
248
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1,19 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import z from '@deepseek-ai/schemastery';
3
+ import type { SettingsScope } from '@deepseek-ai/dsh-settings';
4
+ import { type CodingNsSettings } from '../shared/contracts/config.js';
5
+ /**
6
+ * DSH 设置服务使用的 Codingns4DSH namespace schema。
7
+ *
8
+ * 模块开关用字典表达:新增模块只是字典里多一个键,既不需要改这个 schema,
9
+ * 也不需要改 CodingNsSettings 接口。
10
+ */
11
+ export declare const CodingNsSettingsSchema: z<CodingNsSettings>;
12
+ /**
13
+ * 在 Host 设置文档中注册 Codingns4DSH 的持久化选项。
14
+ *
15
+ * 必须在已经注入 `settings` 的上下文里调用。返回的 scope 既用于读取当前值,
16
+ * 也通过 watch 驱动功能模块启停。
17
+ */
18
+ export declare function registerCodingNsSettings(ctx: Context): SettingsScope<CodingNsSettings>;
19
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1,80 @@
1
+ import z from '@deepseek-ai/schemastery';
2
+ import { CODINGNS_SETTINGS_NAMESPACE, DEFAULT_CODINGNS_SETTINGS, } from '../shared/contracts/config.js';
3
+ /**
4
+ * DSH 设置服务使用的 Codingns4DSH namespace schema。
5
+ *
6
+ * 模块开关用字典表达:新增模块只是字典里多一个键,既不需要改这个 schema,
7
+ * 也不需要改 CodingNsSettings 接口。
8
+ */
9
+ export const CodingNsSettingsSchema = z.object({
10
+ controlBaseUrl: z.string().default(DEFAULT_CODINGNS_SETTINGS.controlBaseUrl),
11
+ controlBaseUrls: z.array(z.string()).default(DEFAULT_CODINGNS_SETTINGS.controlBaseUrls),
12
+ modules: z.dict(z.boolean()).default(DEFAULT_CODINGNS_SETTINGS.modules),
13
+ agentAdapters: z.dict(z.boolean()).default(DEFAULT_CODINGNS_SETTINGS.agentAdapters ?? {}),
14
+ agentAdapterPreferences: z.dict(z.object({
15
+ modelId: z.union([z.string(), z.const(undefined)]),
16
+ effortId: z.union([z.string(), z.const(undefined)]),
17
+ })).default({}),
18
+ // 会话索引是 Host 摘要数据,不能让它进入浏览器状态或模型上下文。
19
+ cliSessions: z.array(z.any()).default(DEFAULT_CODINGNS_SETTINGS.cliSessions ?? []),
20
+ lanAccessDsh: z.object({
21
+ autoStart: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.lanAccessDsh.autoStart),
22
+ listenHost: z.string().default(DEFAULT_CODINGNS_SETTINGS.lanAccessDsh.listenHost),
23
+ listenPort: z.number().default(DEFAULT_CODINGNS_SETTINGS.lanAccessDsh.listenPort),
24
+ dshPort: z.number().default(DEFAULT_CODINGNS_SETTINGS.lanAccessDsh.dshPort),
25
+ }).default(DEFAULT_CODINGNS_SETTINGS.lanAccessDsh),
26
+ terminalEnhancement: z.object({
27
+ bindingScope: z.union([z.const('workspace'), z.const('session')])
28
+ .default(DEFAULT_CODINGNS_SETTINGS.terminalEnhancement.bindingScope ?? 'workspace'),
29
+ defaultProfile: z.union([
30
+ z.const('system'), z.const('zsh'), z.const('bash'),
31
+ z.const('powershell'), z.const('cmd'), z.const('git-bash'),
32
+ ]).default(DEFAULT_CODINGNS_SETTINGS.terminalEnhancement.defaultProfile),
33
+ appearance: z.object({
34
+ theme: z.union([z.const('inherit'), z.const('custom')])
35
+ .default(DEFAULT_CODINGNS_SETTINGS.terminalEnhancement.appearance.theme),
36
+ background: nullableColorSchema(),
37
+ foreground: nullableColorSchema(),
38
+ cursorColor: nullableColorSchema(),
39
+ fontFamily: z.union([
40
+ z.string().min(1).max(128).pattern(/^[^\u0000-\u001F\u007F]+$/u),
41
+ z.const(null),
42
+ ]).default(null),
43
+ fontSize: nullableNumberSchema(10, 32),
44
+ lineHeight: nullableNumberSchema(1, 2),
45
+ cursorStyle: z.union([
46
+ z.const('block'), z.const('bar'), z.const('underline'), z.const(null),
47
+ ]).default(null),
48
+ cursorBlink: z.union([z.boolean(), z.const(null)]).default(null),
49
+ scrollback: z.union([z.number().step(1).min(1000).max(100000), z.const(null)]).default(null),
50
+ }).default(DEFAULT_CODINGNS_SETTINGS.terminalEnhancement.appearance),
51
+ }).default({
52
+ ...DEFAULT_CODINGNS_SETTINGS.terminalEnhancement,
53
+ bindingScope: DEFAULT_CODINGNS_SETTINGS.terminalEnhancement.bindingScope ?? 'workspace',
54
+ }),
55
+ workspaceSessionEnhancement: z.object({
56
+ showAdapterLogo: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showAdapterLogo),
57
+ showArchivedSessions: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showArchivedSessions),
58
+ showSubscriptionUsage: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showSubscriptionUsage),
59
+ }).default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement),
60
+ });
61
+ /** 颜色字段只接受完整十六进制颜色,`null` 表示继承 DSH 原生值。 */
62
+ function nullableColorSchema() {
63
+ return z.union([z.string().pattern(/^#[0-9A-Fa-f]{6}$/u), z.const(null)]).default(null);
64
+ }
65
+ function nullableNumberSchema(min, max) {
66
+ return z.union([z.number().min(min).max(max), z.const(null)]).default(null);
67
+ }
68
+ /**
69
+ * 在 Host 设置文档中注册 Codingns4DSH 的持久化选项。
70
+ *
71
+ * 必须在已经注入 `settings` 的上下文里调用。返回的 scope 既用于读取当前值,
72
+ * 也通过 watch 驱动功能模块启停。
73
+ */
74
+ export function registerCodingNsSettings(ctx) {
75
+ const settings = ctx.settings;
76
+ return settings.register(CODINGNS_SETTINGS_NAMESPACE, CodingNsSettingsSchema, {
77
+ applies: 'live',
78
+ });
79
+ }
80
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1,17 @@
1
+ import type { CodingNsTerminalRuntimeType, TerminalAttachmentRecord, TerminalRecordIdentity } from '../../shared/contracts/terminal.js';
2
+ export interface ManagedTerminalAttachment extends TerminalAttachmentRecord {
3
+ readonly identity: TerminalRecordIdentity;
4
+ readonly runtimeType: CodingNsTerminalRuntimeType;
5
+ }
6
+ /** generation 级 attach 注册表;这里只持有短命连接,绝不写入持久存储。 */
7
+ export declare class TerminalAttachmentRegistry {
8
+ private readonly attachments;
9
+ add(attachment: ManagedTerminalAttachment): void;
10
+ get(subscriptionId: string): ManagedTerminalAttachment | undefined;
11
+ isCurrent(subscriptionId: string, generation: string, runtimeAttachmentId: string): boolean;
12
+ remove(subscriptionId: string): ManagedTerminalAttachment | undefined;
13
+ listByGeneration(generation: string): readonly ManagedTerminalAttachment[];
14
+ listByTerminal(identity: TerminalRecordIdentity): readonly ManagedTerminalAttachment[];
15
+ list(): readonly ManagedTerminalAttachment[];
16
+ }
17
+ //# sourceMappingURL=attachment-registry.d.ts.map
@@ -0,0 +1,49 @@
1
+ /** generation 级 attach 注册表;这里只持有短命连接,绝不写入持久存储。 */
2
+ export class TerminalAttachmentRegistry {
3
+ attachments = new Map();
4
+ add(attachment) {
5
+ if (this.attachments.has(attachment.subscriptionId)) {
6
+ throw new Error(`终端订阅已经存在: ${attachment.subscriptionId}`);
7
+ }
8
+ this.attachments.set(attachment.subscriptionId, cloneAttachment(attachment));
9
+ }
10
+ get(subscriptionId) {
11
+ const attachment = this.attachments.get(subscriptionId);
12
+ return attachment === undefined ? undefined : cloneAttachment(attachment);
13
+ }
14
+ isCurrent(subscriptionId, generation, runtimeAttachmentId) {
15
+ const attachment = this.attachments.get(subscriptionId);
16
+ return attachment?.generation === generation
17
+ && attachment.runtimeAttachmentId === runtimeAttachmentId;
18
+ }
19
+ remove(subscriptionId) {
20
+ const attachment = this.attachments.get(subscriptionId);
21
+ if (attachment === undefined)
22
+ return undefined;
23
+ this.attachments.delete(subscriptionId);
24
+ return cloneAttachment(attachment);
25
+ }
26
+ listByGeneration(generation) {
27
+ return [...this.attachments.values()]
28
+ .filter((attachment) => attachment.generation === generation)
29
+ .map(cloneAttachment);
30
+ }
31
+ listByTerminal(identity) {
32
+ return [...this.attachments.values()]
33
+ .filter((attachment) => sameIdentity(attachment.identity, identity))
34
+ .map(cloneAttachment);
35
+ }
36
+ list() {
37
+ return [...this.attachments.values()].map(cloneAttachment);
38
+ }
39
+ }
40
+ function sameIdentity(left, right) {
41
+ return left.hostId === right.hostId
42
+ && left.workspaceId === right.workspaceId
43
+ && left.dshSessionId === right.dshSessionId
44
+ && left.terminalId === right.terminalId;
45
+ }
46
+ function cloneAttachment(attachment) {
47
+ return { ...attachment, identity: { ...attachment.identity } };
48
+ }
49
+ //# sourceMappingURL=attachment-registry.js.map
@@ -0,0 +1,39 @@
1
+ import { type ConptyBrokerClientLike } from '../broker/conpty-broker-client.js';
2
+ import { type TerminalRuntimeAdapter, type TerminalRuntimeAttachInput, type TerminalRuntimeAttachment, type TerminalRuntimeCreateInput, type TerminalRuntimeIdentity, type TerminalRuntimeResizeInput, type TerminalRuntimeSession, type TerminalRuntimeWriteInput } from '../runtime-adapter.js';
3
+ export interface ConptyBackendOptions {
4
+ readonly platform?: string;
5
+ readonly brokerClient?: ConptyBrokerClientLike;
6
+ readonly launchBroker?: (input: {
7
+ readonly pipeName: string;
8
+ readonly auth: string;
9
+ readonly shellPath: string;
10
+ readonly shellArgs: readonly string[];
11
+ readonly cwd: string;
12
+ readonly env: Readonly<Record<string, string | undefined>>;
13
+ }) => void;
14
+ readonly startupAttempts?: number;
15
+ readonly startupDelayMs?: number;
16
+ }
17
+ /** DSH 进程只启动和连接 broker;真正的 ConPTY 始终由 detached broker 持有。 */
18
+ export declare class ConptyTerminalBackend implements TerminalRuntimeAdapter {
19
+ readonly runtimeTypes: readonly ["conpty-powershell", "conpty-cmd", "conpty-git-bash"];
20
+ private readonly platform;
21
+ private readonly brokerClient;
22
+ private readonly launchBroker;
23
+ private readonly startupAttempts;
24
+ private readonly startupDelayMs;
25
+ private readonly attachments;
26
+ constructor(options?: ConptyBackendOptions);
27
+ create(input: TerminalRuntimeCreateInput): Promise<TerminalRuntimeIdentity>;
28
+ inspect(session: TerminalRuntimeSession): Promise<TerminalRuntimeIdentity>;
29
+ attach(input: TerminalRuntimeAttachInput): Promise<TerminalRuntimeAttachment>;
30
+ write(input: TerminalRuntimeWriteInput): Promise<void>;
31
+ resize(input: TerminalRuntimeResizeInput): Promise<void>;
32
+ detach(attachmentId: string): Promise<void>;
33
+ terminate(session: TerminalRuntimeSession): Promise<void>;
34
+ private tryInspect;
35
+ private getAttachment;
36
+ private assertSupported;
37
+ }
38
+ export declare function conptyPipeName(runtimeSessionKey: string): string;
39
+ //# sourceMappingURL=conpty-backend.d.ts.map
@@ -0,0 +1,160 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { ConptyBrokerClient, } from '../broker/conpty-broker-client.js';
5
+ import { TerminalRuntimeError, } from '../runtime-adapter.js';
6
+ /** DSH 进程只启动和连接 broker;真正的 ConPTY 始终由 detached broker 持有。 */
7
+ export class ConptyTerminalBackend {
8
+ runtimeTypes = ['conpty-powershell', 'conpty-cmd', 'conpty-git-bash'];
9
+ platform;
10
+ brokerClient;
11
+ launchBroker;
12
+ startupAttempts;
13
+ startupDelayMs;
14
+ attachments = new Map();
15
+ constructor(options = {}) {
16
+ this.platform = options.platform ?? process.platform;
17
+ this.brokerClient = options.brokerClient ?? new ConptyBrokerClient();
18
+ this.launchBroker = options.launchBroker ?? launchDetachedBroker;
19
+ this.startupAttempts = options.startupAttempts ?? 40;
20
+ this.startupDelayMs = options.startupDelayMs ?? 50;
21
+ }
22
+ async create(input) {
23
+ this.assertSupported(input.session);
24
+ const existing = await this.tryInspect(input.session);
25
+ if (existing?.alive)
26
+ return existing;
27
+ const pipeName = conptyPipeName(input.session.runtimeSessionKey);
28
+ this.launchBroker({
29
+ pipeName,
30
+ auth: input.session.runtimeSessionKey,
31
+ shellPath: input.session.commandPath ?? input.session.shellPath,
32
+ shellArgs: input.session.commandArgs ?? input.session.shellArgs,
33
+ cwd: input.session.cwd,
34
+ env: { ...process.env, ...(input.session.commandEnv ?? {}), ...(input.env ?? {}) },
35
+ });
36
+ for (let attempt = 0; attempt < this.startupAttempts; attempt += 1) {
37
+ const identity = await this.tryInspect(input.session);
38
+ if (identity?.alive)
39
+ return identity;
40
+ await delay(this.startupDelayMs);
41
+ }
42
+ throw new TerminalRuntimeError('TERMINAL_RUNTIME_CREATE_FAILED', 'ConPTY broker 启动超时');
43
+ }
44
+ async inspect(session) {
45
+ this.assertSupported(session);
46
+ return (await this.tryInspect(session)) ?? {
47
+ alive: false,
48
+ runtimeSessionKey: session.runtimeSessionKey,
49
+ runtimePid: null,
50
+ shellPid: null,
51
+ detail: 'ConPTY broker 不存在或无法连接',
52
+ };
53
+ }
54
+ async attach(input) {
55
+ this.assertSupported(input.session);
56
+ let attachmentId = null;
57
+ const attachment = await this.brokerClient.attach({
58
+ pipeName: conptyPipeName(input.session.runtimeSessionKey),
59
+ auth: input.session.runtimeSessionKey,
60
+ runtimeSessionKey: input.session.runtimeSessionKey,
61
+ cols: input.cols,
62
+ rows: input.rows,
63
+ onData: input.onData,
64
+ onExit: (exitCode) => {
65
+ if (attachmentId !== null)
66
+ this.attachments.delete(attachmentId);
67
+ input.onExit?.(exitCode);
68
+ },
69
+ });
70
+ attachmentId = attachment.attachmentId;
71
+ this.attachments.set(attachment.attachmentId, attachment);
72
+ return { attachmentId: attachment.attachmentId, identity: attachment.identity };
73
+ }
74
+ async write(input) {
75
+ this.getAttachment(input.attachmentId).write(input.data);
76
+ }
77
+ async resize(input) {
78
+ this.getAttachment(input.attachmentId).resize(input.cols, input.rows);
79
+ }
80
+ async detach(attachmentId) {
81
+ const attachment = this.attachments.get(attachmentId);
82
+ if (attachment === undefined)
83
+ return;
84
+ this.attachments.delete(attachmentId);
85
+ await attachment.detach();
86
+ }
87
+ async terminate(session) {
88
+ this.assertSupported(session);
89
+ for (const [attachmentId, attachment] of this.attachments) {
90
+ if (attachment.identity.runtimeSessionKey === session.runtimeSessionKey)
91
+ await this.detach(attachmentId);
92
+ }
93
+ try {
94
+ await this.brokerClient.terminate(conptyPipeName(session.runtimeSessionKey), session.runtimeSessionKey);
95
+ }
96
+ catch (error) {
97
+ // 已经消失的 broker 等价于关闭完成,保证显式 close 幂等。
98
+ if (!isUnavailable(error))
99
+ throw error;
100
+ }
101
+ }
102
+ async tryInspect(session) {
103
+ try {
104
+ return await this.brokerClient.inspect(conptyPipeName(session.runtimeSessionKey), session.runtimeSessionKey, session.runtimeSessionKey);
105
+ }
106
+ catch (error) {
107
+ if (isUnavailable(error))
108
+ return null;
109
+ throw error;
110
+ }
111
+ }
112
+ getAttachment(attachmentId) {
113
+ const attachment = this.attachments.get(attachmentId);
114
+ if (attachment === undefined)
115
+ throw new TerminalRuntimeError('TERMINAL_ATTACHMENT_NOT_FOUND', '终端 attach 不存在或已经释放');
116
+ return attachment;
117
+ }
118
+ assertSupported(session) {
119
+ if (this.platform !== 'win32') {
120
+ throw new TerminalRuntimeError('TERMINAL_PLATFORM_UNSUPPORTED', 'ConPTY backend 只支持 Windows');
121
+ }
122
+ if (!this.runtimeTypes.includes(session.runtimeType)) {
123
+ throw new TerminalRuntimeError('TERMINAL_PLATFORM_UNSUPPORTED', `ConPTY backend 不支持 ${session.runtimeType}`);
124
+ }
125
+ }
126
+ }
127
+ export function conptyPipeName(runtimeSessionKey) {
128
+ const digest = createHash('sha256').update(runtimeSessionKey).digest('hex').slice(0, 40);
129
+ return `\\\\.\\pipe\\codingns4dsh-${digest}`;
130
+ }
131
+ function launchDetachedBroker(input) {
132
+ const scriptPath = fileURLToPath(new URL('../broker/conpty-broker-process.js', import.meta.url));
133
+ const child = spawn(process.execPath, [
134
+ scriptPath,
135
+ '--pipe', input.pipeName,
136
+ '--shell', input.shellPath,
137
+ '--cwd', input.cwd,
138
+ ], {
139
+ env: {
140
+ ...input.env,
141
+ CODINGNS4DSH_TERMINAL_AUTH: input.auth,
142
+ CODINGNS4DSH_TERMINAL_ARGS: JSON.stringify(input.shellArgs),
143
+ },
144
+ detached: true,
145
+ stdio: 'ignore',
146
+ windowsHide: true,
147
+ shell: false,
148
+ });
149
+ child.unref();
150
+ }
151
+ function isUnavailable(error) {
152
+ if (!(error instanceof Error))
153
+ return false;
154
+ const code = error.code;
155
+ return code === 'ENOENT' || code === 'ECONNREFUSED' || code === 'EPIPE';
156
+ }
157
+ function delay(milliseconds) {
158
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
159
+ }
160
+ //# sourceMappingURL=conpty-backend.js.map
@@ -0,0 +1,36 @@
1
+ import { spawn as spawnPty } from '@lydell/node-pty';
2
+ import { type TerminalRuntimeAdapter, type TerminalRuntimeAttachInput, type TerminalRuntimeAttachment, type TerminalRuntimeCreateInput, type TerminalRuntimeIdentity, type TerminalRuntimeResizeInput, type TerminalRuntimeSession, type TerminalRuntimeWriteInput } from '../runtime-adapter.js';
3
+ export interface LocalPtyBackendOptions {
4
+ readonly platform?: string;
5
+ readonly ptySpawner?: typeof spawnPty;
6
+ readonly createAttachmentId?: () => string;
7
+ }
8
+ /**
9
+ * 非强化模式使用的进程内 PTY。
10
+ *
11
+ * shell 由当前 DSH 进程直接持有,不承诺跨 DSH 重启恢复。浏览器 detach 只
12
+ * 释放订阅;显式关闭或 controller 销毁才结束 shell。
13
+ */
14
+ export declare class LocalPtyTerminalBackend implements TerminalRuntimeAdapter {
15
+ readonly runtimeTypes: readonly ["local-pty"];
16
+ private readonly platform;
17
+ private readonly ptySpawner;
18
+ private readonly createAttachmentId;
19
+ private readonly processes;
20
+ private readonly attachments;
21
+ constructor(options?: LocalPtyBackendOptions);
22
+ create(input: TerminalRuntimeCreateInput): Promise<TerminalRuntimeIdentity>;
23
+ inspect(session: TerminalRuntimeSession): Promise<TerminalRuntimeIdentity>;
24
+ attach(input: TerminalRuntimeAttachInput): Promise<TerminalRuntimeAttachment>;
25
+ write(input: TerminalRuntimeWriteInput): Promise<void>;
26
+ resize(input: TerminalRuntimeResizeInput): Promise<void>;
27
+ detach(attachmentId: string): Promise<void>;
28
+ terminate(session: TerminalRuntimeSession): Promise<void>;
29
+ dispose(): Promise<void>;
30
+ private requireAttachment;
31
+ private handleExit;
32
+ private removeAttachments;
33
+ private releaseProcess;
34
+ private assertSupported;
35
+ }
36
+ //# sourceMappingURL=local-pty-backend.d.ts.map