@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,205 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import readline from 'node:readline';
3
+ import { firstToolText, isToolRecord, normalizeToolStatus, serializeToolValue } from './tool-observation.js';
4
+ import { usageChunk } from './rpc-driver-utils.js';
5
+ import { terminateChildProcess } from './process-utils.js';
6
+ const WINDOWS = process.platform === 'win32';
7
+ /**
8
+ * 把采用 JSONL/stream-json 的 CLI 统一成 Codingns4DSH 的最小驱动契约。
9
+ * 子类只需提供命令参数和事件映射,进程终止、stderr 消费及清理由这里统一处理。
10
+ */
11
+ export class StandardStreamDriver {
12
+ descriptor;
13
+ binaries;
14
+ runSpawnSync;
15
+ runSpawn;
16
+ versionArgs;
17
+ modelArgs;
18
+ cachedBinary = null;
19
+ processes = new Set();
20
+ constructor(descriptor, defaults, options = {}) {
21
+ this.descriptor = descriptor;
22
+ this.binaries = options.binaries ?? defaults.binaries;
23
+ this.versionArgs = options.versionArgs ?? defaults.versionArgs ?? ['--version'];
24
+ this.modelArgs = options.modelArgs ?? defaults.modelArgs ?? ['--help'];
25
+ this.runSpawnSync = options.spawnSync ?? spawnSync;
26
+ this.runSpawn = options.spawn ?? spawn;
27
+ }
28
+ async detect() {
29
+ for (const command of this.binaries) {
30
+ try {
31
+ const result = this.runSpawnSync(command, this.versionArgs, { encoding: 'utf8', timeout: 5_000, windowsHide: true, shell: WINDOWS });
32
+ const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
33
+ const version = this.parseVersion(output);
34
+ if (result.status === 0 && version !== null) {
35
+ this.cachedBinary = command;
36
+ return { installed: true, version, command };
37
+ }
38
+ }
39
+ catch {
40
+ // 候选命令不存在时继续尝试下一个名称。
41
+ }
42
+ }
43
+ return { installed: false, version: null, command: null };
44
+ }
45
+ async listModels() {
46
+ const command = this.cachedBinary ?? (await this.detect()).command;
47
+ if (command === null)
48
+ return emptyCatalog();
49
+ try {
50
+ const result = this.runSpawnSync(command, this.modelArgs, { encoding: 'utf8', timeout: 12_000, windowsHide: true, shell: WINDOWS });
51
+ if (result.status !== 0)
52
+ return emptyCatalog();
53
+ return this.parseModels(`${result.stdout ?? ''}\n${result.stderr ?? ''}`);
54
+ }
55
+ catch {
56
+ return emptyCatalog();
57
+ }
58
+ }
59
+ async *executeTurn(input) {
60
+ const command = this.cachedBinary ?? (await this.detect()).command;
61
+ if (command === null)
62
+ throw new Error(`${this.descriptor.name} 未安装`);
63
+ const child = this.runSpawn(command, this.buildArgs(input), {
64
+ cwd: input.cwd ?? process.cwd(), env: { ...process.env }, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, shell: WINDOWS,
65
+ });
66
+ this.processes.add(child);
67
+ let emittedFinish = false;
68
+ let emittedBinding = input.providerSessionId !== undefined;
69
+ const onAbort = () => { terminateChildProcess(child); };
70
+ input.signal?.addEventListener('abort', onAbort, { once: true });
71
+ if (input.signal?.aborted)
72
+ onAbort();
73
+ child.stderr.on('data', () => undefined);
74
+ try {
75
+ const lines = readline.createInterface({ input: child.stdout });
76
+ try {
77
+ for await (const line of lines) {
78
+ if (!line.trim())
79
+ continue;
80
+ const parsed = parseJson(line);
81
+ if (parsed === null)
82
+ continue;
83
+ if (!emittedBinding) {
84
+ const providerSessionId = typeof parsed.session_id === 'string'
85
+ ? parsed.session_id
86
+ : typeof parsed.sessionId === 'string'
87
+ ? parsed.sessionId
88
+ : null;
89
+ if (providerSessionId !== null && providerSessionId.trim() !== '') {
90
+ emittedBinding = true;
91
+ yield { type: 'session-binding', providerSessionId: providerSessionId.trim() };
92
+ }
93
+ }
94
+ for (const chunk of this.parseEvent(parsed, input)) {
95
+ if (chunk.type === 'finish')
96
+ emittedFinish = true;
97
+ yield chunk;
98
+ }
99
+ }
100
+ }
101
+ finally {
102
+ lines.close();
103
+ }
104
+ if (!emittedFinish) {
105
+ if (input.signal?.aborted)
106
+ yield { type: 'finish', reason: 'cancel' };
107
+ else
108
+ throw new Error(`${this.descriptor.name} 执行失败`);
109
+ }
110
+ }
111
+ finally {
112
+ input.signal?.removeEventListener('abort', onAbort);
113
+ this.processes.delete(child);
114
+ terminateChildProcess(child);
115
+ }
116
+ }
117
+ dispose() {
118
+ for (const child of this.processes)
119
+ terminateChildProcess(child);
120
+ this.processes.clear();
121
+ this.cachedBinary = null;
122
+ }
123
+ parseVersion(output) { return output.match(/\b\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?\b/u)?.[0] ?? null; }
124
+ parseEvent(value, input) {
125
+ return genericEventChunks(value, input.signal?.aborted ?? false);
126
+ }
127
+ parseModels(output) { return parseHelpModels(output); }
128
+ }
129
+ export function emptyCatalog() { return { groups: [], currentModel: null, currentEffort: null }; }
130
+ function parseJson(line) { try {
131
+ const value = JSON.parse(line);
132
+ return isRecord(value) ? value : null;
133
+ }
134
+ catch {
135
+ return null;
136
+ } }
137
+ function isRecord(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); }
138
+ function genericEventChunks(value, cancelled) {
139
+ const chunks = [];
140
+ const type = typeof value.type === 'string' ? value.type.toLowerCase() : '';
141
+ const event = isRecord(value.event) ? value.event : value;
142
+ const eventType = typeof event.type === 'string' ? event.type.toLowerCase() : type;
143
+ if (eventType.includes('think') || eventType.includes('reason')) {
144
+ const delta = isRecord(event.delta) ? event.delta : event;
145
+ const reasoning = typeof event.delta === 'string' ? event.delta : typeof delta.text === 'string' ? delta.text : typeof delta.content === 'string' ? delta.content : null;
146
+ if (reasoning)
147
+ chunks.push({ type: 'reasoning-delta', text: reasoning });
148
+ }
149
+ else {
150
+ const delta = isRecord(event.delta) ? event.delta : event;
151
+ const text = typeof event.delta === 'string' ? event.delta : typeof delta.text === 'string' ? delta.text : typeof delta.content === 'string' ? delta.content : null;
152
+ if (text !== null && text.length > 0 && !['result', 'final', 'error'].includes(eventType))
153
+ chunks.push({ type: 'text-delta', text });
154
+ const message = isRecord(event.message) ? event.message : null;
155
+ const messageContent = message === null ? null : typeof message.content === 'string' ? message.content : null;
156
+ if (messageContent)
157
+ chunks.push({ type: 'text-delta', text: messageContent });
158
+ }
159
+ const nestedTool = isToolRecord(event.tool_call) ? event.tool_call : isToolRecord(event.toolCall) ? event.toolCall : isToolRecord(event.function) ? event.function : event;
160
+ const toolName = firstToolText(nestedTool.toolName, nestedTool.tool_name, nestedTool.name);
161
+ const callId = firstToolText(nestedTool.callId, nestedTool.call_id, nestedTool.toolCallId, nestedTool.tool_call_id, nestedTool.toolUseId, nestedTool.tool_use_id, nestedTool.id, event.tool_call_id, event.tool_use_id);
162
+ if ((toolName || callId) && (eventType.includes('tool') || eventType.includes('function') || eventType.includes('command'))) {
163
+ const input = serializeToolValue(nestedTool.input ?? nestedTool.arguments ?? nestedTool.args ?? nestedTool.parameters);
164
+ const output = serializeToolValue(nestedTool.output ?? nestedTool.result);
165
+ const error = serializeToolValue(nestedTool.error);
166
+ const fallback = error !== undefined || eventType.includes('error') || eventType.includes('fail')
167
+ ? 'failed'
168
+ : output !== undefined || eventType.includes('result') || eventType.includes('complete')
169
+ ? 'completed'
170
+ : 'running';
171
+ chunks.push({
172
+ type: 'tool-event',
173
+ toolName: toolName ?? 'tool',
174
+ status: normalizeToolStatus(nestedTool.status ?? nestedTool.state, fallback),
175
+ ...(callId ? { callId } : {}),
176
+ ...(input !== undefined ? { input } : {}),
177
+ ...(output !== undefined ? { output } : {}),
178
+ ...(output !== undefined ? { outputMode: eventType.includes('delta') ? 'delta' : 'snapshot' } : {}),
179
+ ...(error !== undefined ? { error } : {}),
180
+ ...(firstToolText(nestedTool.agentId, nestedTool.agent_id) ? { agentId: firstToolText(nestedTool.agentId, nestedTool.agent_id) } : {}),
181
+ ...(serializeToolValue(nestedTool.detail) !== undefined ? { detail: serializeToolValue(nestedTool.detail) } : {}),
182
+ });
183
+ }
184
+ const usage = isRecord(value.usage) ? value.usage : isRecord(event.usage) ? event.usage : null;
185
+ const usageEvent = usageChunk(usage);
186
+ if (usageEvent)
187
+ chunks.push(usageEvent);
188
+ if (['result', 'turn_end', 'done', 'complete', 'completed', 'final'].includes(eventType) || type === 'result')
189
+ chunks.push({ type: 'finish', reason: cancelled ? 'cancel' : 'stop' });
190
+ return chunks;
191
+ }
192
+ function parseHelpModels(output) {
193
+ const models = [];
194
+ const seen = new Set();
195
+ for (const line of output.split(/\r?\n/u)) {
196
+ const match = line.match(/(?:--model(?:=|\s+)|model(?:s)?\s*:\s*)([A-Za-z0-9][A-Za-z0-9_./:-]{2,})/iu);
197
+ const id = match?.[1];
198
+ if (!id || /^(?:model|models|string|value)$/iu.test(id) || seen.has(id))
199
+ continue;
200
+ seen.add(id);
201
+ models.push({ id, name: id, efforts: [] });
202
+ }
203
+ return models.length === 0 ? emptyCatalog() : { groups: [{ id: 'default', name: '可用模型', models }], currentModel: null, currentEffort: null };
204
+ }
205
+ //# sourceMappingURL=standard-stream-driver.js.map
@@ -0,0 +1,25 @@
1
+ import type { CodingNsAgentEvent } from '../../shared/contracts/cli-adapter.js';
2
+ type SnapshotChunk = Extract<CodingNsAgentEvent, {
3
+ readonly type: 'reasoning-snapshot' | 'text-snapshot';
4
+ }>;
5
+ export type CodingNsNormalizedAgentEvent = Exclude<CodingNsAgentEvent, SnapshotChunk>;
6
+ /**
7
+ * 把驱动差异收敛成 DSH 可消费的增量流。
8
+ *
9
+ * 有些 CLI 发送真正的 delta,有些 CLI 反复发送从头累积的 snapshot。规范化器
10
+ * 分别记录推理和正文已经发送的内容,避免完整快照被重复追加到 DSH 会话日志。
11
+ */
12
+ export declare class CodingNsAgentEventNormalizer {
13
+ private reasoning;
14
+ private text;
15
+ private reasoningBoundary;
16
+ private textBoundary;
17
+ private usage;
18
+ push(chunk: CodingNsAgentEvent): readonly CodingNsNormalizedAgentEvent[];
19
+ /** 流未携带 finish 时仍返回最后一次统计,避免正常结束路径丢失 usage。 */
20
+ flush(): readonly CodingNsNormalizedAgentEvent[];
21
+ private appendSnapshot;
22
+ private takeUsage;
23
+ }
24
+ export {};
25
+ //# sourceMappingURL=stream-normalizer.d.ts.map
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 把驱动差异收敛成 DSH 可消费的增量流。
3
+ *
4
+ * 有些 CLI 发送真正的 delta,有些 CLI 反复发送从头累积的 snapshot。规范化器
5
+ * 分别记录推理和正文已经发送的内容,避免完整快照被重复追加到 DSH 会话日志。
6
+ */
7
+ export class CodingNsAgentEventNormalizer {
8
+ reasoning = '';
9
+ text = '';
10
+ reasoningBoundary = false;
11
+ textBoundary = false;
12
+ usage = null;
13
+ push(chunk) {
14
+ if (chunk.type === 'reasoning-delta') {
15
+ this.reasoning = this.reasoningBoundary ? chunk.text : this.reasoning + chunk.text;
16
+ this.reasoningBoundary = false;
17
+ return chunk.text === '' ? [] : [chunk];
18
+ }
19
+ if (chunk.type === 'text-delta') {
20
+ this.text = this.textBoundary ? chunk.text : this.text + chunk.text;
21
+ this.textBoundary = false;
22
+ return chunk.text === '' ? [] : [chunk];
23
+ }
24
+ if (chunk.type === 'reasoning-snapshot')
25
+ return this.appendSnapshot('reasoning', chunk.text);
26
+ if (chunk.type === 'text-snapshot')
27
+ return this.appendSnapshot('text', chunk.text);
28
+ if (chunk.type === 'usage') {
29
+ this.usage = chunk;
30
+ return [];
31
+ }
32
+ if (chunk.type === 'tool-event') {
33
+ this.reasoningBoundary = true;
34
+ this.textBoundary = true;
35
+ return [chunk];
36
+ }
37
+ if (chunk.type === 'finish') {
38
+ const usage = this.takeUsage();
39
+ return usage === null ? [chunk] : [usage, chunk];
40
+ }
41
+ return [chunk];
42
+ }
43
+ /** 流未携带 finish 时仍返回最后一次统计,避免正常结束路径丢失 usage。 */
44
+ flush() {
45
+ const usage = this.takeUsage();
46
+ return usage === null ? [] : [usage];
47
+ }
48
+ appendSnapshot(channel, snapshot) {
49
+ const previous = channel === 'reasoning' ? this.reasoning : this.text;
50
+ const boundary = channel === 'reasoning' ? this.reasoningBoundary : this.textBoundary;
51
+ if (channel === 'reasoning')
52
+ this.reasoningBoundary = false;
53
+ else
54
+ this.textBoundary = false;
55
+ // 工具前后通常是两条不同的 Assistant 消息。只有新快照不包含旧基线时才
56
+ // 开启新段;累计快照仍按原基线去重,避免工具事件导致整段重放。
57
+ if (boundary && !snapshot.startsWith(previous)) {
58
+ if (channel === 'reasoning')
59
+ this.reasoning = snapshot;
60
+ else
61
+ this.text = snapshot;
62
+ return snapshot === '' ? [] : [{ type: `${channel}-delta`, text: snapshot }];
63
+ }
64
+ if (previous.startsWith(snapshot))
65
+ return [];
66
+ const text = snapshot.startsWith(previous)
67
+ ? snapshot.slice(previous.length)
68
+ : snapshot.slice(Math.min(previous.length, snapshot.length));
69
+ if (snapshot.length >= previous.length) {
70
+ if (channel === 'reasoning')
71
+ this.reasoning = snapshot;
72
+ else
73
+ this.text = snapshot;
74
+ }
75
+ return text === '' ? [] : [{ type: `${channel}-delta`, text }];
76
+ }
77
+ takeUsage() {
78
+ const usage = this.usage;
79
+ this.usage = null;
80
+ return usage;
81
+ }
82
+ }
83
+ //# sourceMappingURL=stream-normalizer.js.map
@@ -0,0 +1,9 @@
1
+ import type { CodingNsAgentToolEvent } from '../../shared/contracts/cli-adapter.js';
2
+ export type ExternalToolStatus = NonNullable<CodingNsAgentToolEvent['status']>;
3
+ /** 保留 Provider 的结构化参数和结果,不用隐式的 [object Object] 丢失信息。 */
4
+ export declare function serializeToolValue(value: unknown): string | undefined;
5
+ /** 工具状态的常见别名统一到 Host 契约,未知值使用调用方给出的协议阶段。 */
6
+ export declare function normalizeToolStatus(value: unknown, fallback: ExternalToolStatus): ExternalToolStatus;
7
+ export declare function firstToolText(...values: unknown[]): string | undefined;
8
+ export declare function isToolRecord(value: unknown): value is Record<string, any>;
9
+ //# sourceMappingURL=tool-observation.d.ts.map
@@ -0,0 +1,39 @@
1
+ /** 保留 Provider 的结构化参数和结果,不用隐式的 [object Object] 丢失信息。 */
2
+ export function serializeToolValue(value) {
3
+ if (value === undefined || value === null)
4
+ return undefined;
5
+ if (typeof value === 'string')
6
+ return value;
7
+ try {
8
+ return JSON.stringify(value) ?? String(value);
9
+ }
10
+ catch {
11
+ return String(value);
12
+ }
13
+ }
14
+ /** 工具状态的常见别名统一到 Host 契约,未知值使用调用方给出的协议阶段。 */
15
+ export function normalizeToolStatus(value, fallback) {
16
+ const status = typeof value === 'string' ? value.trim().toLowerCase().replace(/[\s-]+/gu, '_') : '';
17
+ if (['queued', 'pending', 'starting', 'started'].includes(status))
18
+ return 'started';
19
+ if (['running', 'in_progress', 'inprogress', 'streaming'].includes(status))
20
+ return 'running';
21
+ if (['completed', 'complete', 'done', 'success', 'succeeded'].includes(status))
22
+ return 'completed';
23
+ if (['failed', 'failure', 'error', 'denied', 'rejected', 'cancelled', 'canceled'].includes(status))
24
+ return 'failed';
25
+ return fallback;
26
+ }
27
+ export function firstToolText(...values) {
28
+ for (const value of values) {
29
+ if (typeof value === 'string' && value.trim() !== '')
30
+ return value.trim();
31
+ if (typeof value === 'number' && Number.isFinite(value))
32
+ return String(value);
33
+ }
34
+ return undefined;
35
+ }
36
+ export function isToolRecord(value) {
37
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
38
+ }
39
+ //# sourceMappingURL=tool-observation.js.map
@@ -0,0 +1,84 @@
1
+ import type { AuthDeviceManagementSnapshotDto, HostBindRequest, HostBindResponse, HostBindingsResponse, HostLabelAvailabilityResponse, HostUnbindResponse, LoginByEmailRequest } from '../shared/contracts/auth.js';
2
+ import type { DshDeviceHeartbeatResponse, DshDeviceListResponse, DshDeviceRegistrationRequest, DshDeviceRegistrationResponse, DshRelayTicketRequest, DshRelayTicketResponse } from '../shared/contracts/dsh-device.js';
3
+ import type { RelaySignalingTicketRequest, RelaySignalingTicketResponse } from '../shared/contracts/signaling.js';
4
+ /** 仅 Host 使用的控制面会话响应;refresh token 不进入 shared/client 类型。 */
5
+ export interface LoginByEmailResponse {
6
+ account: import('../shared/contracts/auth.js').AccountProfile;
7
+ accessToken: string;
8
+ expiresAt: string;
9
+ refreshToken: string;
10
+ refreshTokenExpiresAt: string;
11
+ }
12
+ export interface RefreshTokenRequest {
13
+ refreshToken: string;
14
+ }
15
+ export type RefreshTokenResponse = LoginByEmailResponse;
16
+ /** codingns-proxy Control API 的真实路径,供后续 HTTP 实现复用。 */
17
+ export declare const CODINGNS_CONTROL_API_PATHS: {
18
+ readonly login: "/api/public/auth/login";
19
+ readonly refresh: "/api/public/auth/refresh";
20
+ readonly me: "/api/v1/auth/me";
21
+ readonly hosts: "/api/v1/hosts";
22
+ readonly bind: "/api/v1/hosts/bind";
23
+ readonly availability: "/api/v1/hosts/availability";
24
+ readonly signalingTicket: "/api/v1/relay/signaling/ticket";
25
+ readonly dshDevices: "/api/v1/dsh/devices";
26
+ readonly dshRelayTicket: "/api/v1/dsh/relay/ticket";
27
+ };
28
+ export declare class CodingNsControlApiError extends Error {
29
+ readonly status: number;
30
+ readonly errorCode: string | null;
31
+ constructor(message: string, status: number, errorCode?: string | null);
32
+ }
33
+ /**
34
+ * 控制面客户端边界。实现必须由调用方注入,阶段 2 不执行 fetch。
35
+ * accessToken 只作为调用参数存在,不进入凭据存储或公开快照。
36
+ */
37
+ export interface CodingNsControlApiClient {
38
+ login(request: LoginByEmailRequest): Promise<LoginByEmailResponse>;
39
+ refresh(request: RefreshTokenRequest): Promise<RefreshTokenResponse>;
40
+ getDevices(accessToken: string): Promise<AuthDeviceManagementSnapshotDto>;
41
+ listHostBindings(accessToken: string): Promise<HostBindingsResponse>;
42
+ bindHost(accessToken: string, request: HostBindRequest): Promise<HostBindResponse>;
43
+ unbindHost(accessToken: string, bindingId: string): Promise<HostUnbindResponse>;
44
+ checkHostLabelAvailability(accessToken: string, hostLabel: string): Promise<HostLabelAvailabilityResponse>;
45
+ createSignalingTicket(accessToken: string, request: RelaySignalingTicketRequest): Promise<RelaySignalingTicketResponse>;
46
+ registerDshDevice(accessToken: string, request: DshDeviceRegistrationRequest): Promise<DshDeviceRegistrationResponse>;
47
+ listDshDevices(accessToken: string): Promise<DshDeviceListResponse>;
48
+ heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string): Promise<DshDeviceHeartbeatResponse>;
49
+ createDshRelayTicket(accessToken: string, request: DshRelayTicketRequest): Promise<DshRelayTicketResponse>;
50
+ }
51
+ /** 设计文档中的简写名称;保留长名称以明确其 Control API 边界。 */
52
+ export type CodingNsControlClient = CodingNsControlApiClient;
53
+ export interface HttpCodingNsControlApiClientOptions {
54
+ controlBaseUrl: string;
55
+ /** 设备接口属于当前 Host API,默认与 Control API 使用同一基地址。 */
56
+ hostApiBaseUrl?: string;
57
+ fetcher?: typeof fetch;
58
+ }
59
+ /** 基于原生 fetch 的 Host 控制面客户端;不把 token 写入日志或快照。 */
60
+ export declare class HttpCodingNsControlApiClient implements CodingNsControlApiClient {
61
+ private readonly controlBaseUrl;
62
+ private readonly hostApiBaseUrl;
63
+ private readonly fetcher;
64
+ constructor(options: HttpCodingNsControlApiClientOptions);
65
+ login(request: LoginByEmailRequest): Promise<LoginByEmailResponse>;
66
+ refresh(request: RefreshTokenRequest): Promise<RefreshTokenResponse>;
67
+ /**
68
+ * codingns-proxy Connect 只提供账号和 Host 绑定接口,没有旧版的设备管理接口。
69
+ * 保留 DTO 方法是为了兼容插件 RPC;不能向不存在的 `/api/auth/devices` 发请求,
70
+ * 否则登录成功后的补充状态读取会被误报成登录失败。
71
+ */
72
+ getDevices(_accessToken: string): Promise<AuthDeviceManagementSnapshotDto>;
73
+ listHostBindings(accessToken: string): Promise<HostBindingsResponse>;
74
+ bindHost(accessToken: string, request: HostBindRequest): Promise<HostBindResponse>;
75
+ unbindHost(accessToken: string, bindingId: string): Promise<HostUnbindResponse>;
76
+ checkHostLabelAvailability(accessToken: string, hostLabel: string): Promise<HostLabelAvailabilityResponse>;
77
+ createSignalingTicket(accessToken: string, request: RelaySignalingTicketRequest): Promise<RelaySignalingTicketResponse>;
78
+ registerDshDevice(accessToken: string, request: DshDeviceRegistrationRequest): Promise<DshDeviceRegistrationResponse>;
79
+ listDshDevices(accessToken: string): Promise<DshDeviceListResponse>;
80
+ heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string): Promise<DshDeviceHeartbeatResponse>;
81
+ createDshRelayTicket(accessToken: string, request: DshRelayTicketRequest): Promise<DshRelayTicketResponse>;
82
+ private request;
83
+ }
84
+ //# sourceMappingURL=control-api-client.d.ts.map
@@ -0,0 +1,130 @@
1
+ /** codingns-proxy Control API 的真实路径,供后续 HTTP 实现复用。 */
2
+ export const CODINGNS_CONTROL_API_PATHS = {
3
+ login: '/api/public/auth/login',
4
+ refresh: '/api/public/auth/refresh',
5
+ me: '/api/v1/auth/me',
6
+ // 当前 codingns-proxy 没有独立的设备管理接口;设备绑定通过 hosts 返回。
7
+ hosts: '/api/v1/hosts',
8
+ bind: '/api/v1/hosts/bind',
9
+ availability: '/api/v1/hosts/availability',
10
+ signalingTicket: '/api/v1/relay/signaling/ticket',
11
+ dshDevices: '/api/v1/dsh/devices',
12
+ dshRelayTicket: '/api/v1/dsh/relay/ticket',
13
+ };
14
+ export class CodingNsControlApiError extends Error {
15
+ status;
16
+ errorCode;
17
+ constructor(message, status, errorCode = null) {
18
+ super(message);
19
+ this.name = 'CodingNsControlApiError';
20
+ this.status = status;
21
+ this.errorCode = errorCode;
22
+ }
23
+ }
24
+ /** 基于原生 fetch 的 Host 控制面客户端;不把 token 写入日志或快照。 */
25
+ export class HttpCodingNsControlApiClient {
26
+ controlBaseUrl;
27
+ hostApiBaseUrl;
28
+ fetcher;
29
+ constructor(options) {
30
+ this.controlBaseUrl = normalizeBaseUrl(options.controlBaseUrl);
31
+ this.hostApiBaseUrl = normalizeBaseUrl(options.hostApiBaseUrl ?? options.controlBaseUrl);
32
+ this.fetcher = options.fetcher ?? globalThis.fetch.bind(globalThis);
33
+ }
34
+ login(request) {
35
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.login, { method: 'POST', body: request });
36
+ }
37
+ refresh(request) {
38
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.refresh, { method: 'POST', body: request });
39
+ }
40
+ /**
41
+ * codingns-proxy Connect 只提供账号和 Host 绑定接口,没有旧版的设备管理接口。
42
+ * 保留 DTO 方法是为了兼容插件 RPC;不能向不存在的 `/api/auth/devices` 发请求,
43
+ * 否则登录成功后的补充状态读取会被误报成登录失败。
44
+ */
45
+ getDevices(_accessToken) {
46
+ return Promise.resolve({
47
+ currentDevice: null,
48
+ otherActiveDevices: [],
49
+ recentLoginRecords: [],
50
+ });
51
+ }
52
+ listHostBindings(accessToken) {
53
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.hosts, { token: accessToken });
54
+ }
55
+ bindHost(accessToken, request) {
56
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.bind, { method: 'POST', token: accessToken, body: request });
57
+ }
58
+ unbindHost(accessToken, bindingId) {
59
+ return this.request(this.controlBaseUrl, `/api/v1/hosts/${encodeURIComponent(bindingId)}`, { method: 'DELETE', token: accessToken });
60
+ }
61
+ checkHostLabelAvailability(accessToken, hostLabel) {
62
+ return this.request(this.controlBaseUrl, `${CODINGNS_CONTROL_API_PATHS.availability}?hostLabel=${encodeURIComponent(hostLabel)}`, { token: accessToken });
63
+ }
64
+ createSignalingTicket(accessToken, request) {
65
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.signalingTicket, {
66
+ method: 'POST',
67
+ token: accessToken,
68
+ body: request,
69
+ });
70
+ }
71
+ registerDshDevice(accessToken, request) {
72
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.dshDevices, { method: 'POST', token: accessToken, body: request });
73
+ }
74
+ listDshDevices(accessToken) {
75
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.dshDevices, { token: accessToken });
76
+ }
77
+ heartbeatDshDevice(accessToken, deviceId, deviceCredential) {
78
+ return this.request(this.controlBaseUrl, `${CODINGNS_CONTROL_API_PATHS.dshDevices}/${encodeURIComponent(deviceId)}/heartbeat`, {
79
+ method: 'POST',
80
+ token: accessToken,
81
+ headers: { 'x-dsh-device-credential': deviceCredential },
82
+ });
83
+ }
84
+ createDshRelayTicket(accessToken, request) {
85
+ return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.dshRelayTicket, {
86
+ method: 'POST',
87
+ token: accessToken,
88
+ body: request,
89
+ headers: { 'x-dsh-device-credential': request.deviceCredential },
90
+ });
91
+ }
92
+ async request(baseUrl, path, options = {}) {
93
+ const headers = new Headers({ accept: 'application/json' });
94
+ for (const [key, value] of Object.entries(options.headers ?? {}))
95
+ headers.set(key, value);
96
+ if (options.body !== undefined)
97
+ headers.set('content-type', 'application/json');
98
+ if (options.token)
99
+ headers.set('authorization', `Bearer ${options.token}`);
100
+ const requestInit = { method: options.method ?? 'GET', headers };
101
+ if (options.body !== undefined)
102
+ requestInit.body = JSON.stringify(options.body);
103
+ const response = await this.fetcher(`${baseUrl}${path}`, requestInit);
104
+ const raw = await response.text();
105
+ let data = null;
106
+ if (raw) {
107
+ try {
108
+ data = JSON.parse(raw);
109
+ }
110
+ catch {
111
+ data = null;
112
+ }
113
+ }
114
+ if (!response.ok) {
115
+ const error = isRecord(data) && typeof data.errorCode === 'string' ? data.errorCode : null;
116
+ throw new CodingNsControlApiError(`Control API 请求失败 (${response.status})`, response.status, error);
117
+ }
118
+ return data;
119
+ }
120
+ }
121
+ function normalizeBaseUrl(value) {
122
+ const url = new URL(value);
123
+ if (url.protocol !== 'https:' && url.protocol !== 'http:')
124
+ throw new TypeError('Control API 地址必须使用 HTTP(S)');
125
+ return url.toString().replace(/\/$/u, '');
126
+ }
127
+ function isRecord(value) {
128
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
129
+ }
130
+ //# sourceMappingURL=control-api-client.js.map
@@ -0,0 +1,54 @@
1
+ import type { DshDeviceCredentialRecord } from '../shared/contracts/dsh-device.js';
2
+ /** 仅 Host 内部使用的敏感凭据;不要从 Client entry 导入或序列化到客户端。 */
3
+ export interface HostCredentialRecord {
4
+ controlBaseUrl: string;
5
+ accountId: string;
6
+ refreshToken: string;
7
+ refreshTokenExpiresAt: string;
8
+ deviceId: string | null;
9
+ savedAt: string;
10
+ }
11
+ /** Host 凭据存储抽象;生产实现应接入 DSH/Codingns4DSH 的安全凭据存储。 */
12
+ export interface CodingNsCredentialStore {
13
+ read(): Promise<HostCredentialRecord | null>;
14
+ write(record: HostCredentialRecord): Promise<void>;
15
+ clear(): Promise<void>;
16
+ }
17
+ /**
18
+ * 测试用内存实现。
19
+ * 不提供持久化或加密语义,不能用于生产;用于阶段 2 状态机单元测试。
20
+ */
21
+ export declare class InMemoryCodingNsCredentialStore implements CodingNsCredentialStore {
22
+ private record;
23
+ read(): Promise<HostCredentialRecord | null>;
24
+ write(record: HostCredentialRecord): Promise<void>;
25
+ clear(): Promise<void>;
26
+ }
27
+ /** Host 侧 refresh token 的文件存储;文件权限限制为当前用户可读写。 */
28
+ export declare class FileCodingNsCredentialStore implements CodingNsCredentialStore {
29
+ private readonly filePath;
30
+ constructor(filePath: string);
31
+ read(): Promise<HostCredentialRecord | null>;
32
+ write(record: HostCredentialRecord): Promise<void>;
33
+ clear(): Promise<void>;
34
+ }
35
+ /** DSH device credential 独立存储,避免与 Codingns4DSH refresh token 混用。 */
36
+ export interface DshDeviceCredentialStore {
37
+ read(): Promise<DshDeviceCredentialRecord | null>;
38
+ write(record: DshDeviceCredentialRecord): Promise<void>;
39
+ clear(): Promise<void>;
40
+ }
41
+ export declare class InMemoryDshDeviceCredentialStore implements DshDeviceCredentialStore {
42
+ private record;
43
+ read(): Promise<DshDeviceCredentialRecord | null>;
44
+ write(record: DshDeviceCredentialRecord): Promise<void>;
45
+ clear(): Promise<void>;
46
+ }
47
+ export declare class FileDshDeviceCredentialStore implements DshDeviceCredentialStore {
48
+ private readonly filePath;
49
+ constructor(filePath: string);
50
+ read(): Promise<DshDeviceCredentialRecord | null>;
51
+ write(record: DshDeviceCredentialRecord): Promise<void>;
52
+ clear(): Promise<void>;
53
+ }
54
+ //# sourceMappingURL=credential-store.d.ts.map