@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,161 @@
1
+ import { ResourceScopeStaleError, } from '../../shared/contracts/peer-host.js';
2
+ export { ResourceScopeStaleError, } from '../../shared/contracts/peer-host.js';
3
+ /**
4
+ * 管理当前 Host/Workspace/PeerHost 资源作用域。
5
+ *
6
+ * 这是纯状态协调器:它不发请求、不创建连接,也不理解具体资源类型。
7
+ * 作用域切换会立即让旧 generation 失效,然后清理旧 disposer,最后保留新快照。
8
+ */
9
+ export class ResourceScopeManager {
10
+ activeScope = null;
11
+ nextGeneration = 0;
12
+ transitionTail = Promise.resolve();
13
+ constructor(initialScope) {
14
+ if (initialScope) {
15
+ this.activeScope = {
16
+ ref: Object.freeze({
17
+ ...validateScopeInput(initialScope),
18
+ scopeGeneration: 1,
19
+ }),
20
+ disposers: [],
21
+ };
22
+ this.nextGeneration = 1;
23
+ }
24
+ }
25
+ /** 返回当前快照;返回值不可用于修改管理器内部状态。 */
26
+ getCurrent() {
27
+ return this.activeScope?.ref ?? null;
28
+ }
29
+ /**
30
+ * 切换作用域。并发切换会按调用顺序串行化,避免旧 disposer 交叉执行。
31
+ * 相同作用域不会制造无意义的新 generation,但仍可附加 disposer。
32
+ */
33
+ switchTo(input, disposer) {
34
+ const validatedInput = validateScopeInput(input);
35
+ let result;
36
+ const operation = this.transitionTail.then(async () => {
37
+ const current = this.activeScope;
38
+ if (current && sameScope(current.ref, validatedInput)) {
39
+ if (disposer)
40
+ this.addDisposer(disposer);
41
+ result = current.ref;
42
+ return;
43
+ }
44
+ const previous = this.activeScope;
45
+ const next = Object.freeze({
46
+ ...validatedInput,
47
+ scopeGeneration: ++this.nextGeneration,
48
+ });
49
+ // 先撤销旧快照,旧异步回调从这一刻起就会被 isCurrent 拒绝。
50
+ // 清理完成后才提交新快照,避免新作用域与旧连接同时被观察到。
51
+ this.activeScope = null;
52
+ let disposeError;
53
+ try {
54
+ await disposeScope(previous);
55
+ }
56
+ catch (error) {
57
+ disposeError = error;
58
+ }
59
+ this.activeScope = { ref: next, disposers: [] };
60
+ if (disposer)
61
+ this.addDisposer(disposer);
62
+ result = next;
63
+ if (disposeError)
64
+ throw disposeError;
65
+ });
66
+ this.transitionTail = operation.then(() => undefined, () => undefined);
67
+ return operation.then(() => result);
68
+ }
69
+ /**
70
+ * 为当前作用域注册清理函数。传入旧快照会直接失败,防止资源归属错乱。
71
+ */
72
+ addDisposer(disposer) {
73
+ if (!this.activeScope)
74
+ throw new ResourceScopeStaleError('No active resource scope');
75
+ const entry = { dispose: disposer, active: true };
76
+ this.activeScope.disposers.push(entry);
77
+ return () => {
78
+ entry.active = false;
79
+ };
80
+ }
81
+ /**
82
+ * 按快照注册清理函数。异步初始化完成后应优先使用此方法,避免旧作用域
83
+ * 的初始化结果把 disposer 错挂到新作用域。
84
+ */
85
+ registerDisposer(scope, disposer) {
86
+ this.assertCurrent(scope);
87
+ return this.addDisposer(disposer);
88
+ }
89
+ /** 判断快照是否仍然代表当前作用域。 */
90
+ isCurrent(scope) {
91
+ return Boolean(scope && this.activeScope && sameRef(this.activeScope.ref, scope));
92
+ }
93
+ /** 旧请求回写前调用;作用域不匹配时抛出稳定错误。 */
94
+ assertCurrent(scope) {
95
+ if (!this.isCurrent(scope))
96
+ throw new ResourceScopeStaleError();
97
+ }
98
+ /** 只有当前作用域才能执行写入,避免旧请求污染新作用域。 */
99
+ commitIfCurrent(scope, write) {
100
+ this.assertCurrent(scope);
101
+ return write();
102
+ }
103
+ /** 清理当前作用域并使其失效。后续可重新 switchTo。 */
104
+ async clear() {
105
+ const operation = this.transitionTail.then(async () => {
106
+ const previous = this.activeScope;
107
+ this.activeScope = null;
108
+ await disposeScope(previous);
109
+ });
110
+ this.transitionTail = operation.then(() => undefined, () => undefined);
111
+ await operation;
112
+ }
113
+ }
114
+ function validateScopeInput(input) {
115
+ if (!input || !nonEmpty(input.hostId) || !nonEmpty(input.workspaceId)) {
116
+ throw new TypeError('Resource scope hostId and workspaceId must be non-empty');
117
+ }
118
+ if (input.targetHostId !== null && !nonEmpty(input.targetHostId)) {
119
+ throw new TypeError('Resource scope targetHostId must be null or non-empty');
120
+ }
121
+ return {
122
+ hostId: input.hostId,
123
+ workspaceId: input.workspaceId,
124
+ targetHostId: input.targetHostId,
125
+ };
126
+ }
127
+ function nonEmpty(value) {
128
+ return typeof value === 'string' && value.trim().length > 0;
129
+ }
130
+ function sameScope(ref, input) {
131
+ return ref.hostId === input.hostId
132
+ && ref.workspaceId === input.workspaceId
133
+ && ref.targetHostId === input.targetHostId;
134
+ }
135
+ function sameRef(left, right) {
136
+ return left.hostId === right.hostId
137
+ && left.workspaceId === right.workspaceId
138
+ && left.targetHostId === right.targetHostId
139
+ && left.scopeGeneration === right.scopeGeneration;
140
+ }
141
+ async function disposeScope(scope) {
142
+ if (!scope)
143
+ return;
144
+ const errors = [];
145
+ for (const entry of [...scope.disposers].reverse()) {
146
+ if (!entry.active)
147
+ continue;
148
+ entry.active = false;
149
+ try {
150
+ await entry.dispose();
151
+ }
152
+ catch (error) {
153
+ errors.push(error);
154
+ }
155
+ }
156
+ if (errors.length === 1)
157
+ throw errors[0];
158
+ if (errors.length > 1)
159
+ throw new AggregateError(errors, 'Failed to dispose resource scope');
160
+ }
161
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,42 @@
1
+ import type { AuthDeviceManagementSnapshotDto, CodingNsAuthLoginResult, CodingNsAuthSessionSnapshot, HostBindRequest, LoginByEmailRequest, TunnelBindingSummary } from '../shared/contracts/auth.js';
2
+ import type { CodingNsControlApiClient } from './control-api-client.js';
3
+ import type { RelaySignalingTicketResponse } from '../shared/contracts/signaling.js';
4
+ import type { CodingNsCredentialStore } from './credential-store.js';
5
+ /**
6
+ * Host 侧认证协调器。
7
+ * 只管理状态和依赖边界,不创建 HTTP、计时器或 WebRTC 资源。
8
+ */
9
+ export declare class CodingNsAuthSession {
10
+ private readonly client;
11
+ private readonly credentials;
12
+ private readonly controlBaseUrl;
13
+ private state;
14
+ private accessToken;
15
+ private credential;
16
+ constructor(client: CodingNsControlApiClient, credentials: CodingNsCredentialStore, controlBaseUrl: string);
17
+ snapshot(): CodingNsAuthSessionSnapshot;
18
+ /**
19
+ * 供 Host 侧 Control API/信令适配器临时取用 access token。
20
+ * 调用方不得把返回值写入快照、日志或发送给 Client。
21
+ */
22
+ getAccessToken(): string | null;
23
+ /** 仅供 Host 内部设备运行时调用,Client 不会拿到控制面客户端。 */
24
+ getControlClient(): CodingNsControlApiClient;
25
+ /** 使用保存的 refresh token 恢复会话;没有凭据时保持 logged_out。 */
26
+ restore(): Promise<CodingNsAuthSessionSnapshot>;
27
+ login(request: LoginByEmailRequest): Promise<CodingNsAuthLoginResult>;
28
+ refresh(): Promise<CodingNsAuthSessionSnapshot>;
29
+ logout(): Promise<void>;
30
+ getDevices(): Promise<AuthDeviceManagementSnapshotDto>;
31
+ listHostBindings(): Promise<TunnelBindingSummary[]>;
32
+ bindHost(request: HostBindRequest): Promise<TunnelBindingSummary>;
33
+ unbindHost(bindingId: string): Promise<TunnelBindingSummary>;
34
+ /** 为浏览器 Client 申请短期票据;access/refresh token 永远不离开 Host。 */
35
+ createClientSignalingTicket(tunnelDomain?: string): Promise<RelaySignalingTicketResponse>;
36
+ private saveResponse;
37
+ private refreshDeviceAndBinding;
38
+ private loginResult;
39
+ private requireAccessToken;
40
+ private reset;
41
+ }
42
+ //# sourceMappingURL=auth-session.d.ts.map
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Host 侧认证协调器。
3
+ * 只管理状态和依赖边界,不创建 HTTP、计时器或 WebRTC 资源。
4
+ */
5
+ export class CodingNsAuthSession {
6
+ client;
7
+ credentials;
8
+ controlBaseUrl;
9
+ state = {
10
+ status: 'logged_out',
11
+ account: null,
12
+ currentDevice: null,
13
+ binding: null,
14
+ expiresAt: null,
15
+ errorCode: null,
16
+ };
17
+ accessToken = null;
18
+ credential = null;
19
+ constructor(client, credentials, controlBaseUrl) {
20
+ this.client = client;
21
+ this.credentials = credentials;
22
+ this.controlBaseUrl = controlBaseUrl;
23
+ if (controlBaseUrl.trim() === '') {
24
+ throw new TypeError('controlBaseUrl 不能为空');
25
+ }
26
+ }
27
+ snapshot() {
28
+ return {
29
+ ...this.state,
30
+ account: this.state.account ? { ...this.state.account } : null,
31
+ currentDevice: this.state.currentDevice ? { ...this.state.currentDevice } : null,
32
+ binding: this.state.binding ? { ...this.state.binding } : null,
33
+ };
34
+ }
35
+ /**
36
+ * 供 Host 侧 Control API/信令适配器临时取用 access token。
37
+ * 调用方不得把返回值写入快照、日志或发送给 Client。
38
+ */
39
+ getAccessToken() {
40
+ return this.accessToken;
41
+ }
42
+ /** 仅供 Host 内部设备运行时调用,Client 不会拿到控制面客户端。 */
43
+ getControlClient() {
44
+ return this.client;
45
+ }
46
+ /** 使用保存的 refresh token 恢复会话;没有凭据时保持 logged_out。 */
47
+ async restore() {
48
+ const credential = await this.credentials.read();
49
+ if (!credential) {
50
+ this.reset('logged_out');
51
+ return this.snapshot();
52
+ }
53
+ this.credential = credential;
54
+ return this.refresh();
55
+ }
56
+ async login(request) {
57
+ this.state = { ...this.state, status: 'logging_in', errorCode: null };
58
+ try {
59
+ const response = await this.client.login(request);
60
+ await this.saveResponse(response);
61
+ await this.refreshDeviceAndBinding();
62
+ this.state = { ...this.state, status: 'authenticated', errorCode: null };
63
+ return this.loginResult();
64
+ }
65
+ catch (error) {
66
+ this.state = { ...this.state, status: 'failed', errorCode: errorCode(error) };
67
+ throw error;
68
+ }
69
+ }
70
+ async refresh() {
71
+ const credential = this.credential ?? await this.credentials.read();
72
+ if (!credential) {
73
+ this.reset('logged_out');
74
+ return this.snapshot();
75
+ }
76
+ this.state = { ...this.state, status: 'refreshing', errorCode: null };
77
+ try {
78
+ const response = await this.client.refresh({ refreshToken: credential.refreshToken });
79
+ await this.saveResponse(response);
80
+ await this.refreshDeviceAndBinding();
81
+ this.state = { ...this.state, status: 'authenticated', errorCode: null };
82
+ return this.snapshot();
83
+ }
84
+ catch (error) {
85
+ this.accessToken = null;
86
+ this.state = { ...this.state, status: 'revoked', errorCode: errorCode(error) };
87
+ throw error;
88
+ }
89
+ }
90
+ async logout() {
91
+ this.accessToken = null;
92
+ this.credential = null;
93
+ await this.credentials.clear();
94
+ this.reset('logged_out');
95
+ }
96
+ async getDevices() {
97
+ const token = this.requireAccessToken();
98
+ const devices = await this.client.getDevices(token);
99
+ this.state = { ...this.state, currentDevice: devices.currentDevice };
100
+ return devices;
101
+ }
102
+ async listHostBindings() {
103
+ const response = await this.client.listHostBindings(this.requireAccessToken());
104
+ const binding = response.bindings[0] ?? null;
105
+ this.state = { ...this.state, binding };
106
+ return response.bindings;
107
+ }
108
+ async bindHost(request) {
109
+ const response = await this.client.bindHost(this.requireAccessToken(), request);
110
+ this.state = { ...this.state, binding: response.binding };
111
+ return response.binding;
112
+ }
113
+ async unbindHost(bindingId) {
114
+ const response = await this.client.unbindHost(this.requireAccessToken(), bindingId);
115
+ if (this.state.binding?.bindingId === response.binding.bindingId) {
116
+ this.state = { ...this.state, binding: null };
117
+ }
118
+ return response.binding;
119
+ }
120
+ /** 为浏览器 Client 申请短期票据;access/refresh token 永远不离开 Host。 */
121
+ async createClientSignalingTicket(tunnelDomain) {
122
+ const domain = tunnelDomain?.trim() || this.state.binding?.tunnelDomain;
123
+ if (!domain)
124
+ throw new Error('Codingns4DSH 尚未绑定 Host');
125
+ return this.client.createSignalingTicket(this.requireAccessToken(), { tunnelDomain: domain });
126
+ }
127
+ async saveResponse(response) {
128
+ this.accessToken = response.accessToken;
129
+ this.credential = {
130
+ controlBaseUrl: this.controlBaseUrl,
131
+ accountId: response.account?.accountId ?? '',
132
+ refreshToken: response.refreshToken,
133
+ refreshTokenExpiresAt: response.refreshTokenExpiresAt,
134
+ deviceId: this.state.currentDevice?.deviceId ?? null,
135
+ savedAt: new Date().toISOString(),
136
+ };
137
+ await this.credentials.write(this.credential);
138
+ this.state = {
139
+ ...this.state,
140
+ account: response.account,
141
+ expiresAt: response.expiresAt,
142
+ };
143
+ }
144
+ async refreshDeviceAndBinding() {
145
+ const devices = await this.client.getDevices(this.requireAccessToken());
146
+ const bindings = await this.client.listHostBindings(this.requireAccessToken());
147
+ this.state = {
148
+ ...this.state,
149
+ currentDevice: devices.currentDevice,
150
+ binding: bindings.bindings[0] ?? null,
151
+ };
152
+ }
153
+ loginResult() {
154
+ if (!this.state.account)
155
+ throw new Error('认证响应缺少 account');
156
+ return {
157
+ account: this.state.account,
158
+ expiresAt: this.state.expiresAt ?? '',
159
+ currentDevice: this.state.currentDevice,
160
+ binding: this.state.binding,
161
+ };
162
+ }
163
+ requireAccessToken() {
164
+ if (!this.accessToken)
165
+ throw new Error('Codingns4DSH 会话未认证');
166
+ return this.accessToken;
167
+ }
168
+ reset(status) {
169
+ this.accessToken = null;
170
+ this.credential = null;
171
+ this.state = {
172
+ status,
173
+ account: null,
174
+ currentDevice: null,
175
+ binding: null,
176
+ expiresAt: null,
177
+ errorCode: null,
178
+ };
179
+ }
180
+ }
181
+ function errorCode(error) {
182
+ if (error instanceof Error && error.name)
183
+ return error.name;
184
+ return 'AUTH_REQUEST_FAILED';
185
+ }
186
+ //# sourceMappingURL=auth-session.js.map
@@ -0,0 +1,14 @@
1
+ import type { CodingNsAgentEvent, CodingNsCliTurnInput } from '../../shared/contracts/cli-adapter.js';
2
+ import type { CodingNsCliSessionProbeInput, CodingNsCliSessionProbeResult } from './driver.js';
3
+ import { StandardStreamDriver, type StandardStreamDriverOptions } from './standard-stream-driver.js';
4
+ export declare class ClaudeCodeDriver extends StandardStreamDriver {
5
+ private readonly sessionRoots;
6
+ constructor(options?: StandardStreamDriverOptions);
7
+ listModels(): Promise<import("../../shared/contracts/cli-adapter.js").CodingNsCliModelCatalog>;
8
+ probeSession(input: CodingNsCliSessionProbeInput): Promise<CodingNsCliSessionProbeResult>;
9
+ protected buildArgs(input: CodingNsCliTurnInput): readonly string[];
10
+ protected parseEvent(value: Record<string, unknown>, input: CodingNsCliTurnInput): readonly CodingNsAgentEvent[];
11
+ }
12
+ /** 简短别名,便于按适配器名称装配。 */
13
+ export { ClaudeCodeDriver as ClaudeDriver };
14
+ //# sourceMappingURL=claude-driver.d.ts.map
@@ -0,0 +1,103 @@
1
+ import { homedir } from 'node:os';
2
+ import { basename, join } from 'node:path';
3
+ import { StandardStreamDriver, emptyCatalog } from './standard-stream-driver.js';
4
+ import { CLAUDE_CATALOG, enrichEfforts, isProviderDefaultModel } from './model-catalog.js';
5
+ import { probeStoredSession, readFirstJsonRecord } from './session-probe.js';
6
+ import { firstToolText, isToolRecord, serializeToolValue } from './tool-observation.js';
7
+ export class ClaudeCodeDriver extends StandardStreamDriver {
8
+ sessionRoots;
9
+ constructor(options = {}) {
10
+ super({ id: 'claude-code', name: 'Claude Code', protocol: 'stream-json', capabilities: ['models', 'stream', 'resume', 'interrupt', 'tool-events', 'reasoning', 'usage'] }, { binaries: ['claude'] }, options);
11
+ this.sessionRoots = options.sessionRoots ?? [join(process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), '.claude'), 'projects')];
12
+ }
13
+ async listModels() {
14
+ if (!(await this.detect()).installed)
15
+ return emptyCatalog();
16
+ const catalog = await super.listModels();
17
+ return catalog.groups.length > 0 ? enrichEfforts(catalog, CLAUDE_CATALOG) : CLAUDE_CATALOG;
18
+ }
19
+ async probeSession(input) {
20
+ return probeStoredSession(input, {
21
+ roots: this.sessionRoots,
22
+ matches: (path, entry, id) => entry.isFile() && basename(path) === `${id}.jsonl`,
23
+ validate: async (path, id) => (await readFirstJsonRecord(path))?.sessionId === id,
24
+ });
25
+ }
26
+ buildArgs(input) {
27
+ const args = ['-p', input.prompt, '--output-format', 'stream-json', '--verbose', '--permission-mode', 'bypassPermissions'];
28
+ if (input.providerSessionId)
29
+ args.push('--resume', input.providerSessionId);
30
+ if (input.modelId && !isProviderDefaultModel(input.modelId))
31
+ args.push('--model', input.modelId);
32
+ return args;
33
+ }
34
+ parseEvent(value, input) {
35
+ const event = value.type === 'stream_event' && typeof value.event === 'object' && value.event !== null ? value.event : value;
36
+ const delta = typeof event.delta === 'object' && event.delta !== null ? event.delta : null;
37
+ if (event.type === 'content_block_delta' && delta?.type === 'text_delta' && typeof delta.text === 'string')
38
+ return [{ type: 'text-delta', text: delta.text }];
39
+ if (event.type === 'content_block_start' && isToolRecord(event.content_block) && event.content_block.type === 'tool_use') {
40
+ const tool = claudeToolUse(event.content_block);
41
+ return tool === null ? [] : [tool];
42
+ }
43
+ if ((value.type === 'assistant' || value.type === 'user') && typeof value.message === 'object' && value.message !== null) {
44
+ const message = value.message;
45
+ const content = Array.isArray(message.content) ? message.content : [];
46
+ return content.flatMap((part) => {
47
+ if (!part || typeof part !== 'object')
48
+ return [];
49
+ const item = part;
50
+ if (item.type === 'tool_use') {
51
+ const tool = claudeToolUse(item);
52
+ return tool === null ? [] : [tool];
53
+ }
54
+ if (item.type === 'tool_result') {
55
+ const tool = claudeToolResult(item);
56
+ return tool === null ? [] : [tool];
57
+ }
58
+ return typeof item.text === 'string' ? [{ type: 'text-delta', text: item.text }] : [];
59
+ });
60
+ }
61
+ return super.parseEvent(value, input);
62
+ }
63
+ }
64
+ function claudeToolUse(item) {
65
+ const toolName = firstToolText(item.name, item.toolName);
66
+ if (toolName === undefined)
67
+ return null;
68
+ const callId = firstToolText(item.id, item.tool_use_id, item.toolUseId);
69
+ const input = serializeToolValue(item.input ?? item.arguments);
70
+ const agentId = firstToolText(item.agentId, item.agent_id);
71
+ const detail = serializeToolValue(item.detail);
72
+ return {
73
+ type: 'tool-event',
74
+ toolName,
75
+ status: 'running',
76
+ ...(callId ? { callId } : {}),
77
+ ...(input !== undefined ? { input } : {}),
78
+ ...(agentId ? { agentId } : {}),
79
+ ...(detail !== undefined ? { detail } : {}),
80
+ };
81
+ }
82
+ function claudeToolResult(item) {
83
+ const callId = firstToolText(item.tool_use_id, item.toolUseId, item.callId);
84
+ if (callId === undefined)
85
+ return null;
86
+ const failed = item.is_error === true || item.isError === true;
87
+ const content = serializeToolValue(item.content ?? item.output ?? item.result);
88
+ const agentId = firstToolText(item.agentId, item.agent_id);
89
+ const detail = serializeToolValue(item.detail);
90
+ return {
91
+ type: 'tool-event',
92
+ toolName: firstToolText(item.name, item.toolName) ?? 'tool',
93
+ callId,
94
+ status: failed ? 'failed' : 'completed',
95
+ ...(failed ? (content === undefined ? {} : { error: content }) : (content === undefined ? {} : { output: content })),
96
+ ...(!failed && content !== undefined ? { outputMode: 'snapshot' } : {}),
97
+ ...(agentId ? { agentId } : {}),
98
+ ...(detail !== undefined ? { detail } : {}),
99
+ };
100
+ }
101
+ /** 简短别名,便于按适配器名称装配。 */
102
+ export { ClaudeCodeDriver as ClaudeDriver };
103
+ //# sourceMappingURL=claude-driver.js.map
@@ -0,0 +1,45 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import type { CodingNsAgentEvent, CodingNsAgentQuestionResponse, CodingNsCliModelCatalog, CodingNsAgentPermissionResponse, CodingNsCliTurnInput } from '../../shared/contracts/cli-adapter.js';
3
+ import type { CodingNsCliDriver, CodingNsCliSessionProbeInput, CodingNsCliSessionProbeResult } from './driver.js';
4
+ export interface CodexAppServerDriverOptions {
5
+ readonly binaries?: readonly string[];
6
+ readonly sessionRoots?: readonly string[];
7
+ readonly spawnSync?: typeof spawnSync;
8
+ readonly spawn?: typeof spawn;
9
+ }
10
+ /** Codex app-server 的 JSON-RPC 驱动,Host 只暴露统一文本流,不暴露线程和 token。 */
11
+ export declare class CodexAppServerDriver implements CodingNsCliDriver {
12
+ readonly descriptor: {
13
+ readonly id: "codex";
14
+ readonly name: "Codex";
15
+ readonly protocol: "json-rpc";
16
+ readonly capabilities: readonly ["models", "stream", "resume", "interrupt", "tool-events", "reasoning", "usage", "permission", "questions", "steer"];
17
+ };
18
+ private readonly binaries;
19
+ private readonly runSpawnSync;
20
+ private readonly runSpawn;
21
+ private readonly sessionRoots;
22
+ private cachedBinary;
23
+ private readonly processes;
24
+ private readonly sessions;
25
+ constructor(options?: CodexAppServerDriverOptions);
26
+ detect(): Promise<{
27
+ installed: boolean;
28
+ version: string | null;
29
+ command: string | null;
30
+ }>;
31
+ listModels(): Promise<CodingNsCliModelCatalog>;
32
+ probeSession(input: CodingNsCliSessionProbeInput): Promise<CodingNsCliSessionProbeResult>;
33
+ executeTurn(input: CodingNsCliTurnInput): AsyncIterable<CodingNsAgentEvent>;
34
+ /** 将新输入 steer 到当前 Codex turn。 */
35
+ steer(sessionId: string, prompt: string): Promise<void>;
36
+ /** 中断当前 Codex turn,但保留 app-server 线程。 */
37
+ interrupt(sessionId: string): Promise<void>;
38
+ /** 回传原生权限请求;审批值只在 Host 进程中流转。 */
39
+ respondPermission(sessionId: string, response: CodingNsAgentPermissionResponse): void;
40
+ /** 回传 requestUserInput 的结构化回答。 */
41
+ respondQuestion(sessionId: string, response: CodingNsAgentQuestionResponse): void;
42
+ dispose(): void;
43
+ private getSession;
44
+ }
45
+ //# sourceMappingURL=codex-driver.d.ts.map