@jingyi0605/codingns4dsh 0.2.1-beta.4 → 0.2.1-beta.5

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 (248) hide show
  1. package/README.en.md +30 -6
  2. package/README.md +29 -5
  3. package/data/build/dist/client/account-bar.d.ts +1 -1
  4. package/data/build/dist/client/account-bar.d.ts.map +1 -1
  5. package/data/build/dist/client/account-bar.js +22 -14
  6. package/data/build/dist/client/account-bar.js.map +1 -1
  7. package/data/build/dist/client/adapter-catalog-watch.d.ts +8 -0
  8. package/data/build/dist/client/adapter-catalog-watch.d.ts.map +1 -0
  9. package/data/build/dist/client/adapter-catalog-watch.js +79 -0
  10. package/data/build/dist/client/adapter-catalog-watch.js.map +1 -0
  11. package/data/build/dist/client/avatar/live2d.d.ts +2 -0
  12. package/data/build/dist/client/avatar/live2d.d.ts.map +1 -1
  13. package/data/build/dist/client/avatar/live2d.js +16 -6
  14. package/data/build/dist/client/avatar/live2d.js.map +1 -1
  15. package/data/build/dist/client/avatar/manager.d.ts.map +1 -1
  16. package/data/build/dist/client/avatar/manager.js +4 -2
  17. package/data/build/dist/client/avatar/manager.js.map +1 -1
  18. package/data/build/dist/client/bundle.js +831 -403
  19. package/data/build/dist/client/bundle.js.map +1 -1
  20. package/data/build/dist/client/cli-catalog.d.ts +3 -0
  21. package/data/build/dist/client/cli-catalog.d.ts.map +1 -1
  22. package/data/build/dist/client/cli-catalog.js +7 -0
  23. package/data/build/dist/client/cli-catalog.js.map +1 -1
  24. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  25. package/data/build/dist/client/cli-slots.js +5 -43
  26. package/data/build/dist/client/cli-slots.js.map +1 -1
  27. package/data/build/dist/client/debug/ui.d.ts.map +1 -1
  28. package/data/build/dist/client/debug/ui.js +14 -5
  29. package/data/build/dist/client/debug/ui.js.map +1 -1
  30. package/data/build/dist/client/desktop-assistant.js +19 -5
  31. package/data/build/dist/client/features/cli-adapters.d.ts.map +1 -1
  32. package/data/build/dist/client/features/cli-adapters.js +48 -13
  33. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  34. package/data/build/dist/client/features/global-voice-assistant.d.ts.map +1 -1
  35. package/data/build/dist/client/features/global-voice-assistant.js +12 -7
  36. package/data/build/dist/client/features/global-voice-assistant.js.map +1 -1
  37. package/data/build/dist/client/features/peer-host.d.ts +2 -1
  38. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  39. package/data/build/dist/client/features/peer-host.js +110 -33
  40. package/data/build/dist/client/features/peer-host.js.map +1 -1
  41. package/data/build/dist/client/features/workspace-session-enhancement.d.ts.map +1 -1
  42. package/data/build/dist/client/features/workspace-session-enhancement.js +37 -10
  43. package/data/build/dist/client/features/workspace-session-enhancement.js.map +1 -1
  44. package/data/build/dist/client/git-management.d.ts +1 -1
  45. package/data/build/dist/client/git-management.d.ts.map +1 -1
  46. package/data/build/dist/client/git-management.js +46 -27
  47. package/data/build/dist/client/git-management.js.map +1 -1
  48. package/data/build/dist/client/locale.d.ts.map +1 -1
  49. package/data/build/dist/client/locale.js +10 -0
  50. package/data/build/dist/client/locale.js.map +1 -1
  51. package/data/build/dist/client/locales/peerHost.d.ts.map +1 -1
  52. package/data/build/dist/client/locales/peerHost.js +4 -0
  53. package/data/build/dist/client/locales/peerHost.js.map +1 -1
  54. package/data/build/dist/client/locales/peerHostWorkspace.js +2 -2
  55. package/data/build/dist/client/locales/peerHostWorkspace.js.map +1 -1
  56. package/data/build/dist/client/locales/usage.d.ts.map +1 -1
  57. package/data/build/dist/client/locales/usage.js +4 -0
  58. package/data/build/dist/client/locales/usage.js.map +1 -1
  59. package/data/build/dist/client/model-catalog-cache.d.ts.map +1 -1
  60. package/data/build/dist/client/model-catalog-cache.js +9 -2
  61. package/data/build/dist/client/model-catalog-cache.js.map +1 -1
  62. package/data/build/dist/client/rpc-call.d.ts +4 -0
  63. package/data/build/dist/client/rpc-call.d.ts.map +1 -0
  64. package/data/build/dist/client/rpc-call.js +23 -0
  65. package/data/build/dist/client/rpc-call.js.map +1 -0
  66. package/data/build/dist/client/serial-polling.d.ts +13 -0
  67. package/data/build/dist/client/serial-polling.d.ts.map +1 -0
  68. package/data/build/dist/client/serial-polling.js +41 -0
  69. package/data/build/dist/client/serial-polling.js.map +1 -0
  70. package/data/build/dist/client/session-adapter-cache.d.ts.map +1 -1
  71. package/data/build/dist/client/session-adapter-cache.js +11 -1
  72. package/data/build/dist/client/session-adapter-cache.js.map +1 -1
  73. package/data/build/dist/client/sherpa-voice-adapter.d.ts.map +1 -1
  74. package/data/build/dist/client/sherpa-voice-adapter.js +8 -8
  75. package/data/build/dist/client/sherpa-voice-adapter.js.map +1 -1
  76. package/data/build/dist/client/subscription-slot.d.ts +11 -0
  77. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  78. package/data/build/dist/client/subscription-slot.js +42 -15
  79. package/data/build/dist/client/subscription-slot.js.map +1 -1
  80. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +1 -1
  81. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
  82. package/data/build/dist/host/cli-adapters/acp-cli-driver.js +3 -10
  83. package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
  84. package/data/build/dist/host/cli-adapters/antigravity-subscription.d.ts.map +1 -1
  85. package/data/build/dist/host/cli-adapters/antigravity-subscription.js +10 -10
  86. package/data/build/dist/host/cli-adapters/antigravity-subscription.js.map +1 -1
  87. package/data/build/dist/host/cli-adapters/claude-driver.d.ts.map +1 -1
  88. package/data/build/dist/host/cli-adapters/claude-driver.js +7 -5
  89. package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
  90. package/data/build/dist/host/cli-adapters/codebuddy-driver.d.ts.map +1 -1
  91. package/data/build/dist/host/cli-adapters/codebuddy-driver.js +8 -7
  92. package/data/build/dist/host/cli-adapters/codebuddy-driver.js.map +1 -1
  93. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  94. package/data/build/dist/host/cli-adapters/command-code-driver.js +9 -8
  95. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  96. package/data/build/dist/host/cli-adapters/cursor-driver.d.ts.map +1 -1
  97. package/data/build/dist/host/cli-adapters/cursor-driver.js +4 -3
  98. package/data/build/dist/host/cli-adapters/cursor-driver.js.map +1 -1
  99. package/data/build/dist/host/cli-adapters/delegate-dispatch.js +1 -1
  100. package/data/build/dist/host/cli-adapters/delegate-dispatch.js.map +1 -1
  101. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.d.ts +2 -0
  102. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.d.ts.map +1 -1
  103. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js +5 -0
  104. package/data/build/dist/host/cli-adapters/delegation-mention-rewrite.js.map +1 -1
  105. package/data/build/dist/host/cli-adapters/desktop-app-runtime.d.ts.map +1 -1
  106. package/data/build/dist/host/cli-adapters/desktop-app-runtime.js +2 -4
  107. package/data/build/dist/host/cli-adapters/desktop-app-runtime.js.map +1 -1
  108. package/data/build/dist/host/cli-adapters/driver.d.ts +1 -1
  109. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  110. package/data/build/dist/host/cli-adapters/feature.js +28 -36
  111. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  112. package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
  113. package/data/build/dist/host/cli-adapters/grok-driver.js +2 -1
  114. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  115. package/data/build/dist/host/cli-adapters/kimi-driver.d.ts.map +1 -1
  116. package/data/build/dist/host/cli-adapters/kimi-driver.js +4 -3
  117. package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
  118. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +2 -0
  119. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts.map +1 -1
  120. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +10 -0
  121. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js.map +1 -1
  122. package/data/build/dist/host/cli-adapters/log-files.d.ts +3 -0
  123. package/data/build/dist/host/cli-adapters/log-files.d.ts.map +1 -0
  124. package/data/build/dist/host/cli-adapters/log-files.js +32 -0
  125. package/data/build/dist/host/cli-adapters/log-files.js.map +1 -0
  126. package/data/build/dist/host/cli-adapters/native-team-subagent.js +1 -1
  127. package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -1
  128. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +10 -0
  129. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts.map +1 -1
  130. package/data/build/dist/host/cli-adapters/opencode-driver.js +128 -26
  131. package/data/build/dist/host/cli-adapters/opencode-driver.js.map +1 -1
  132. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.d.ts +29 -0
  133. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.d.ts.map +1 -0
  134. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js +471 -0
  135. package/data/build/dist/host/cli-adapters/opencode-v2-protocol.js.map +1 -0
  136. package/data/build/dist/host/cli-adapters/pi-driver.d.ts.map +1 -1
  137. package/data/build/dist/host/cli-adapters/pi-driver.js +2 -1
  138. package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
  139. package/data/build/dist/host/cli-adapters/process-utils.d.ts +8 -2
  140. package/data/build/dist/host/cli-adapters/process-utils.d.ts.map +1 -1
  141. package/data/build/dist/host/cli-adapters/process-utils.js +90 -9
  142. package/data/build/dist/host/cli-adapters/process-utils.js.map +1 -1
  143. package/data/build/dist/host/cli-adapters/qoder-driver.d.ts.map +1 -1
  144. package/data/build/dist/host/cli-adapters/qoder-driver.js +55 -72
  145. package/data/build/dist/host/cli-adapters/qoder-driver.js.map +1 -1
  146. package/data/build/dist/host/cli-adapters/qoder-subscription.d.ts +6 -1
  147. package/data/build/dist/host/cli-adapters/qoder-subscription.d.ts.map +1 -1
  148. package/data/build/dist/host/cli-adapters/qoder-subscription.js +37 -10
  149. package/data/build/dist/host/cli-adapters/qoder-subscription.js.map +1 -1
  150. package/data/build/dist/host/cli-adapters/registry.d.ts +13 -21
  151. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  152. package/data/build/dist/host/cli-adapters/registry.js +71 -127
  153. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  154. package/data/build/dist/host/cli-adapters/rpc-driver-utils.d.ts +1 -0
  155. package/data/build/dist/host/cli-adapters/rpc-driver-utils.d.ts.map +1 -1
  156. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +6 -6
  157. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js.map +1 -1
  158. package/data/build/dist/host/cli-adapters/session-store.d.ts +5 -1
  159. package/data/build/dist/host/cli-adapters/session-store.d.ts.map +1 -1
  160. package/data/build/dist/host/cli-adapters/session-store.js +68 -11
  161. package/data/build/dist/host/cli-adapters/session-store.js.map +1 -1
  162. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts.map +1 -1
  163. package/data/build/dist/host/cli-adapters/standard-stream-driver.js +4 -3
  164. package/data/build/dist/host/cli-adapters/standard-stream-driver.js.map +1 -1
  165. package/data/build/dist/host/cli-bridge/dispatch.js +1 -1
  166. package/data/build/dist/host/cli-bridge/dispatch.js.map +1 -1
  167. package/data/build/dist/host/debug.d.ts.map +1 -1
  168. package/data/build/dist/host/debug.js +5 -4
  169. package/data/build/dist/host/debug.js.map +1 -1
  170. package/data/build/dist/host/dsh-runtime-version.d.ts +1 -1
  171. package/data/build/dist/host/dsh-runtime-version.d.ts.map +1 -1
  172. package/data/build/dist/host/dsh-runtime-version.js +22 -17
  173. package/data/build/dist/host/dsh-runtime-version.js.map +1 -1
  174. package/data/build/dist/host/features/assistant-avatar-runtime.d.ts.map +1 -1
  175. package/data/build/dist/host/features/assistant-avatar-runtime.js +20 -5
  176. package/data/build/dist/host/features/assistant-avatar-runtime.js.map +1 -1
  177. package/data/build/dist/host/features/assistant-source-cache.d.ts +12 -0
  178. package/data/build/dist/host/features/assistant-source-cache.d.ts.map +1 -0
  179. package/data/build/dist/host/features/assistant-source-cache.js +56 -0
  180. package/data/build/dist/host/features/assistant-source-cache.js.map +1 -0
  181. package/data/build/dist/host/features/global-voice-coordinator.d.ts.map +1 -1
  182. package/data/build/dist/host/features/global-voice-coordinator.js +15 -10
  183. package/data/build/dist/host/features/global-voice-coordinator.js.map +1 -1
  184. package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
  185. package/data/build/dist/host/features/global-voice-rpc.js +28 -13
  186. package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
  187. package/data/build/dist/host/features/sherpa-voice-worker.d.ts +18 -0
  188. package/data/build/dist/host/features/sherpa-voice-worker.d.ts.map +1 -0
  189. package/data/build/dist/host/features/sherpa-voice-worker.js +40 -0
  190. package/data/build/dist/host/features/sherpa-voice-worker.js.map +1 -0
  191. package/data/build/dist/host/features/sherpa-worker-runtime.d.ts +41 -0
  192. package/data/build/dist/host/features/sherpa-worker-runtime.d.ts.map +1 -0
  193. package/data/build/dist/host/features/sherpa-worker-runtime.js +200 -0
  194. package/data/build/dist/host/features/sherpa-worker-runtime.js.map +1 -0
  195. package/data/build/dist/host/index.d.ts +1 -1
  196. package/data/build/dist/host/index.d.ts.map +1 -1
  197. package/data/build/dist/host/index.js +2 -2
  198. package/data/build/dist/host/index.js.map +1 -1
  199. package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
  200. package/data/build/dist/host/lan-access-dsh.js +5 -22
  201. package/data/build/dist/host/lan-access-dsh.js.map +1 -1
  202. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.d.ts +6 -46
  203. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.d.ts.map +1 -1
  204. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.js +48 -28
  205. package/data/build/dist/host/modules/peer-host/host-api-proxy-service.js.map +1 -1
  206. package/data/build/dist/host/modules/peer-host/peer-host-diagnostics.d.ts.map +1 -1
  207. package/data/build/dist/host/modules/peer-host/peer-host-diagnostics.js +1 -0
  208. package/data/build/dist/host/modules/peer-host/peer-host-diagnostics.js.map +1 -1
  209. package/data/build/dist/host/modules/peer-host/peer-host-handshake.d.ts.map +1 -1
  210. package/data/build/dist/host/modules/peer-host/peer-host-handshake.js +4 -1
  211. package/data/build/dist/host/modules/peer-host/peer-host-handshake.js.map +1 -1
  212. package/data/build/dist/host/modules/peer-host/peer-host-session.d.ts +7 -1
  213. package/data/build/dist/host/modules/peer-host/peer-host-session.d.ts.map +1 -1
  214. package/data/build/dist/host/modules/peer-host/peer-host-session.js +40 -13
  215. package/data/build/dist/host/modules/peer-host/peer-host-session.js.map +1 -1
  216. package/data/build/dist/host/rpc.js +1 -1
  217. package/data/build/dist/host/rpc.js.map +1 -1
  218. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -1
  219. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts.map +1 -1
  220. package/data/build/dist/host/terminal/backends/tmux-backend.js +15 -14
  221. package/data/build/dist/host/terminal/backends/tmux-backend.js.map +1 -1
  222. package/data/build/dist/shared/assistant-avatar-engine.d.ts +3 -0
  223. package/data/build/dist/shared/assistant-avatar-engine.d.ts.map +1 -1
  224. package/data/build/dist/shared/assistant-avatar-engine.js +4 -0
  225. package/data/build/dist/shared/assistant-avatar-engine.js.map +1 -1
  226. package/data/build/dist/shared/contracts/cli-adapter.d.ts +3 -0
  227. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  228. package/data/build/dist/shared/contracts/errors.d.ts +1 -0
  229. package/data/build/dist/shared/contracts/errors.d.ts.map +1 -1
  230. package/data/build/dist/shared/contracts/errors.js +1 -0
  231. package/data/build/dist/shared/contracts/errors.js.map +1 -1
  232. package/data/build/dist/shared/contracts/peer-host.d.ts +1 -0
  233. package/data/build/dist/shared/contracts/peer-host.d.ts.map +1 -1
  234. package/data/build/dist/shared/contracts/peer-host.js +1 -0
  235. package/data/build/dist/shared/contracts/peer-host.js.map +1 -1
  236. package/data/build/dist/shared/contracts/version.d.ts +3 -1
  237. package/data/build/dist/shared/contracts/version.d.ts.map +1 -1
  238. package/data/build/dist/shared/contracts/version.js +20 -7
  239. package/data/build/dist/shared/contracts/version.js.map +1 -1
  240. package/data/build/dist/shared/peer-host-http-routes.d.ts +62 -0
  241. package/data/build/dist/shared/peer-host-http-routes.d.ts.map +1 -0
  242. package/data/build/dist/shared/peer-host-http-routes.js +31 -0
  243. package/data/build/dist/shared/peer-host-http-routes.js.map +1 -0
  244. package/package.json +1 -1
  245. package/profile/README.md +2 -2
  246. package/profile/package.json +2 -2
  247. package/profile/version.json +1 -1
  248. package/version.json +1 -1
@@ -1367,6 +1367,8 @@ window.__ModuleLoader__.load({
1367
1367
  "peerHost.statusUnreachable": "Unreachable",
1368
1368
  "peerHost.statusReconnecting": "Reconnecting",
1369
1369
  "peerHost.statusDisabled": "Disabled",
1370
+ "peerHost.debugWorkspaceUnavailable": "The remote debug workspace scope is unavailable. Please wait for PeerHost workspaces to refresh.",
1371
+ "peerHost.gitWorkspaceUnavailable": "The remote Git workspace is temporarily unavailable. Please wait for PeerHost workspaces to refresh.",
1370
1372
  "peerHost.stateExternal": "The Transport structure of this page is not supported, so the plugin cannot wrap it and PeerHost aggregation is disabled; refreshing the page will not change the result.",
1371
1373
  "peerHost.stateNotInstalledDesktop": "The preboot shim is not installed in this Desktop page; restart DSH Desktop and reopen the page.",
1372
1374
  "peerHost.stateNotInstalledWeb": "The preboot shim is not installed in this page; refresh DSH Web and then enable PeerHost.",
@@ -1440,6 +1442,8 @@ window.__ModuleLoader__.load({
1440
1442
  "peerHost.statusUnreachable": "无法连接",
1441
1443
  "peerHost.statusReconnecting": "重连中",
1442
1444
  "peerHost.statusDisabled": "已禁用",
1445
+ "peerHost.debugWorkspaceUnavailable": "远程调试工作区作用域不可用,请等待 PeerHost 工作区刷新",
1446
+ "peerHost.gitWorkspaceUnavailable": "远程 Git 工作区暂不可用,请等待 PeerHost 工作区刷新",
1443
1447
  "peerHost.stateExternal": "当前页面的 Transport 结构不受支持,插件无法包装它,PeerHost 聚合已停用;刷新页面不会改变结果。",
1444
1448
  "peerHost.stateNotInstalledDesktop": "当前 Desktop 页面没有安装 preboot shim;请重启 DSH Desktop 后再打开页面。",
1445
1449
  "peerHost.stateNotInstalledWeb": "当前页面未安装 preboot shim;请刷新 DSH Web 后再启用 PeerHost。",
@@ -1484,7 +1488,7 @@ window.__ModuleLoader__.load({
1484
1488
  "peerHostWorkspace.statusDisabled": "Disabled",
1485
1489
  "peerHostWorkspace.hintSessionRequired": "“{host}” needs a new sign-in. Open “Manage other DSH Hosts”, choose “Edit” for this Host, and save the account and password.",
1486
1490
  "peerHostWorkspace.hintUnreachable": "“{host}” is unreachable. Make sure the target machine is running, then click “Test” in the management panel to retry.",
1487
- "peerHostWorkspace.hintVersionMismatch": "The plugin or DSH version on “{host}” does not match; upgrade this plugin on that Host first.",
1491
+ "peerHostWorkspace.hintVersionMismatch": "“{host}” is incompatible. The client plugin version must be at least the PeerHost plugin version; the DSH version and API compatibility must also be supported.",
1488
1492
  "peerHostWorkspace.hintPluginMissing": "“{host}” does not have this plugin installed, so its workspaces cannot be aggregated.",
1489
1493
  "peerHostWorkspace.hintIdentityChanged": "The identity of “{host}” changed. Run “Test” and sign in again in the management panel.",
1490
1494
  "peerHostWorkspace.hintNotReady": "“{host}” is currently “{status}”; finish connecting it in the management panel first.",
@@ -1522,7 +1526,7 @@ window.__ModuleLoader__.load({
1522
1526
  "peerHostWorkspace.statusDisabled": "已禁用",
1523
1527
  "peerHostWorkspace.hintSessionRequired": "“{host}”需要重新登录。请到“管理其他 DSH Host”打开该 Host 的“编辑”,填入账号密码保存即可。",
1524
1528
  "peerHostWorkspace.hintUnreachable": "“{host}”当前无法连接。请确认目标机器已启动,然后在管理面板点“测试”重试。",
1525
- "peerHostWorkspace.hintVersionMismatch": "“{host}”的插件或 DSH 版本不匹配,需要先升级目标 Host 上的本插件。",
1529
+ "peerHostWorkspace.hintVersionMismatch": "“{host}”版本不兼容。客户端插件版本须不低于 PeerHost 插件版本,DSH 版本及 API 兼容标识也须受支持。",
1526
1530
  "peerHostWorkspace.hintPluginMissing": "“{host}”没有安装本插件,无法聚合它的工作区。",
1527
1531
  "peerHostWorkspace.hintIdentityChanged": "“{host}”的身份已变化。请在管理面板重新“测试”并登录。",
1528
1532
  "peerHostWorkspace.hintNotReady": "“{host}”当前状态为“{status}”,请先在管理面板完成连接。",
@@ -1783,6 +1787,8 @@ window.__ModuleLoader__.load({
1783
1787
  "accountBar.access": "Access: {access}",
1784
1788
  "accountBar.accessWithLatency": "Access: {access} · {latency} ms",
1785
1789
  "accountBar.memory": "Memory",
1790
+ "accountBar.hostCpu": "Host CPU",
1791
+ "accountBar.hostMemory": "Host memory",
1786
1792
  "accountBar.managePeerHost": "Manage PeerHost",
1787
1793
  "accountBar.managePeerHostHint": "Connect and manage other DSH Hosts",
1788
1794
  "accountBar.loggingOut": "Signing out…",
@@ -1889,6 +1895,8 @@ window.__ModuleLoader__.load({
1889
1895
  "accountBar.access": "访问:{access}",
1890
1896
  "accountBar.accessWithLatency": "访问:{access} · {latency} ms",
1891
1897
  "accountBar.memory": "内存",
1898
+ "accountBar.hostCpu": "主机 CPU",
1899
+ "accountBar.hostMemory": "主机内存",
1892
1900
  "accountBar.managePeerHost": "管理 PeerHost",
1893
1901
  "accountBar.managePeerHostHint": "连接和管理其他 DSH Host",
1894
1902
  "accountBar.loggingOut": "注销中…",
@@ -2770,6 +2778,11 @@ window.__ModuleLoader__.load({
2770
2778
  "cli.capabilities": "Verified capabilities",
2771
2779
  "cli.installed": "Installed",
2772
2780
  "cli.notInstalled": "Not installed",
2781
+ "cli.detecting": "Detecting…",
2782
+ "cli.detectionFailed": "Detection failed",
2783
+ "cli.redetect": "Detect again",
2784
+ "cli.redetectAll": "Detect all again",
2785
+ "cli.redetectHostUnsupported": "The connected Host does not support Agent detection refresh. Load the same CodingNS plugin version on the Host as this page, restart the Host, then refresh the page.",
2773
2786
  "cli.enabled": "Enabled",
2774
2787
  "cli.disabled": "Disabled",
2775
2788
  "cli.notDetectedVersion": "Version not detected",
@@ -3203,6 +3216,11 @@ window.__ModuleLoader__.load({
3203
3216
  "cli.capabilities": "已验证能力",
3204
3217
  "cli.installed": "已安装",
3205
3218
  "cli.notInstalled": "未安装",
3219
+ "cli.detecting": "检测中…",
3220
+ "cli.detectionFailed": "检测失败",
3221
+ "cli.redetect": "重新检测",
3222
+ "cli.redetectAll": "重新检测全部",
3223
+ "cli.redetectHostUnsupported": "当前连接的 Host 不支持重新检测 Agent。请确认 Host 已安装与页面一致的 CodingNS 插件版本,重启 Host 后再刷新页面。",
3206
3224
  "cli.enabled": "已启用",
3207
3225
  "cli.disabled": "已停用",
3208
3226
  "cli.notDetectedVersion": "未检测到版本",
@@ -4067,7 +4085,7 @@ window.__ModuleLoader__.load({
4067
4085
  return /^0\.1\.5(?:-|$)/u.test(version);
4068
4086
  }
4069
4087
  /** Codingns4DSH 插件自身的 npm 版本。 */
4070
- const CODINGNS_VERSION = "0.2.1-beta.4";
4088
+ const CODINGNS_VERSION = "0.2.1-beta.5";
4071
4089
  /** 判断宿主版本是否落在当前插件声明的 DSH 兼容范围内;范围省略上界时不校验上限。 */
4072
4090
  function isDshVersionCompatible(version) {
4073
4091
  const match = /^>=([^ ]+)(?: <=([^ ]+))?$/u.exec(DSH_COMPATIBILITY);
@@ -4081,19 +4099,26 @@ window.__ModuleLoader__.load({
4081
4099
  }
4082
4100
  /** 判断 DSH 版本是否达到某个功能模块要求的最低版本。 */
4083
4101
  function isDshVersionAtLeast(version, minimum) {
4102
+ return isVersionAtLeast(version, minimum);
4103
+ }
4104
+ /** 按语义版本比较大小;预发布标识参与排序,构建元数据不影响优先级,非法版本不放行。 */
4105
+ function isVersionAtLeast(version, minimum) {
4084
4106
  const actual = parseVersion$1(version);
4085
4107
  const required = parseVersion$1(minimum);
4086
4108
  if (!actual || !required) return false;
4087
4109
  return compareVersions$1(actual, required) >= 0;
4088
4110
  }
4089
4111
  function parseVersion$1(value) {
4090
- const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(value);
4112
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.exec(value);
4091
4113
  if (!match) return void 0;
4114
+ if (!match.slice(1, 4).map(Number).every(Number.isSafeInteger)) return void 0;
4115
+ const prerelease = match[4]?.split(".") ?? [];
4116
+ if (prerelease.some((part) => /^0\d+$/u.test(part))) return void 0;
4092
4117
  return {
4093
4118
  major: Number(match[1]),
4094
4119
  minor: Number(match[2]),
4095
4120
  patch: Number(match[3]),
4096
- prerelease: match[4] === void 0 ? [] : match[4].split(".").map((part) => /^\d+$/u.test(part) ? Number(part) : part)
4121
+ prerelease
4097
4122
  };
4098
4123
  }
4099
4124
  function compareVersions$1(left, right) {
@@ -4110,8 +4135,9 @@ window.__ModuleLoader__.load({
4110
4135
  if (leftPart === void 0) return -1;
4111
4136
  if (rightPart === void 0) return 1;
4112
4137
  if (leftPart === rightPart) continue;
4113
- if (typeof leftPart === "number" && typeof rightPart === "string") return -1;
4114
- if (typeof leftPart === "string" && typeof rightPart === "number") return 1;
4138
+ const leftNumeric = /^\d+$/u.test(leftPart);
4139
+ if (leftNumeric !== /^\d+$/u.test(rightPart)) return leftNumeric ? -1 : 1;
4140
+ if (leftNumeric && leftPart.length !== rightPart.length) return leftPart.length - rightPart.length;
4115
4141
  return leftPart < rightPart ? -1 : 1;
4116
4142
  }
4117
4143
  return 0;
@@ -6595,6 +6621,7 @@ window.__ModuleLoader__.load({
6595
6621
  NOT_READY: "PEER_HOST_NOT_READY",
6596
6622
  SESSION_REQUIRED: "PEER_HOST_SESSION_REQUIRED",
6597
6623
  PROXY_PATH_NOT_ALLOWED: "PEER_HOST_PROXY_PATH_NOT_ALLOWED",
6624
+ PROXY_ACCESS_DENIED: "PEER_HOST_PROXY_ACCESS_DENIED",
6598
6625
  SCOPE_MISMATCH: "PEER_HOST_SCOPE_MISMATCH",
6599
6626
  PROXY_UNREACHABLE: "PEER_HOST_PROXY_UNREACHABLE",
6600
6627
  RESPONSE_INVALID: "PEER_HOST_RESPONSE_INVALID",
@@ -6664,6 +6691,7 @@ window.__ModuleLoader__.load({
6664
6691
  DEBUG_DSH_HOST_API_UNAVAILABLE: "DEBUG_DSH_HOST_API_UNAVAILABLE",
6665
6692
  PEER_HOST_NOT_READY: PEER_HOST_ERROR_CODES.NOT_READY,
6666
6693
  PEER_HOST_PROXY_PATH_NOT_ALLOWED: PEER_HOST_ERROR_CODES.PROXY_PATH_NOT_ALLOWED,
6694
+ PEER_HOST_PROXY_ACCESS_DENIED: PEER_HOST_ERROR_CODES.PROXY_ACCESS_DENIED,
6667
6695
  PEER_HOST_SCOPE_MISMATCH: PEER_HOST_ERROR_CODES.SCOPE_MISMATCH,
6668
6696
  PEER_HOST_PROXY_UNREACHABLE: PEER_HOST_ERROR_CODES.PROXY_UNREACHABLE,
6669
6697
  PEER_HOST_RESPONSE_INVALID: PEER_HOST_ERROR_CODES.RESPONSE_INVALID,
@@ -7009,6 +7037,14 @@ window.__ModuleLoader__.load({
7009
7037
  }
7010
7038
  //#endregion
7011
7039
  //#region src/shared/assistant-avatar-engine.ts
7040
+ let runtimeRevision = 0;
7041
+ /** Host 与 Client 各自维护代次,安装成功立即解除缺失引擎的短期缓存。 */
7042
+ function invalidateAssistantAvatarRuntime() {
7043
+ runtimeRevision += 1;
7044
+ }
7045
+ function assistantAvatarRuntimeRevision() {
7046
+ return runtimeRevision;
7047
+ }
7012
7048
  /** 引擎许可单独版本化:Cubism SDK 条款与第三方素材许可分别确认。 */
7013
7049
  const ASSISTANT_AVATAR_ENGINE_CONSENT_VERSION = "2026-10-08.1";
7014
7050
  function validAssistantAvatarEngineConsent(value) {
@@ -11689,6 +11725,11 @@ window.__ModuleLoader__.load({
11689
11725
  function errorMessage$7(error) {
11690
11726
  return error instanceof Error ? error.message : String(error);
11691
11727
  }
11728
+ /** 旧 Host 缺少重新检测动作时给出版本提示;网络和检测错误仍保留原始原因。 */
11729
+ function catalogRefreshErrorMessage(error, t) {
11730
+ const message = errorMessage$7(error);
11731
+ return /^未知 CLI RPC: cli\/catalog\/refresh$/u.test(message) ? t("cli.redetectHostUnsupported") : message;
11732
+ }
11692
11733
  var init_cli_catalog = __esmMin((() => {
11693
11734
  init_transport();
11694
11735
  init_debug();
@@ -11855,7 +11896,16 @@ window.__ModuleLoader__.load({
11855
11896
  }
11856
11897
  /** 一次 RPC 读取全部脱敏绑定;不会按 DOM 行逐条请求。 */
11857
11898
  async function fetchSessionAdapters(rpc) {
11858
- const value = await callCliRpc(rpc, "session/adapter-map", {});
11899
+ const existing = requests.get(rpc);
11900
+ if (existing !== void 0) return existing;
11901
+ const request = readSessionAdapters(rpc).finally(() => {
11902
+ if (requests.get(rpc) === request) requests.delete(rpc);
11903
+ });
11904
+ requests.set(rpc, request);
11905
+ return request;
11906
+ }
11907
+ async function readSessionAdapters(rpc) {
11908
+ const value = await callCliRpc(rpc, "session/adapter-map", {}, AbortSignal.timeout(1e4));
11859
11909
  if (!Array.isArray(value)) return [];
11860
11910
  return value.filter(isSessionAdapterBinding).map((binding) => ({
11861
11911
  sessionId: binding.sessionId.trim(),
@@ -11863,8 +11913,8 @@ window.__ModuleLoader__.load({
11863
11913
  }));
11864
11914
  }
11865
11915
  function subscribeSessionAdapters(listener) {
11866
- listeners.add(listener);
11867
- return () => listeners.delete(listener);
11916
+ listeners$1.add(listener);
11917
+ return () => listeners$1.delete(listener);
11868
11918
  }
11869
11919
  /** 模块停用时清空内存关系,避免跨 generation 使用旧绑定。 */
11870
11920
  function clearSessionAdapters() {
@@ -11878,17 +11928,18 @@ window.__ModuleLoader__.load({
11878
11928
  return true;
11879
11929
  }
11880
11930
  function notify() {
11881
- for (const listener of [...listeners]) listener();
11931
+ for (const listener of [...listeners$1]) listener();
11882
11932
  }
11883
11933
  function isSessionAdapterBinding(value) {
11884
11934
  if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
11885
11935
  const record = value;
11886
11936
  return typeof record.sessionId === "string" && record.sessionId.trim() !== "" && typeof record.adapterId === "string" && record.adapterId.trim() !== "";
11887
11937
  }
11888
- var adaptersBySession, listeners;
11938
+ var adaptersBySession, listeners$1, requests;
11889
11939
  var init_session_adapter_cache = __esmMin((() => {
11890
11940
  adaptersBySession = /* @__PURE__ */ new Map();
11891
- listeners = /* @__PURE__ */ new Set();
11941
+ listeners$1 = /* @__PURE__ */ new Set();
11942
+ requests = /* @__PURE__ */ new WeakMap();
11892
11943
  }));
11893
11944
  //#endregion
11894
11945
  //#region src/client/context-breakdown-dom.ts
@@ -12015,6 +12066,329 @@ window.__ModuleLoader__.load({
12015
12066
  dom.head.appendChild(style);
12016
12067
  }
12017
12068
  //#endregion
12069
+ //#region src/client/adapter-catalog-watch.ts
12070
+ /** 手动检测完成后,让已挂载的选择器和模型目录一起更新。 */
12071
+ function notifyAdapterCatalogChanged(rpc) {
12072
+ for (const listener of listeners.get(rpc) ?? []) listener();
12073
+ }
12074
+ function subscribeAdapterCatalogChanged(rpc, listener) {
12075
+ let entries = listeners.get(rpc);
12076
+ if (entries === void 0) {
12077
+ entries = /* @__PURE__ */ new Set();
12078
+ listeners.set(rpc, entries);
12079
+ }
12080
+ entries.add(listener);
12081
+ return () => {
12082
+ entries.delete(listener);
12083
+ };
12084
+ }
12085
+ /** 只在首轮检测未完成时读取进度;完成即停,没有长期后台轮询。 */
12086
+ function watchAdapterCatalog(rpc, sessionId, onValue, onError = () => void 0) {
12087
+ let active = true;
12088
+ let busy = false;
12089
+ let dirty = false;
12090
+ let started = Date.now();
12091
+ let failures = 0;
12092
+ let timer;
12093
+ const refresh = async () => {
12094
+ if (!active) return;
12095
+ if (busy) {
12096
+ dirty = true;
12097
+ return;
12098
+ }
12099
+ clearTimeout(timer);
12100
+ busy = true;
12101
+ try {
12102
+ let requests = loads.get(rpc);
12103
+ if (requests === void 0) {
12104
+ requests = /* @__PURE__ */ new Map();
12105
+ loads.set(rpc, requests);
12106
+ }
12107
+ const key = sessionId ?? "";
12108
+ let request = requests.get(key);
12109
+ if (request === void 0) {
12110
+ request = callCliRpc(rpc, "catalog", sessionId === void 0 ? {} : { sessionId }, AbortSignal.timeout(1e4)).finally(() => {
12111
+ if (requests.get(key) === request) requests.delete(key);
12112
+ });
12113
+ requests.set(key, request);
12114
+ }
12115
+ const value = await request;
12116
+ if (!active) return;
12117
+ failures = 0;
12118
+ onValue(value);
12119
+ if (value.some((entry) => entry.detectionState === "pending" || entry.detectionState === "running") && Date.now() - started < 12e4) timer = setTimeout(() => {
12120
+ refresh();
12121
+ }, 1e3);
12122
+ } catch (error) {
12123
+ if (active) {
12124
+ failures += 1;
12125
+ if (failures === 1) onError(error);
12126
+ if (Date.now() - started < 12e4) timer = setTimeout(() => {
12127
+ refresh();
12128
+ }, Math.min(1e3 * 2 ** failures, 15e3));
12129
+ }
12130
+ } finally {
12131
+ busy = false;
12132
+ if (dirty && active) {
12133
+ dirty = false;
12134
+ refresh();
12135
+ }
12136
+ }
12137
+ };
12138
+ const remove = subscribeAdapterCatalogChanged(rpc, () => {
12139
+ started = Date.now();
12140
+ refresh();
12141
+ });
12142
+ refresh();
12143
+ return () => {
12144
+ active = false;
12145
+ clearTimeout(timer);
12146
+ remove();
12147
+ };
12148
+ }
12149
+ var loads, listeners;
12150
+ var init_adapter_catalog_watch = __esmMin((() => {
12151
+ init_cli_catalog();
12152
+ loads = /* @__PURE__ */ new WeakMap();
12153
+ listeners = /* @__PURE__ */ new WeakMap();
12154
+ }));
12155
+ //#endregion
12156
+ //#region src/client/model-catalog-cache.ts
12157
+ function modelCatalogKey(rpc, sessionId) {
12158
+ const hostId = sessionId === void 0 ? void 0 : parseVirtualSessionId(sessionId)?.hostId;
12159
+ if (hostId === void 0) return rpc;
12160
+ let hosts = modelCatalogHostKeys.get(rpc);
12161
+ if (hosts === void 0) {
12162
+ hosts = /* @__PURE__ */ new Map();
12163
+ modelCatalogHostKeys.set(rpc, hosts);
12164
+ }
12165
+ let key = hosts.get(hostId);
12166
+ if (key === void 0) {
12167
+ key = {};
12168
+ hosts.set(hostId, key);
12169
+ }
12170
+ return key;
12171
+ }
12172
+ function cacheEntry(rpc, adapterId, sessionId) {
12173
+ return cacheTimesFor(rpc, sessionId).get(adapterId);
12174
+ }
12175
+ function cacheTimesFor(rpc, sessionId) {
12176
+ const key = modelCatalogKey(rpc, sessionId);
12177
+ let times = modelCatalogCacheTimes.get(key);
12178
+ if (times === void 0) {
12179
+ times = /* @__PURE__ */ new Map();
12180
+ modelCatalogCacheTimes.set(key, times);
12181
+ }
12182
+ return times;
12183
+ }
12184
+ function storeCatalog(rpc, adapterId, value, sessionId) {
12185
+ getModelCatalogCache(rpc, sessionId).set(adapterId, value);
12186
+ cacheTimesFor(rpc, sessionId).set(adapterId, {
12187
+ value,
12188
+ storedAt: Date.now()
12189
+ });
12190
+ }
12191
+ /** 指定会话时只作废其 Host;旧调用不传会话时仍清理整个 RPC 的指定目录。 */
12192
+ function invalidateModelCatalogCache(rpc, adapterId, sessionId) {
12193
+ const keys = sessionId === void 0 ? [rpc, ...modelCatalogHostKeys.get(rpc)?.values() ?? []] : [modelCatalogKey(rpc, sessionId)];
12194
+ for (const key of keys) {
12195
+ const cache = modelCatalogCaches.get(key);
12196
+ const times = modelCatalogCacheTimes.get(key);
12197
+ const loads = modelCatalogLoads.get(key);
12198
+ if (adapterId === void 0) loads?.clear();
12199
+ else loads?.delete(adapterId);
12200
+ if (adapterId === void 0) {
12201
+ cache?.clear();
12202
+ times?.clear();
12203
+ } else {
12204
+ cache?.delete(adapterId);
12205
+ times?.delete(adapterId);
12206
+ }
12207
+ }
12208
+ }
12209
+ function shouldRevalidateModelCatalog(rpc, adapterId, needsRevalidation, sessionId) {
12210
+ if (!needsRevalidation) return false;
12211
+ const key = modelCatalogKey(rpc, sessionId);
12212
+ let times = modelCatalogRevalidations.get(key);
12213
+ if (times === void 0) {
12214
+ times = /* @__PURE__ */ new Map();
12215
+ modelCatalogRevalidations.set(key, times);
12216
+ }
12217
+ const last = times.get(adapterId);
12218
+ const now = Date.now();
12219
+ if (last !== void 0 && now - last < 6e4) return false;
12220
+ times.set(adapterId, now);
12221
+ return true;
12222
+ }
12223
+ function getModelCatalogCache(rpc, sessionId) {
12224
+ const key = modelCatalogKey(rpc, sessionId);
12225
+ let cache = modelCatalogCaches.get(key);
12226
+ if (cache === void 0) {
12227
+ cache = /* @__PURE__ */ new Map();
12228
+ modelCatalogCaches.set(key, cache);
12229
+ }
12230
+ return cache;
12231
+ }
12232
+ function loadModelCatalog(rpc, adapterId, sessionId) {
12233
+ const cached = getModelCatalogCache(rpc, sessionId).get(adapterId);
12234
+ if (cached !== void 0 && cached.fallback !== true && isFreshCacheEntry(rpc, adapterId, cached, sessionId)) return Promise.resolve(cached);
12235
+ if (cached !== void 0) invalidateModelCatalogCache(rpc, adapterId, sessionId);
12236
+ const loads = getModelCatalogLoadCache(rpc, sessionId);
12237
+ const running = loads.get(adapterId);
12238
+ if (running !== void 0) return running;
12239
+ const request = callCliRpc(rpc, "models", {
12240
+ adapterId,
12241
+ ...sessionId === void 0 ? {} : { sessionId }
12242
+ }).then((value) => {
12243
+ if (loads.get(adapterId) !== request) return loadModelCatalog(rpc, adapterId, sessionId);
12244
+ if (value.fallback === true) invalidateModelCatalogCache(rpc, adapterId, sessionId);
12245
+ else storeCatalog(rpc, adapterId, value, sessionId);
12246
+ return value;
12247
+ }).finally(() => {
12248
+ if (loads.get(adapterId) === request) loads.delete(adapterId);
12249
+ });
12250
+ loads.set(adapterId, request);
12251
+ return request;
12252
+ }
12253
+ /** 缓存条目是否仍在有效期内;没有时间戳的旧条目按过期处理并触发一次重新读取。 */
12254
+ function isFreshCacheEntry(rpc, adapterId, cached, sessionId) {
12255
+ const entry = cacheEntry(rpc, adapterId, sessionId);
12256
+ if (entry === void 0 || entry.value !== cached) return false;
12257
+ return Date.now() - entry.storedAt < MODEL_CATALOG_CACHE_TTL_MS;
12258
+ }
12259
+ function getModelCatalogLoadCache(rpc, sessionId) {
12260
+ const key = modelCatalogKey(rpc, sessionId);
12261
+ let cache = modelCatalogLoads.get(key);
12262
+ if (cache === void 0) {
12263
+ cache = /* @__PURE__ */ new Map();
12264
+ modelCatalogLoads.set(key, cache);
12265
+ }
12266
+ return cache;
12267
+ }
12268
+ var modelCatalogCaches, modelCatalogLoads, modelCatalogHostKeys, MODEL_CATALOG_CACHE_TTL_MS, modelCatalogCacheTimes, modelCatalogRevalidations;
12269
+ var init_model_catalog_cache = __esmMin((() => {
12270
+ init_cli_catalog();
12271
+ init_peer_host();
12272
+ modelCatalogCaches = /* @__PURE__ */ new WeakMap();
12273
+ modelCatalogLoads = /* @__PURE__ */ new WeakMap();
12274
+ modelCatalogHostKeys = /* @__PURE__ */ new WeakMap();
12275
+ MODEL_CATALOG_CACHE_TTL_MS = 6e4;
12276
+ modelCatalogCacheTimes = /* @__PURE__ */ new WeakMap();
12277
+ modelCatalogRevalidations = /* @__PURE__ */ new WeakMap();
12278
+ }));
12279
+ //#endregion
12280
+ //#region src/dsh-capabilities/client/primitives-adapter.ts
12281
+ /** 助理控件优先共用宿主图标,缺少的电话与普通对话采用相同 16px 画布和细描边。 */
12282
+ function resolveAssistantControlIcon(name) {
12283
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12284
+ switch (name) {
12285
+ case "add": return resolvePlusIcon();
12286
+ case "clear": return resolveRefreshIcon();
12287
+ case "settings": return value.IconSettingsOutlineRegular ?? value.IconSettingsOutlineMedium ?? resolveToolIcon();
12288
+ case "close": return value.IconCloseOutlineRegular ?? value.IconCloseOutlineMedium ?? unavailableIcon;
12289
+ case "chat": return value.IconChatOutlineRegular ?? value.IconChatOutlineMedium ?? AssistantChatIcon;
12290
+ case "send": return value.IconSendOutlineRegular ?? value.IconSendOutlineMedium ?? unavailableIcon;
12291
+ case "stop": return value.IconStopFillRegular ?? value.IconStopFillMedium ?? unavailableIcon;
12292
+ case "phone": return value.IconPhoneOutlineRegular ?? value.IconPhoneOutlineMedium ?? AssistantPhoneIcon;
12293
+ }
12294
+ }
12295
+ /** 沿用 DSH 新对话的气泡轮廓,内部使用三点表示进入已有对话。 */
12296
+ function AssistantChatIcon({ size = 20, className }) {
12297
+ return (0, react.createElement)("svg", {
12298
+ width: size,
12299
+ height: size,
12300
+ className,
12301
+ viewBox: "0 0 16 16",
12302
+ fill: "none",
12303
+ "aria-hidden": true,
12304
+ focusable: false,
12305
+ stroke: "currentColor",
12306
+ strokeWidth: 1,
12307
+ strokeLinecap: "round",
12308
+ strokeLinejoin: "round"
12309
+ }, (0, react.createElement)("path", { d: "M2.37091 11.2501C1.58745 9.89288 1.32067 8.29835 1.61969 6.76006C1.91872 5.22177 2.76342 3.8433 3.99826 2.87846C5.2331 1.91362 6.77494 1.42737 8.33988 1.50925C9.90482 1.59113 11.3875 2.23562 12.5149 3.32406C13.6425 4.41269 14.3387 5.87206 14.4754 7.4334C14.612 8.99474 14.18 10.5529 13.2587 11.8209C12.3375 13.0888 10.9891 13.9813 9.46194 14.3337C8.18691 14.628 6.85895 14.5294 5.64989 14.0605C5.1712 13.8748 4.76962 13.4932 4.26534 13.3967C3.67413 13.2835 2.95257 13.5598 2.03794 14.3337" }), ...[
12310
+ 5.25,
12311
+ 8,
12312
+ 10.75
12313
+ ].map((cx) => (0, react.createElement)("circle", {
12314
+ key: cx,
12315
+ cx,
12316
+ cy: 8,
12317
+ r: .65,
12318
+ fill: "currentColor",
12319
+ stroke: "none"
12320
+ })));
12321
+ }
12322
+ function AssistantPhoneIcon({ size = 20, className }) {
12323
+ return (0, react.createElement)("svg", {
12324
+ width: size,
12325
+ height: size,
12326
+ className,
12327
+ viewBox: "0 0 16 16",
12328
+ fill: "none",
12329
+ "aria-hidden": true,
12330
+ stroke: "currentColor",
12331
+ strokeWidth: 1,
12332
+ strokeLinecap: "round",
12333
+ strokeLinejoin: "round"
12334
+ }, (0, react.createElement)("path", { d: "M3.1 1.8h2l1.1 3.1-1.4 1.4a10.5 10.5 0 0 0 4.9 4.9l1.4-1.4 3.1 1.1v2a1.4 1.4 0 0 1-1.6 1.4A13 13 0 0 1 1.7 3.4a1.4 1.4 0 0 1 1.4-1.6Z" }));
12335
+ }
12336
+ /**
12337
+ * 图标导出兼容层。0.1.7 可能改名为 Regular/Medium,运行时优先使用新导出,
12338
+ * 旧导出仍作为回退;业务组件不再直接判断 DSH 版本。
12339
+ */
12340
+ function resolvePlusIcon() {
12341
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12342
+ return value.IconPlusOutlineRegular ?? value.IconPlusOutlineMedium ?? value.IconPlusOutline16 ?? unavailableIcon;
12343
+ }
12344
+ function resolveChevronDownIcon() {
12345
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12346
+ return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ?? value.IconChevronDownOutline14 ?? unavailableIcon;
12347
+ }
12348
+ /** 终端工具栏使用的原生刷新图标。 */
12349
+ function resolveRefreshIcon() {
12350
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12351
+ return value.IconRefreshOutlineRegular ?? value.IconRefreshOutlineMedium ?? unavailableIcon;
12352
+ }
12353
+ /** 终端工具栏入口使用的原生工具图标。 */
12354
+ function resolveToolIcon() {
12355
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12356
+ return value.IconSlidersTwoOutlineRegular ?? value.IconSlidersTwoOutlineMedium ?? value.IconSettingsOutlineRegular ?? value.IconSettingsOutlineMedium ?? unavailableIcon;
12357
+ }
12358
+ /** 终端快捷操作的方向图标。 */
12359
+ function resolveTerminalArrowIcon(direction) {
12360
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12361
+ if (direction === "up") return value.IconChevronUpOutlineRegular ?? value.IconChevronUpOutlineMedium ?? unavailableIcon;
12362
+ if (direction === "down") return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ?? unavailableIcon;
12363
+ if (direction === "left") return value.IconChevronLeftOutlineRegular ?? value.IconChevronLeftOutlineMedium ?? unavailableIcon;
12364
+ return value.IconChevronRightOutlineRegular ?? value.IconChevronRightOutlineMedium ?? unavailableIcon;
12365
+ }
12366
+ /** 终端按键标签使用 DSH 原生 ShortcutKeys,旧版本缺失时退回纯文本。 */
12367
+ function resolveShortcutKeys() {
12368
+ return _deepseek_ai_dsh_client_ui_primitives.ShortcutKeys ?? fallbackShortcutKeys;
12369
+ }
12370
+ /**
12371
+ * 模型图标:DSH 原生模型选择器在紧凑状态显示的 data 图标(0.1.7 起为 Regular/Medium,
12372
+ * 0.1.6 为 16 后缀),插件模型选择器收起时与之保持一致。
12373
+ */
12374
+ function resolveDataIcon() {
12375
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12376
+ return value.IconDataOutlineRegular ?? value.IconDataOutlineMedium ?? value.IconDataOutline16 ?? unavailableIcon;
12377
+ }
12378
+ /**
12379
+ * `/委派` 菜单行图标:优先使用共享(send/share)字形,缺失时回退到插件通用的
12380
+ * data 图标,保证旧版 DSH 仍能渲染出一行可识别的委派入口。
12381
+ */
12382
+ function resolveDelegateIcon() {
12383
+ const value = _deepseek_ai_dsh_client_ui_primitives;
12384
+ return value.IconShareOutlineRegular ?? value.IconShareOutlineMedium ?? value.IconSendOutlineRegular ?? value.IconSendOutlineMedium ?? resolveDataIcon();
12385
+ }
12386
+ var unavailableIcon, fallbackShortcutKeys;
12387
+ var init_primitives_adapter = __esmMin((() => {
12388
+ unavailableIcon = () => null;
12389
+ fallbackShortcutKeys = ({ keys }) => (0, react.createElement)("span", void 0, keys.join(" + "));
12390
+ }));
12391
+ //#endregion
12018
12392
  //#region src/shared/delegation-carrier.ts
12019
12393
  function encodeDelegationCarrier(adapterId, label, modelId) {
12020
12394
  const normalizedId = adapterId.trim();
@@ -12660,239 +13034,6 @@ window.__ModuleLoader__.load({
12660
13034
  DELEGATION_TARGET_PATTERN = /^-\s*([^\s((]+)\s*[((]([^,,))]+)(?:[,,]\s*模型:([^,,))]*))?(?:[,,][^))]*)?[))]\s*$/gmu;
12661
13035
  }));
12662
13036
  //#endregion
12663
- //#region src/client/model-catalog-cache.ts
12664
- function modelCatalogKey(rpc, sessionId) {
12665
- const hostId = sessionId === void 0 ? void 0 : parseVirtualSessionId(sessionId)?.hostId;
12666
- if (hostId === void 0) return rpc;
12667
- let hosts = modelCatalogHostKeys.get(rpc);
12668
- if (hosts === void 0) {
12669
- hosts = /* @__PURE__ */ new Map();
12670
- modelCatalogHostKeys.set(rpc, hosts);
12671
- }
12672
- let key = hosts.get(hostId);
12673
- if (key === void 0) {
12674
- key = {};
12675
- hosts.set(hostId, key);
12676
- }
12677
- return key;
12678
- }
12679
- function cacheEntry(rpc, adapterId, sessionId) {
12680
- return cacheTimesFor(rpc, sessionId).get(adapterId);
12681
- }
12682
- function cacheTimesFor(rpc, sessionId) {
12683
- const key = modelCatalogKey(rpc, sessionId);
12684
- let times = modelCatalogCacheTimes.get(key);
12685
- if (times === void 0) {
12686
- times = /* @__PURE__ */ new Map();
12687
- modelCatalogCacheTimes.set(key, times);
12688
- }
12689
- return times;
12690
- }
12691
- function storeCatalog(rpc, adapterId, value, sessionId) {
12692
- getModelCatalogCache(rpc, sessionId).set(adapterId, value);
12693
- cacheTimesFor(rpc, sessionId).set(adapterId, {
12694
- value,
12695
- storedAt: Date.now()
12696
- });
12697
- }
12698
- /** 指定会话时只作废其 Host;旧调用不传会话时仍清理整个 RPC 的指定目录。 */
12699
- function invalidateModelCatalogCache(rpc, adapterId, sessionId) {
12700
- const keys = sessionId === void 0 ? [rpc, ...modelCatalogHostKeys.get(rpc)?.values() ?? []] : [modelCatalogKey(rpc, sessionId)];
12701
- for (const key of keys) {
12702
- const cache = modelCatalogCaches.get(key);
12703
- const times = modelCatalogCacheTimes.get(key);
12704
- if (adapterId === void 0) {
12705
- cache?.clear();
12706
- times?.clear();
12707
- } else {
12708
- cache?.delete(adapterId);
12709
- times?.delete(adapterId);
12710
- }
12711
- }
12712
- }
12713
- function shouldRevalidateModelCatalog(rpc, adapterId, needsRevalidation, sessionId) {
12714
- if (!needsRevalidation) return false;
12715
- const key = modelCatalogKey(rpc, sessionId);
12716
- let times = modelCatalogRevalidations.get(key);
12717
- if (times === void 0) {
12718
- times = /* @__PURE__ */ new Map();
12719
- modelCatalogRevalidations.set(key, times);
12720
- }
12721
- const last = times.get(adapterId);
12722
- const now = Date.now();
12723
- if (last !== void 0 && now - last < 6e4) return false;
12724
- times.set(adapterId, now);
12725
- return true;
12726
- }
12727
- function getModelCatalogCache(rpc, sessionId) {
12728
- const key = modelCatalogKey(rpc, sessionId);
12729
- let cache = modelCatalogCaches.get(key);
12730
- if (cache === void 0) {
12731
- cache = /* @__PURE__ */ new Map();
12732
- modelCatalogCaches.set(key, cache);
12733
- }
12734
- return cache;
12735
- }
12736
- function loadModelCatalog(rpc, adapterId, sessionId) {
12737
- const cached = getModelCatalogCache(rpc, sessionId).get(adapterId);
12738
- if (cached !== void 0 && cached.fallback !== true && isFreshCacheEntry(rpc, adapterId, cached, sessionId)) return Promise.resolve(cached);
12739
- if (cached !== void 0) invalidateModelCatalogCache(rpc, adapterId, sessionId);
12740
- const loads = getModelCatalogLoadCache(rpc, sessionId);
12741
- const running = loads.get(adapterId);
12742
- if (running !== void 0) return running;
12743
- const request = callCliRpc(rpc, "models", {
12744
- adapterId,
12745
- ...sessionId === void 0 ? {} : { sessionId }
12746
- }).then((value) => {
12747
- if (value.fallback === true) invalidateModelCatalogCache(rpc, adapterId, sessionId);
12748
- else storeCatalog(rpc, adapterId, value, sessionId);
12749
- return value;
12750
- }).finally(() => {
12751
- if (loads.get(adapterId) === request) loads.delete(adapterId);
12752
- });
12753
- loads.set(adapterId, request);
12754
- return request;
12755
- }
12756
- /** 缓存条目是否仍在有效期内;没有时间戳的旧条目按过期处理并触发一次重新读取。 */
12757
- function isFreshCacheEntry(rpc, adapterId, cached, sessionId) {
12758
- const entry = cacheEntry(rpc, adapterId, sessionId);
12759
- if (entry === void 0 || entry.value !== cached) return false;
12760
- return Date.now() - entry.storedAt < MODEL_CATALOG_CACHE_TTL_MS;
12761
- }
12762
- function getModelCatalogLoadCache(rpc, sessionId) {
12763
- const key = modelCatalogKey(rpc, sessionId);
12764
- let cache = modelCatalogLoads.get(key);
12765
- if (cache === void 0) {
12766
- cache = /* @__PURE__ */ new Map();
12767
- modelCatalogLoads.set(key, cache);
12768
- }
12769
- return cache;
12770
- }
12771
- var modelCatalogCaches, modelCatalogLoads, modelCatalogHostKeys, MODEL_CATALOG_CACHE_TTL_MS, modelCatalogCacheTimes, MODEL_CATALOG_REVALIDATE_INTERVAL_MS, modelCatalogRevalidations;
12772
- var init_model_catalog_cache = __esmMin((() => {
12773
- init_cli_catalog();
12774
- init_peer_host();
12775
- modelCatalogCaches = /* @__PURE__ */ new WeakMap();
12776
- modelCatalogLoads = /* @__PURE__ */ new WeakMap();
12777
- modelCatalogHostKeys = /* @__PURE__ */ new WeakMap();
12778
- MODEL_CATALOG_CACHE_TTL_MS = 6e4;
12779
- modelCatalogCacheTimes = /* @__PURE__ */ new WeakMap();
12780
- MODEL_CATALOG_REVALIDATE_INTERVAL_MS = 6e4;
12781
- modelCatalogRevalidations = /* @__PURE__ */ new WeakMap();
12782
- }));
12783
- //#endregion
12784
- //#region src/dsh-capabilities/client/primitives-adapter.ts
12785
- /** 助理控件优先共用宿主图标,缺少的电话与普通对话采用相同 16px 画布和细描边。 */
12786
- function resolveAssistantControlIcon(name) {
12787
- const value = _deepseek_ai_dsh_client_ui_primitives;
12788
- switch (name) {
12789
- case "add": return resolvePlusIcon();
12790
- case "clear": return resolveRefreshIcon();
12791
- case "settings": return value.IconSettingsOutlineRegular ?? value.IconSettingsOutlineMedium ?? resolveToolIcon();
12792
- case "close": return value.IconCloseOutlineRegular ?? value.IconCloseOutlineMedium ?? unavailableIcon;
12793
- case "chat": return value.IconChatOutlineRegular ?? value.IconChatOutlineMedium ?? AssistantChatIcon;
12794
- case "send": return value.IconSendOutlineRegular ?? value.IconSendOutlineMedium ?? unavailableIcon;
12795
- case "stop": return value.IconStopFillRegular ?? value.IconStopFillMedium ?? unavailableIcon;
12796
- case "phone": return value.IconPhoneOutlineRegular ?? value.IconPhoneOutlineMedium ?? AssistantPhoneIcon;
12797
- }
12798
- }
12799
- /** 沿用 DSH 新对话的气泡轮廓,内部使用三点表示进入已有对话。 */
12800
- function AssistantChatIcon({ size = 20, className }) {
12801
- return (0, react.createElement)("svg", {
12802
- width: size,
12803
- height: size,
12804
- className,
12805
- viewBox: "0 0 16 16",
12806
- fill: "none",
12807
- "aria-hidden": true,
12808
- focusable: false,
12809
- stroke: "currentColor",
12810
- strokeWidth: 1,
12811
- strokeLinecap: "round",
12812
- strokeLinejoin: "round"
12813
- }, (0, react.createElement)("path", { d: "M2.37091 11.2501C1.58745 9.89288 1.32067 8.29835 1.61969 6.76006C1.91872 5.22177 2.76342 3.8433 3.99826 2.87846C5.2331 1.91362 6.77494 1.42737 8.33988 1.50925C9.90482 1.59113 11.3875 2.23562 12.5149 3.32406C13.6425 4.41269 14.3387 5.87206 14.4754 7.4334C14.612 8.99474 14.18 10.5529 13.2587 11.8209C12.3375 13.0888 10.9891 13.9813 9.46194 14.3337C8.18691 14.628 6.85895 14.5294 5.64989 14.0605C5.1712 13.8748 4.76962 13.4932 4.26534 13.3967C3.67413 13.2835 2.95257 13.5598 2.03794 14.3337" }), ...[
12814
- 5.25,
12815
- 8,
12816
- 10.75
12817
- ].map((cx) => (0, react.createElement)("circle", {
12818
- key: cx,
12819
- cx,
12820
- cy: 8,
12821
- r: .65,
12822
- fill: "currentColor",
12823
- stroke: "none"
12824
- })));
12825
- }
12826
- function AssistantPhoneIcon({ size = 20, className }) {
12827
- return (0, react.createElement)("svg", {
12828
- width: size,
12829
- height: size,
12830
- className,
12831
- viewBox: "0 0 16 16",
12832
- fill: "none",
12833
- "aria-hidden": true,
12834
- stroke: "currentColor",
12835
- strokeWidth: 1,
12836
- strokeLinecap: "round",
12837
- strokeLinejoin: "round"
12838
- }, (0, react.createElement)("path", { d: "M3.1 1.8h2l1.1 3.1-1.4 1.4a10.5 10.5 0 0 0 4.9 4.9l1.4-1.4 3.1 1.1v2a1.4 1.4 0 0 1-1.6 1.4A13 13 0 0 1 1.7 3.4a1.4 1.4 0 0 1 1.4-1.6Z" }));
12839
- }
12840
- /**
12841
- * 图标导出兼容层。0.1.7 可能改名为 Regular/Medium,运行时优先使用新导出,
12842
- * 旧导出仍作为回退;业务组件不再直接判断 DSH 版本。
12843
- */
12844
- function resolvePlusIcon() {
12845
- const value = _deepseek_ai_dsh_client_ui_primitives;
12846
- return value.IconPlusOutlineRegular ?? value.IconPlusOutlineMedium ?? value.IconPlusOutline16 ?? unavailableIcon;
12847
- }
12848
- function resolveChevronDownIcon() {
12849
- const value = _deepseek_ai_dsh_client_ui_primitives;
12850
- return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ?? value.IconChevronDownOutline14 ?? unavailableIcon;
12851
- }
12852
- /** 终端工具栏使用的原生刷新图标。 */
12853
- function resolveRefreshIcon() {
12854
- const value = _deepseek_ai_dsh_client_ui_primitives;
12855
- return value.IconRefreshOutlineRegular ?? value.IconRefreshOutlineMedium ?? unavailableIcon;
12856
- }
12857
- /** 终端工具栏入口使用的原生工具图标。 */
12858
- function resolveToolIcon() {
12859
- const value = _deepseek_ai_dsh_client_ui_primitives;
12860
- return value.IconSlidersTwoOutlineRegular ?? value.IconSlidersTwoOutlineMedium ?? value.IconSettingsOutlineRegular ?? value.IconSettingsOutlineMedium ?? unavailableIcon;
12861
- }
12862
- /** 终端快捷操作的方向图标。 */
12863
- function resolveTerminalArrowIcon(direction) {
12864
- const value = _deepseek_ai_dsh_client_ui_primitives;
12865
- if (direction === "up") return value.IconChevronUpOutlineRegular ?? value.IconChevronUpOutlineMedium ?? unavailableIcon;
12866
- if (direction === "down") return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ?? unavailableIcon;
12867
- if (direction === "left") return value.IconChevronLeftOutlineRegular ?? value.IconChevronLeftOutlineMedium ?? unavailableIcon;
12868
- return value.IconChevronRightOutlineRegular ?? value.IconChevronRightOutlineMedium ?? unavailableIcon;
12869
- }
12870
- /** 终端按键标签使用 DSH 原生 ShortcutKeys,旧版本缺失时退回纯文本。 */
12871
- function resolveShortcutKeys() {
12872
- return _deepseek_ai_dsh_client_ui_primitives.ShortcutKeys ?? fallbackShortcutKeys;
12873
- }
12874
- /**
12875
- * 模型图标:DSH 原生模型选择器在紧凑状态显示的 data 图标(0.1.7 起为 Regular/Medium,
12876
- * 0.1.6 为 16 后缀),插件模型选择器收起时与之保持一致。
12877
- */
12878
- function resolveDataIcon() {
12879
- const value = _deepseek_ai_dsh_client_ui_primitives;
12880
- return value.IconDataOutlineRegular ?? value.IconDataOutlineMedium ?? value.IconDataOutline16 ?? unavailableIcon;
12881
- }
12882
- /**
12883
- * `/委派` 菜单行图标:优先使用共享(send/share)字形,缺失时回退到插件通用的
12884
- * data 图标,保证旧版 DSH 仍能渲染出一行可识别的委派入口。
12885
- */
12886
- function resolveDelegateIcon() {
12887
- const value = _deepseek_ai_dsh_client_ui_primitives;
12888
- return value.IconShareOutlineRegular ?? value.IconShareOutlineMedium ?? value.IconSendOutlineRegular ?? value.IconSendOutlineMedium ?? resolveDataIcon();
12889
- }
12890
- var unavailableIcon, fallbackShortcutKeys;
12891
- var init_primitives_adapter = __esmMin((() => {
12892
- unavailableIcon = () => null;
12893
- fallbackShortcutKeys = ({ keys }) => (0, react.createElement)("span", void 0, keys.join(" + "));
12894
- }));
12895
- //#endregion
12896
13037
  //#region src/client/delegate-command.ts
12897
13038
  var delegate_command_exports = /* @__PURE__ */ __exportAll({ registerDelegateCommand: () => registerDelegateCommand });
12898
13039
  function delegateReferenceKey(adapterId, modelId) {
@@ -13795,13 +13936,7 @@ window.__ModuleLoader__.load({
13795
13936
  };
13796
13937
  }, [selection.adapterId]);
13797
13938
  (0, react.useEffect)(() => {
13798
- let active = true;
13799
- callCliRpc(props.rpc, "catalog", sessionId === void 0 ? {} : { sessionId }).then((value) => {
13800
- if (active) setAgents(adapterCatalogWithDsh(value));
13801
- }).catch(() => void 0);
13802
- return () => {
13803
- active = false;
13804
- };
13939
+ return watchAdapterCatalog(props.rpc, sessionId, (value) => setAgents(adapterCatalogWithDsh(value)));
13805
13940
  }, [props.rpc, sessionId]);
13806
13941
  (0, react.useEffect)(() => {
13807
13942
  if (locked) setOpen(false);
@@ -13972,7 +14107,6 @@ window.__ModuleLoader__.load({
13972
14107
  });
13973
14108
  const catalog = catalogState?.adapterId === selection.adapterId && catalogState.sessionId === sessionId ? catalogState.value : null;
13974
14109
  const loading = selection.adapterId !== "dsh" && catalog === null && refreshingAdapterId === selection.adapterId;
13975
- const serviceTierRevalidation = needsServiceTierRevalidation(catalog);
13976
14110
  (0, react.useEffect)(() => {
13977
14111
  if (selection.adapterId === "dsh") {
13978
14112
  setCatalogState(null);
@@ -13980,7 +14114,6 @@ window.__ModuleLoader__.load({
13980
14114
  return;
13981
14115
  }
13982
14116
  let active = true;
13983
- let retryTimer;
13984
14117
  const adapterId = selection.adapterId;
13985
14118
  const cached = getModelCatalogCache(props.rpc, sessionId).get(adapterId);
13986
14119
  if (cached !== void 0) setCatalogState({
@@ -13997,9 +14130,6 @@ window.__ModuleLoader__.load({
13997
14130
  adapterId,
13998
14131
  value
13999
14132
  });
14000
- if (value.fallback === true) retryTimer = setTimeout(() => {
14001
- if (active) setCatalogRetry((value) => value + 1);
14002
- }, 15e3);
14003
14133
  const normalize = () => {
14004
14134
  if (!active) return;
14005
14135
  const currentSelection = sessionId === void 0 ? selection : selections.get(sessionId) ?? selection;
@@ -14034,7 +14164,6 @@ window.__ModuleLoader__.load({
14034
14164
  });
14035
14165
  return () => {
14036
14166
  active = false;
14037
- if (retryTimer !== void 0) clearTimeout(retryTimer);
14038
14167
  };
14039
14168
  }, [
14040
14169
  props.rpc,
@@ -14042,25 +14171,7 @@ window.__ModuleLoader__.load({
14042
14171
  sessionId,
14043
14172
  catalogRetry
14044
14173
  ]);
14045
- /**
14046
- * 档位判定处于「未确认官方订阅」时周期复检。
14047
- *
14048
- * 用户在 cc-switch 之类的工具里切回官方订阅不会触发页面事件,唯一能发现变化的
14049
- * 方式就是再探测一次。这里只负责到点触发一次目录重读,是否真正作废缓存交给主
14050
- * effect 的节流判定——若在本 effect 里调用节流函数,会先消耗掉窗口,紧接着主
14051
- * effect 的判定就被挡下,反而不会重新请求。
14052
- *
14053
- * 探测本身很廉价:Host 比对配置指纹后,配置没变就直接返回缓存,不会重启 CLI。
14054
- * 真实第三方接入会长期停在该状态,因此轮询持续存在,代价是每分钟一次缓存命中的
14055
- * RPC;这换取的是用户切换供应商后无需刷新页面。
14056
- */
14057
- (0, react.useEffect)(() => {
14058
- if (!serviceTierRevalidation) return;
14059
- const timer = setInterval(() => {
14060
- setCatalogRetry((value) => value + 1);
14061
- }, MODEL_CATALOG_REVALIDATE_INTERVAL_MS + 5e3);
14062
- return () => clearInterval(timer);
14063
- }, [selection.adapterId, serviceTierRevalidation]);
14174
+ (0, react.useEffect)(() => subscribeAdapterCatalogChanged(props.rpc, () => setCatalogRetry((value) => value + 1)), [props.rpc]);
14064
14175
  (0, react.useEffect)(() => {
14065
14176
  if (selection.adapterId === "dsh") setOpen(false);
14066
14177
  }, [selection.adapterId]);
@@ -14256,6 +14367,7 @@ window.__ModuleLoader__.load({
14256
14367
  }
14257
14368
  var CLI_STYLE_ID, CIRCULAR_PROVIDER_ICON_IDS, DEFAULT_SELECTION, selections, selectionListeners, selectionLastUsed, MAX_SELECTION_CACHE, selectionLoads, selectionUpdates, selectionRevisions, agentRootStyle, agentTriggerStyle, agentTriggerIconStyle, agentTriggerLabelStyle, nativeDropdownChevronStyle, agentMenuStyle, agentOptionStyle, agentCheckStyle, agentOptionIconStyle, agentOptionLabelStyle, agentStatusStyle, agentFallbackIconStyle, nativeTriggerStyle, modelNameStyle, nativeMenuStyle, nativeMenuCellStyle, serviceTierRowStyle, serviceTierLabelStyle, nativeMenuLabelStyle, nativeMenuValueStyle, nativeChevronStyle, nativeBackStyle, nativeGroupTitleStyle, nativeOptionStyle, modelSpinnerStyle, modelLoadingMenuStyle;
14258
14369
  var init_cli_slots = __esmMin((() => {
14370
+ init_adapter_catalog_watch();
14259
14371
  init_popup_dismiss();
14260
14372
  init_cli_catalog();
14261
14373
  init_service_tier();
@@ -14540,6 +14652,9 @@ window.__ModuleLoader__.load({
14540
14652
  init_popup_dismiss();
14541
14653
  init_session_adapter_cache();
14542
14654
  init_provider_icons();
14655
+ init_adapter_catalog_watch();
14656
+ init_model_catalog_cache();
14657
+ init_primitives_adapter();
14543
14658
  const CLI_ADAPTER_STYLE_ID = "codingns4dsh-cli-adapter-settings-style";
14544
14659
  const cliAdapterClass = {
14545
14660
  panel: "codingns4dsh-cli-adapter-panel",
@@ -14553,7 +14668,8 @@ window.__ModuleLoader__.load({
14553
14668
  metadata: "codingns4dsh-cli-adapter-metadata",
14554
14669
  status: "codingns4dsh-cli-adapter-status",
14555
14670
  version: "codingns4dsh-cli-adapter-version",
14556
- toggle: "codingns4dsh-cli-adapter-toggle"
14671
+ toggle: "codingns4dsh-cli-adapter-toggle",
14672
+ detectButton: "codingns4dsh-cli-adapter-detect-button"
14557
14673
  };
14558
14674
  /** 设置页 Agent 行的响应式布局;内联样式无法表达移动端换行规则,因此集中注入。 */
14559
14675
  function installCliAdapterStyles() {
@@ -14576,6 +14692,13 @@ window.__ModuleLoader__.load({
14576
14692
  .${cliAdapterClass.status}{padding:3px 7px;border-radius:5px;background:var(--dsw-alias-state-success-bg,rgba(22,163,74,.12))}
14577
14693
  .${cliAdapterClass.toggle}{display:inline-flex;align-items:center;gap:7px;flex:0 0 auto;color:var(--dsw-alias-label-secondary,GrayText);font-size:13px;font-weight:500}
14578
14694
  .${cliAdapterClass.toggle} input{width:18px;height:18px;margin:0;accent-color:var(--dsw-alias-state-success-primary,#16a34a)}
14695
+ .${cliAdapterClass.detectButton}{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:32px;height:32px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary,GrayText);cursor:pointer}
14696
+ .${cliAdapterClass.detectButton}:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}
14697
+ .${cliAdapterClass.detectButton}:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#1677ff);outline-offset:2px}
14698
+ .${cliAdapterClass.detectButton}:disabled{opacity:.45;cursor:not-allowed}
14699
+ .${cliAdapterClass.detectButton}[aria-busy="true"] svg{animation:codingns-cli-detect-spin 1s linear infinite}
14700
+ @keyframes codingns-cli-detect-spin{to{transform:rotate(360deg)}}
14701
+ @media (prefers-reduced-motion:reduce){.${cliAdapterClass.detectButton}[aria-busy="true"] svg{animation:none}}
14579
14702
  @media (max-width:768px){
14580
14703
  .${cliAdapterClass.row}{display:grid!important;grid-template-columns:minmax(0,1fr) auto;align-items:center!important;gap:7px 10px!important;min-height:0!important;padding:12px 14px!important}
14581
14704
  .${cliAdapterClass.main}{grid-column:1 / -1;display:flex!important;align-items:center!important;width:100%;gap:10px!important}
@@ -14585,6 +14708,7 @@ window.__ModuleLoader__.load({
14585
14708
  .${cliAdapterClass.status},.${cliAdapterClass.version}{max-width:100%;min-width:0!important}
14586
14709
  .${cliAdapterClass.toggle}{grid-column:2;grid-row:2;justify-self:end;align-self:center;min-width:0;max-width:100%;white-space:nowrap}
14587
14710
  .${cliAdapterClass.toggle} span{max-width:7em;overflow:hidden;text-overflow:ellipsis}
14711
+ .${cliAdapterClass.row}>.${cliAdapterClass.detectButton}{grid-column:1;grid-row:2;justify-self:start}
14588
14712
  }
14589
14713
  `;
14590
14714
  document.head.appendChild(style);
@@ -14647,27 +14771,24 @@ window.__ModuleLoader__.load({
14647
14771
  const [busyAdapterId, setBusyAdapterId] = (0, react.useState)(null);
14648
14772
  const [bridgeBusy, setBridgeBusy] = (0, react.useState)(false);
14649
14773
  const [modelsError, setModelsError] = (0, react.useState)("");
14774
+ const [detecting, setDetecting] = (0, react.useState)(null);
14650
14775
  const disabled = !enabled;
14651
14776
  (0, react.useEffect)(() => {
14652
14777
  installCliAdapterStyles();
14653
14778
  }, []);
14654
14779
  (0, react.useEffect)(() => {
14655
14780
  if (disabled) return;
14656
- let active = true;
14657
14781
  setLoading(true);
14658
- callCliRpc(services.rpc, "catalog", {}).then((value) => {
14659
- if (active) setCatalog(value);
14660
- }).catch((error) => {
14661
- if (active) notify({
14782
+ return watchAdapterCatalog(services.rpc, void 0, (value) => {
14783
+ setCatalog(value);
14784
+ setLoading(false);
14785
+ }, (error) => {
14786
+ setLoading(false);
14787
+ notify({
14662
14788
  kind: "error",
14663
14789
  message: errorMessage$7(error)
14664
14790
  });
14665
- }).finally(() => {
14666
- if (active) setLoading(false);
14667
14791
  });
14668
- return () => {
14669
- active = false;
14670
- };
14671
14792
  }, [disabled, services.rpc]);
14672
14793
  (0, react.useEffect)(() => {
14673
14794
  if (selected === null || disabled || !selected.installed || !selected.enabled) {
@@ -14701,6 +14822,24 @@ window.__ModuleLoader__.load({
14701
14822
  ...dshSettingsButtonStyle,
14702
14823
  cursor: disabled ? "not-allowed" : "pointer"
14703
14824
  };
14825
+ const redetect = async (adapterId) => {
14826
+ if (detecting !== null) return;
14827
+ setDetecting(adapterId ?? "*");
14828
+ try {
14829
+ const value = await callCliRpc(services.rpc, "catalog/refresh", adapterId === void 0 ? {} : { adapterId });
14830
+ invalidateModelCatalogCache(services.rpc, adapterId);
14831
+ setCatalog(value);
14832
+ setSelected((current) => current === null ? null : value.find((entry) => entry.id === current.id) ?? null);
14833
+ notifyAdapterCatalogChanged(services.rpc);
14834
+ } catch (error) {
14835
+ notify({
14836
+ kind: "error",
14837
+ message: catalogRefreshErrorMessage(error, t)
14838
+ });
14839
+ } finally {
14840
+ setDetecting(null);
14841
+ }
14842
+ };
14704
14843
  const bridgeEnabled = snapshot.value?.subagentBridge?.enabled === true;
14705
14844
  const bridgeWritable = snapshot.status !== "loading" && snapshot.writable;
14706
14845
  const bridgeConcurrency = normalizeSubagentBridgeSettings(snapshot.value?.subagentBridge).maxConcurrentSubagents;
@@ -14774,6 +14913,7 @@ window.__ModuleLoader__.load({
14774
14913
  });
14775
14914
  const refreshed = await callCliRpc(services.rpc, "catalog", {});
14776
14915
  setCatalog(refreshed);
14916
+ notifyAdapterCatalogChanged(services.rpc);
14777
14917
  notify({
14778
14918
  kind: "success",
14779
14919
  message: t(next ? "cli.adapterEnabled" : "cli.adapterDisabled", { name: adapter.name })
@@ -14859,7 +14999,20 @@ window.__ModuleLoader__.load({
14859
14999
  })), loading && (0, react.createElement)("div", { role: "status" }, t("cli.readingAgents")), !loading && catalog.length === 0 && (0, react.createElement)("div", {
14860
15000
  role: "status",
14861
15001
  style: { opacity: .7 }
14862
- }, t("cli.noAgents")), (0, react.createElement)("div", { className: cliAdapterClass.listHeader }, (0, react.createElement)("span", void 0, t("cli.agentList")), catalog.length > 0 && (0, react.createElement)("span", void 0, t("cli.agentCount", { count: catalog.length }))), (0, react.createElement)("div", { className: cliAdapterClass.listCard }, ...catalog.map((adapter) => (0, react.createElement)("div", {
15002
+ }, t("cli.noAgents")), (0, react.createElement)("div", { className: cliAdapterClass.listHeader }, (0, react.createElement)("span", void 0, t("cli.agentList")), (0, react.createElement)("div", { style: {
15003
+ display: "flex",
15004
+ alignItems: "center",
15005
+ gap: 8,
15006
+ marginLeft: "auto",
15007
+ flex: "0 0 auto"
15008
+ } }, catalog.length > 0 && (0, react.createElement)("span", void 0, t("cli.agentCount", { count: catalog.length })), (0, react.createElement)(AdapterDetectButton, {
15009
+ label: t(detecting === "*" ? "cli.detecting" : "cli.redetectAll"),
15010
+ busy: detecting === "*",
15011
+ disabled: disabled || detecting !== null,
15012
+ onClick: () => {
15013
+ redetect();
15014
+ }
15015
+ }))), (0, react.createElement)("div", { className: cliAdapterClass.listCard }, ...catalog.map((adapter) => (0, react.createElement)("div", {
14863
15016
  key: adapter.id,
14864
15017
  className: cliAdapterClass.row
14865
15018
  }, (0, react.createElement)("button", {
@@ -14889,7 +15042,14 @@ window.__ModuleLoader__.load({
14889
15042
  color: adapter.installed ? dshThemeColor.success : dshThemeColor.labelTertiary,
14890
15043
  background: adapter.installed ? "rgba(22,163,74,.12)" : dshThemeColor.surfaceSubtle
14891
15044
  }
14892
- }, adapter.installed ? t("cli.installed") : t("cli.notInstalled")), (0, react.createElement)("span", { className: cliAdapterClass.version }, adapter.version ?? t("cli.notDetectedVersion"))))), (0, react.createElement)("label", {
15045
+ }, adapterStatus(adapter, t)), (0, react.createElement)("span", { className: cliAdapterClass.version }, adapter.version ?? t("cli.notDetectedVersion"))))), (0, react.createElement)(AdapterDetectButton, {
15046
+ label: `${adapter.name} · ${t(detecting === adapter.id || detecting === "*" ? "cli.detecting" : "cli.redetect")}`,
15047
+ busy: detecting === adapter.id || detecting === "*",
15048
+ disabled: disabled || detecting !== null,
15049
+ onClick: () => {
15050
+ redetect(adapter.id);
15051
+ }
15052
+ }), (0, react.createElement)("label", {
14893
15053
  className: cliAdapterClass.toggle,
14894
15054
  style: {
14895
15055
  display: "inline-flex",
@@ -14917,6 +15077,26 @@ window.__ModuleLoader__.load({
14917
15077
  }));
14918
15078
  }
14919
15079
  const CIRCULAR_ADAPTER_ICON_IDS = /* @__PURE__ */ new Set(["gemini", "grok"]);
15080
+ /** 顶部和单个 Agent 共用刷新图标;文字保留在悬停提示和无障碍名称中。 */
15081
+ function AdapterDetectButton({ label, busy, disabled, onClick }) {
15082
+ return (0, react.createElement)("button", {
15083
+ type: "button",
15084
+ className: cliAdapterClass.detectButton,
15085
+ title: label,
15086
+ "aria-label": label,
15087
+ "aria-busy": busy,
15088
+ disabled,
15089
+ onClick
15090
+ }, (0, react.createElement)("span", {
15091
+ "aria-hidden": true,
15092
+ style: { display: "inline-flex" }
15093
+ }, (0, react.createElement)(resolveRefreshIcon(), { size: 18 })));
15094
+ }
15095
+ function adapterStatus(adapter, t) {
15096
+ if (adapter.detectionState === "pending" || adapter.detectionState === "running") return t("cli.detecting");
15097
+ if (adapter.detectionState === "error") return t("cli.detectionFailed");
15098
+ return t(adapter.installed ? "cli.installed" : "cli.notInstalled");
15099
+ }
14920
15100
  /** 设置页列表中的 Agent logo;资产缺失时用首字母占位,避免出现破图或空白。 */
14921
15101
  function AdapterIcon({ adapter }) {
14922
15102
  const icon = providerIconUrl(adapter.id);
@@ -14987,7 +15167,7 @@ window.__ModuleLoader__.load({
14987
15167
  gridTemplateColumns: "max-content 1fr",
14988
15168
  gap: "8px 16px",
14989
15169
  margin: "20px 0"
14990
- } }, (0, react.createElement)("dt", void 0, t("cli.installStatus")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapter.installed ? t("cli.installed") : t("cli.notInstalled")), (0, react.createElement)("dt", void 0, t("cli.enabledStatus")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapter.enabled ? t("cli.enabled") : t("cli.disabled")), (0, react.createElement)("dt", void 0, t("cli.version")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapter.version ?? t("cli.notDetectedVersion")), (0, react.createElement)("dt", void 0, t("cli.commandPath")), (0, react.createElement)("dd", { style: {
15170
+ } }, (0, react.createElement)("dt", void 0, t("cli.installStatus")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapterStatus(adapter, t)), (0, react.createElement)("dt", void 0, t("cli.enabledStatus")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapter.enabled ? t("cli.enabled") : t("cli.disabled")), (0, react.createElement)("dt", void 0, t("cli.version")), (0, react.createElement)("dd", { style: { margin: 0 } }, adapter.version ?? t("cli.notDetectedVersion")), (0, react.createElement)("dt", void 0, t("cli.commandPath")), (0, react.createElement)("dd", { style: {
14991
15171
  margin: 0,
14992
15172
  overflowWrap: "anywhere"
14993
15173
  } }, adapter.command ?? t("cli.notDetectedCommand")), adapter.diagnostic && (0, react.createElement)("dt", void 0, t("cli.diagnostic")), adapter.diagnostic && (0, react.createElement)("dd", { style: {
@@ -17273,6 +17453,52 @@ window.__ModuleLoader__.load({
17273
17453
  }));
17274
17454
  }
17275
17455
  //#endregion
17456
+ //#region src/client/serial-polling.ts
17457
+ /**
17458
+ * 完成后再计时,失败逐步退避;隐藏页面暂停,销毁时取消在途请求。
17459
+ * 手动刷新复用在途 Promise,避免慢 Host 上请求越积越多。
17460
+ */
17461
+ function startSerialPolling(task, intervalMs, options = {}) {
17462
+ const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
17463
+ const lifetime = new AbortController();
17464
+ let timer;
17465
+ let pending;
17466
+ let failures = 0;
17467
+ const refresh = () => {
17468
+ if (lifetime.signal.aborted) return Promise.resolve();
17469
+ if (pending !== void 0) return pending;
17470
+ clearTimeout(timer);
17471
+ const signal = AbortSignal.any([lifetime.signal, AbortSignal.timeout(options.timeoutMs ?? 15e3)]);
17472
+ pending = Promise.resolve().then(() => task(signal)).then((success) => {
17473
+ failures = success === false ? failures + 1 : 0;
17474
+ }, () => {
17475
+ failures += 1;
17476
+ }).finally(() => {
17477
+ pending = void 0;
17478
+ if (lifetime.signal.aborted || intervalMs <= 0 || dom?.visibilityState === "hidden") return;
17479
+ const delay = Math.min(intervalMs * 2 ** Math.min(failures, 4), options.maxDelayMs ?? Math.max(intervalMs, 6e4));
17480
+ timer = setTimeout(() => {
17481
+ refresh();
17482
+ }, delay);
17483
+ });
17484
+ return pending;
17485
+ };
17486
+ const visible = () => {
17487
+ clearTimeout(timer);
17488
+ if (dom?.visibilityState !== "hidden") refresh();
17489
+ };
17490
+ dom?.addEventListener("visibilitychange", visible);
17491
+ visible();
17492
+ return {
17493
+ refresh,
17494
+ dispose() {
17495
+ lifetime.abort();
17496
+ clearTimeout(timer);
17497
+ dom?.removeEventListener("visibilitychange", visible);
17498
+ }
17499
+ };
17500
+ }
17501
+ //#endregion
17276
17502
  //#region src/client/subscription-slot.ts
17277
17503
  init_cli_catalog();
17278
17504
  init_locale();
@@ -17291,11 +17517,35 @@ window.__ModuleLoader__.load({
17291
17517
  subscribe: () => () => {},
17292
17518
  register: () => () => {}
17293
17519
  };
17294
- /**
17295
- * 进程内用量结果缓存:同一适配器/提供商在刷新间隔内直接复用上次结果,
17296
- * 避免每次进入会话或切回同一 Agent 都请求上游;null 结果不缓存,便于刚登录后立刻重试。
17297
- */
17298
- const subscriptionUsageCache = /* @__PURE__ */ new Map();
17520
+ const usageCaches = /* @__PURE__ */ new WeakMap();
17521
+ const usageLoads = /* @__PURE__ */ new WeakMap();
17522
+ function usageCache(rpc) {
17523
+ let cache = usageCaches.get(rpc);
17524
+ if (cache === void 0) {
17525
+ cache = /* @__PURE__ */ new Map();
17526
+ usageCaches.set(rpc, cache);
17527
+ }
17528
+ return cache;
17529
+ }
17530
+ /** 重置影响同一账号的所有模型额度,不能只删除不含模型的旧缓存键。 */
17531
+ function invalidateSubscriptionUsageCache(cache, adapterId, providerId) {
17532
+ const prefix = `${adapterId}|${providerId ?? ""}|`;
17533
+ for (const key of cache.keys()) if (key.startsWith(prefix)) cache.delete(key);
17534
+ }
17535
+ function loadUsage(rpc, key, payload) {
17536
+ let loads = usageLoads.get(rpc);
17537
+ if (loads === void 0) {
17538
+ loads = /* @__PURE__ */ new Map();
17539
+ usageLoads.set(rpc, loads);
17540
+ }
17541
+ const existing = loads.get(key);
17542
+ if (existing !== void 0) return existing;
17543
+ const request = callCliRpc(rpc, "subscription", payload, AbortSignal.timeout(3e4)).finally(() => {
17544
+ if (loads.get(key) === request) loads.delete(key);
17545
+ });
17546
+ loads.set(key, request);
17547
+ return request;
17548
+ }
17299
17549
  /** 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。 */
17300
17550
  function installSubscriptionStyles() {
17301
17551
  if (typeof document === "undefined" || document.querySelector(`style[data-plugin-css="${SUBSCRIPTION_STYLE_ID}"]`) !== null) return;
@@ -17324,6 +17574,7 @@ window.__ModuleLoader__.load({
17324
17574
  }
17325
17575
  function CommandCodeSubscriptionSlot(props) {
17326
17576
  const t = useCodingNsTranslator(props.locale ?? FALLBACK_LOCALE);
17577
+ const subscriptionUsageCache = usageCache(props.rpc);
17327
17578
  const [usage, setUsage] = (0, react.useState)(null);
17328
17579
  const [adapterId, setAdapterId] = (0, react.useState)(null);
17329
17580
  const [providerId, setProviderId] = (0, react.useState)(null);
@@ -17367,10 +17618,10 @@ window.__ModuleLoader__.load({
17367
17618
  setResetPending(false);
17368
17619
  setResetResult(null);
17369
17620
  setResetError(null);
17370
- const refresh = async () => {
17621
+ const refresh = async (signal) => {
17371
17622
  setLoading(true);
17372
17623
  try {
17373
- const selection = await callCliRpc(props.rpc, "session/get", { sessionId });
17624
+ const selection = await callCliRpc(props.rpc, "session/get", { sessionId }, signal);
17374
17625
  const adapterId = selection.adapterId;
17375
17626
  if (!active || !isSubscriptionAdapter(adapterId)) {
17376
17627
  if (active) {
@@ -17393,7 +17644,7 @@ window.__ModuleLoader__.load({
17393
17644
  if (active) setUsage(cached.usage);
17394
17645
  return;
17395
17646
  }
17396
- const next = await callCliRpc(props.rpc, "subscription", {
17647
+ const next = await loadUsage(props.rpc, cacheKey, {
17397
17648
  adapterId,
17398
17649
  ...selection.providerId ? { providerId: selection.providerId } : {},
17399
17650
  ...selection.modelId ? { modelId: selection.modelId } : {}
@@ -17408,20 +17659,18 @@ window.__ModuleLoader__.load({
17408
17659
  setEligible(false);
17409
17660
  setUsage(null);
17410
17661
  }
17662
+ return false;
17411
17663
  } finally {
17412
17664
  if (active) setLoading(false);
17413
17665
  }
17414
17666
  };
17415
- refreshRef.current = refresh;
17416
- refresh();
17417
17667
  const intervalMins = props.getRefreshIntervalMins?.() ?? DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
17418
- const timer = intervalMins > 0 ? globalThis.setInterval(() => {
17419
- refresh();
17420
- }, intervalMins * 6e4) : void 0;
17668
+ const poll = startSerialPolling(refresh, Math.max(0, intervalMins) * 6e4, { timeoutMs: 3e4 });
17669
+ refreshRef.current = poll.refresh;
17421
17670
  return () => {
17422
17671
  active = false;
17423
17672
  refreshRef.current = null;
17424
- if (timer !== void 0) globalThis.clearInterval(timer);
17673
+ poll.dispose();
17425
17674
  };
17426
17675
  }, [
17427
17676
  props.rpc,
@@ -17443,7 +17692,6 @@ window.__ModuleLoader__.load({
17443
17692
  };
17444
17693
  const confirmReset = () => {
17445
17694
  if (resetPending || adapterId === null) return;
17446
- const cacheKey = `${adapterId}|${providerId ?? ""}`;
17447
17695
  setResetPending(true);
17448
17696
  setResetError(null);
17449
17697
  (async () => {
@@ -17453,7 +17701,7 @@ window.__ModuleLoader__.load({
17453
17701
  ...providerId === null ? {} : { providerId }
17454
17702
  });
17455
17703
  setResetResult(result.outcome);
17456
- subscriptionUsageCache.delete(cacheKey);
17704
+ invalidateSubscriptionUsageCache(subscriptionUsageCache, adapterId, providerId);
17457
17705
  await refreshRef.current?.();
17458
17706
  } catch (error) {
17459
17707
  setResetError(error instanceof Error ? error.message : "");
@@ -20013,7 +20261,7 @@ window.__ModuleLoader__.load({
20013
20261
  let archiveDom;
20014
20262
  let visibilityDom;
20015
20263
  let rightbarDom;
20016
- let adapterRefreshTimer;
20264
+ let disposeAdapterRefresh;
20017
20265
  let disposeSubscription;
20018
20266
  let disposeQuickPhrases;
20019
20267
  let disposeSkillCommand;
@@ -20023,10 +20271,8 @@ window.__ModuleLoader__.load({
20023
20271
  generation += 1;
20024
20272
  logoDom?.dispose();
20025
20273
  logoDom = void 0;
20026
- if (adapterRefreshTimer !== void 0) {
20027
- globalThis.clearInterval(adapterRefreshTimer);
20028
- adapterRefreshTimer = void 0;
20029
- }
20274
+ disposeAdapterRefresh?.();
20275
+ disposeAdapterRefresh = void 0;
20030
20276
  clearSessionAdapters();
20031
20277
  };
20032
20278
  const enableArchive = () => {
@@ -20113,16 +20359,44 @@ window.__ModuleLoader__.load({
20113
20359
  if (logoDom !== void 0) return;
20114
20360
  const currentGeneration = ++generation;
20115
20361
  logoDom = startWorkspaceSessionLogoDom({ locale: context.services.locale });
20362
+ let refreshing = false;
20363
+ let dirty = false;
20116
20364
  const refreshAdapters = () => {
20365
+ if (refreshing) {
20366
+ dirty = true;
20367
+ return;
20368
+ }
20369
+ refreshing = true;
20117
20370
  fetchSessionAdapters(context.services.rpc).then((bindings) => {
20118
20371
  if (generation !== currentGeneration || logoDom === void 0) return;
20119
20372
  replaceSessionAdapters(bindings);
20120
20373
  logoDom.refresh();
20121
20374
  archiveDom?.refresh();
20122
- }).catch(() => void 0);
20375
+ }).catch(() => void 0).finally(() => {
20376
+ refreshing = false;
20377
+ if (dirty && generation === currentGeneration) {
20378
+ dirty = false;
20379
+ refreshAdapters();
20380
+ }
20381
+ });
20123
20382
  };
20124
20383
  refreshAdapters();
20125
- adapterRefreshTimer = globalThis.setInterval(refreshAdapters, 2e3);
20384
+ const store = readNativeWorkspaceListStore(context.services.uiContext);
20385
+ let membership = "";
20386
+ const removeStore = store?.subscribe(() => {
20387
+ const snapshot = readNativeWorkspaceSnapshot(context.services.uiContext);
20388
+ const next = JSON.stringify(snapshot?.items.map((item) => [item.workspaceId, item.sessionIds]));
20389
+ if (next === membership) return;
20390
+ membership = next ?? "";
20391
+ refreshAdapters();
20392
+ });
20393
+ globalThis.addEventListener?.("popstate", refreshAdapters);
20394
+ globalThis.addEventListener?.("focus", refreshAdapters);
20395
+ disposeAdapterRefresh = () => {
20396
+ removeStore?.();
20397
+ globalThis.removeEventListener?.("popstate", refreshAdapters);
20398
+ globalThis.removeEventListener?.("focus", refreshAdapters);
20399
+ };
20126
20400
  };
20127
20401
  const sync = () => {
20128
20402
  const workspaceSettings = context.services.settings.getSnapshot().value?.workspaceSessionEnhancement;
@@ -21913,17 +22187,30 @@ ${scope} [data-dockkit-strip-tabs] {
21913
22187
  };
21914
22188
  (0, react.useEffect)(() => {
21915
22189
  let disposed = false;
22190
+ setWorkspaceId(null);
22191
+ setConfig(null);
22192
+ setInstances([]);
22193
+ setBindings([]);
21916
22194
  setPortChecks({});
22195
+ setDraft(null);
22196
+ setTerminalStatus(null);
22197
+ setMessage({
22198
+ text: t("debug.readingWorkspace"),
22199
+ tone: "info"
22200
+ });
21917
22201
  const terminal = terminalRemote?.();
21918
- call$2(rpc, "terminal/status", {}).then((status) => {
21919
- if (!disposed) setTerminalStatus(status);
21920
- }).catch(() => {});
21921
22202
  (async () => {
21922
22203
  try {
21923
22204
  const id = readWorkspaceId(await terminal?.environment?.(String(sessionId)));
21924
22205
  if (id === null) throw new Error("当前 Session 没有关联 Workspace");
21925
22206
  if (disposed) return;
21926
22207
  setWorkspaceId(id);
22208
+ call$2(rpc, "terminal/status", {
22209
+ sessionId: String(sessionId),
22210
+ workspaceId: id
22211
+ }).then((status) => {
22212
+ if (!disposed) setTerminalStatus(status);
22213
+ }).catch(() => {});
21927
22214
  await load(id, () => !disposed);
21928
22215
  } catch (error) {
21929
22216
  if (!disposed) setMessage({
@@ -22080,6 +22367,7 @@ ${scope} [data-dockkit-strip-tabs] {
22080
22367
  await withBusy(async () => {
22081
22368
  const result = await call$2(rpc, "debug/profile/launch", {
22082
22369
  sessionId: String(sessionId),
22370
+ dshSessionId: String(sessionId),
22083
22371
  workspaceId,
22084
22372
  generation: 0,
22085
22373
  profileId: profile.id,
@@ -23269,6 +23557,7 @@ ${scope} [data-dockkit-strip-tabs] {
23269
23557
  init_debug();
23270
23558
  init_theme();
23271
23559
  init_locale();
23560
+ init_peer_host();
23272
23561
  function SegmentedControl({ id, value, options, onChange, label, disabled }) {
23273
23562
  const index = Math.max(0, options.findIndex((option) => option.value === value));
23274
23563
  return (0, react.createElement)("div", {
@@ -23328,6 +23617,7 @@ ${scope} [data-dockkit-strip-tabs] {
23328
23617
  inject: () => ({
23329
23618
  rpc: services.rpc,
23330
23619
  remote: services.remote,
23620
+ uiContext: ctx,
23331
23621
  t
23332
23622
  })
23333
23623
  }, GitPanel)));
@@ -23342,10 +23632,11 @@ ${scope} [data-dockkit-strip-tabs] {
23342
23632
  order: 990,
23343
23633
  inject: () => ({
23344
23634
  remote: services.remote,
23635
+ uiContext: ctx,
23345
23636
  sidebarRight
23346
23637
  })
23347
23638
  }, GitWorkspaceRecovery)));
23348
- if (typeof sidebarRight.registerCloseHandler === "function") disposers.push(sidebarRight.registerCloseHandler("git", (sessionId, tab) => closeGitWorkspaceTabs(sidebarRight, services.remote, sessionId, tab)));
23639
+ if (typeof sidebarRight.registerCloseHandler === "function") disposers.push(sidebarRight.registerCloseHandler("git", (sessionId, tab) => closeGitWorkspaceTabs(sidebarRight, services.remote, sessionId, tab, ctx)));
23349
23640
  } catch (error) {
23350
23641
  for (const dispose of disposers.reverse()) dispose();
23351
23642
  if (isDuplicateGitRegistration(error)) {
@@ -23391,6 +23682,8 @@ ${scope} [data-dockkit-strip-tabs] {
23391
23682
  const sessionId = String(props.sessionId);
23392
23683
  const t = props.t;
23393
23684
  const tabInfo = props.useTabInfo();
23685
+ useGitWorkspaceSnapshot(props.uiContext);
23686
+ const projectedWorkspaceId = readNativeWorkspaceSnapshot(props.uiContext)?.items.find((item) => item.sessionIds.includes(sessionId))?.workspaceId;
23394
23687
  const [workspaceId, setWorkspaceId] = (0, react.useState)();
23395
23688
  const [status, setStatus] = (0, react.useState)(null);
23396
23689
  const [history, setHistory] = (0, react.useState)([]);
@@ -23449,7 +23742,7 @@ ${scope} [data-dockkit-strip-tabs] {
23449
23742
  setBranches(null);
23450
23743
  setDiffView(null);
23451
23744
  setFileDiff(null);
23452
- const load = async (resolvedWorkspaceId) => {
23745
+ const load = async (resolvedWorkspaceId, signal) => {
23453
23746
  const cached = readCache(resolvedWorkspaceId);
23454
23747
  if (cached !== null && !historyExpanded.current) {
23455
23748
  setStatus(cached.status);
@@ -23458,7 +23751,7 @@ ${scope} [data-dockkit-strip-tabs] {
23458
23751
  setBranches(cached.branches);
23459
23752
  }
23460
23753
  try {
23461
- const nextStatus = await call$1(props.rpc, "git/status", { workspaceId: resolvedWorkspaceId });
23754
+ const nextStatus = await call$1(props.rpc, "git/status", { workspaceId: resolvedWorkspaceId }, signal);
23462
23755
  if (disposed) return;
23463
23756
  if (nextStatus.snapshot.enabled === false) {
23464
23757
  setStatus(nextStatus);
@@ -23479,7 +23772,7 @@ ${scope} [data-dockkit-strip-tabs] {
23479
23772
  limit: INITIAL_HISTORY_LIMIT,
23480
23773
  offset: 0,
23481
23774
  scope: historyScope
23482
- }), call$1(props.rpc, "git/branches", { workspaceId: resolvedWorkspaceId })]);
23775
+ }, signal), call$1(props.rpc, "git/branches", { workspaceId: resolvedWorkspaceId }, signal)]);
23483
23776
  if (disposed) return;
23484
23777
  const normalizedBranches = normalizeBranchSnapshot(nextBranches);
23485
23778
  if (nextHistory !== null) {
@@ -23496,9 +23789,10 @@ ${scope} [data-dockkit-strip-tabs] {
23496
23789
  setBranches(normalizedBranches);
23497
23790
  } catch (error) {
23498
23791
  if (!disposed) notify("error", error instanceof Error ? error.message : String(error));
23792
+ return false;
23499
23793
  }
23500
23794
  };
23501
- resolveGitWorkspaceId(props.remote, sessionId).then((resolvedWorkspaceId) => {
23795
+ resolveGitWorkspaceId(props.remote, sessionId, props.uiContext).then((resolvedWorkspaceId) => {
23502
23796
  if (disposed) return;
23503
23797
  if (resolvedWorkspaceId === void 0) {
23504
23798
  notify("error", t("git.noWorkspace"));
@@ -23507,11 +23801,8 @@ ${scope} [data-dockkit-strip-tabs] {
23507
23801
  rememberGitWorkspaceSession(sessionId, resolvedWorkspaceId);
23508
23802
  writeGitWorkspaceOpen(resolvedWorkspaceId, true);
23509
23803
  setWorkspaceId(resolvedWorkspaceId);
23510
- load(resolvedWorkspaceId);
23511
- const timer = globalThis.setInterval(() => {
23512
- load(resolvedWorkspaceId);
23513
- }, 5e3);
23514
- cleanupTimer = () => globalThis.clearInterval(timer);
23804
+ const poll = startSerialPolling((signal) => load(resolvedWorkspaceId, signal), 5e3);
23805
+ cleanupTimer = () => poll.dispose();
23515
23806
  }).catch((error) => {
23516
23807
  if (!disposed) notify("error", error instanceof Error ? error.message : String(error));
23517
23808
  });
@@ -23522,8 +23813,10 @@ ${scope} [data-dockkit-strip-tabs] {
23522
23813
  }, [
23523
23814
  props.remote,
23524
23815
  props.rpc,
23816
+ props.uiContext,
23525
23817
  sessionId,
23526
- historyScope
23818
+ historyScope,
23819
+ projectedWorkspaceId
23527
23820
  ]);
23528
23821
  (0, react.useEffect)(() => {
23529
23822
  const close = () => {
@@ -24577,8 +24870,9 @@ ${scope} [data-dockkit-strip-tabs] {
24577
24870
  const GIT_WORKSPACE_STATE_EVENT = "codingns4dsh-git-workspace-state";
24578
24871
  const workspaceBySession = /* @__PURE__ */ new Map();
24579
24872
  const closingWorkspaces = /* @__PURE__ */ new Set();
24580
- function GitWorkspaceRecovery({ useSessions, remote, sidebarRight }) {
24873
+ function GitWorkspaceRecovery({ useSessions, remote, uiContext, sidebarRight }) {
24581
24874
  const sessionsSnapshot = useSessions((value) => value);
24875
+ const workspaceSnapshot = useGitWorkspaceSnapshot(uiContext);
24582
24876
  const [workspaceRevision, setWorkspaceRevision] = (0, react.useState)(0);
24583
24877
  const openTabs = readGitOpenTabs(sidebarRight);
24584
24878
  const openTabSnapshot = (0, react.useSyncExternalStore)(openTabs?.subscribe ?? noSubscribe$1, openTabs?.getSnapshot ?? noOpenTabs$1, openTabs?.getSnapshot ?? noOpenTabs$1);
@@ -24597,10 +24891,10 @@ ${scope} [data-dockkit-strip-tabs] {
24597
24891
  if (typeof sidebarRight.openTabIn !== "function") return;
24598
24892
  let disposed = false;
24599
24893
  const recover = async () => {
24600
- const workspaceItems = await readWorkspaceItems(remote?.workspace);
24894
+ const workspaceItems = await readWorkspaceItems(remote?.workspace, uiContext);
24601
24895
  const allSessionIds = [.../* @__PURE__ */ new Set([...sessionIds, ...workspaceItems.flatMap((item) => item.sessionIds)])];
24602
24896
  for (const sessionId of allSessionIds) {
24603
- const workspaceId = await resolveGitWorkspaceId(remote, sessionId).catch(() => void 0);
24897
+ const workspaceId = await resolveGitWorkspaceId(remote, sessionId, uiContext).catch(() => void 0);
24604
24898
  if (disposed || workspaceId === void 0) continue;
24605
24899
  rememberGitWorkspaceSession(sessionId, workspaceId);
24606
24900
  const existing = readGitTabs(sidebarRight, sessionId, openTabSnapshot);
@@ -24621,19 +24915,21 @@ ${scope} [data-dockkit-strip-tabs] {
24621
24915
  }, [
24622
24916
  openTabSnapshot,
24623
24917
  remote,
24918
+ uiContext,
24624
24919
  sessionIds.join("|"),
24625
24920
  sidebarRight,
24626
- workspaceRevision
24921
+ workspaceRevision,
24922
+ workspaceSnapshot
24627
24923
  ]);
24628
24924
  return null;
24629
24925
  }
24630
- function closeGitWorkspaceTabs(sidebar, remote, sessionId, tab) {
24926
+ function closeGitWorkspaceTabs(sidebar, remote, sessionId, tab, uiContext) {
24631
24927
  const knownWorkspaceId = workspaceBySession.get(sessionId);
24632
24928
  if (knownWorkspaceId !== void 0) {
24633
24929
  closeKnownGitWorkspaceTabs(sidebar, knownWorkspaceId, sessionId, tab.id);
24634
24930
  return;
24635
24931
  }
24636
- resolveGitWorkspaceId(remote, sessionId).then((workspaceId) => {
24932
+ resolveGitWorkspaceId(remote, sessionId, uiContext).then((workspaceId) => {
24637
24933
  if (workspaceId === void 0) return;
24638
24934
  rememberGitWorkspaceSession(sessionId, workspaceId);
24639
24935
  closeKnownGitWorkspaceTabs(sidebar, workspaceId, sessionId, tab.id);
@@ -24725,21 +25021,29 @@ ${scope} [data-dockkit-strip-tabs] {
24725
25021
  function noOpenTabs$1() {
24726
25022
  return EMPTY_GIT_OPEN_TABS;
24727
25023
  }
24728
- async function resolveGitWorkspaceId(remote, sessionId) {
25024
+ function useGitWorkspaceSnapshot(uiContext) {
25025
+ const store = readNativeWorkspaceListStore(uiContext);
25026
+ return (0, react.useSyncExternalStore)((listener) => store?.subscribe(listener) ?? noSubscribe$1(), () => store?.getSnapshot(), () => void 0);
25027
+ }
25028
+ async function resolveGitWorkspaceId(remote, sessionId, uiContext) {
24729
25029
  const api = remote;
24730
- const workspaces = await readWorkspaceItems(api?.workspace);
25030
+ const workspaces = await readWorkspaceItems(api?.workspace, uiContext);
24731
25031
  const direct = workspaces.find((item) => item.sessionIds.includes(sessionId));
24732
25032
  if (direct !== void 0) return direct.workspaceId;
25033
+ if (parseVirtualSessionId(sessionId) !== null) return void 0;
25034
+ const localWorkspaces = workspaces.filter((item) => parseVirtualWorkspaceId(item.workspaceId) === null);
24733
25035
  const session = await readCurrentSession(api?.session, sessionId);
24734
25036
  if (session?.workspaceId !== void 0) return session.workspaceId;
24735
25037
  const sessionCwd = session?.cwd;
24736
25038
  if (sessionCwd !== void 0) {
24737
- const byPath = workspaces.filter((item) => item.path !== void 0 && isPathWithin(sessionCwd, item.path)).sort((left, right) => (right.path?.length ?? 0) - (left.path?.length ?? 0))[0];
25039
+ const byPath = localWorkspaces.filter((item) => item.path !== void 0 && isPathWithin(sessionCwd, item.path)).sort((left, right) => (right.path?.length ?? 0) - (left.path?.length ?? 0))[0];
24738
25040
  if (byPath !== void 0) return byPath.workspaceId;
24739
25041
  }
24740
- if (workspaces.length === 1) return workspaces[0]?.workspaceId;
25042
+ if (localWorkspaces.length === 1) return localWorkspaces[0]?.workspaceId;
24741
25043
  }
24742
- async function readWorkspaceItems(api) {
25044
+ async function readWorkspaceItems(api, uiContext) {
25045
+ const snapshot = readNativeWorkspaceSnapshot(uiContext);
25046
+ if (snapshot !== void 0) return snapshot.items;
24743
25047
  if (api?.follow === void 0) return [];
24744
25048
  const iterator = (await api.follow())[Symbol.asyncIterator]();
24745
25049
  const first = await iterator.next();
@@ -24841,13 +25145,13 @@ ${scope} [data-dockkit-strip-tabs] {
24841
25145
  remote
24842
25146
  };
24843
25147
  }
24844
- async function call$1(rpc, endpoint, payload) {
25148
+ async function call$1(rpc, endpoint, payload, signal) {
24845
25149
  let result;
24846
25150
  try {
24847
- result = await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload);
25151
+ result = await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload, signal);
24848
25152
  } catch (error) {
24849
25153
  if (!/HTTP (?:404|405)\b/u.test(error instanceof Error ? error.message : String(error))) throw error;
24850
- result = await rpc.call("/api", `codingns/${endpoint}`, payload);
25154
+ result = await rpc.call("/api", `codingns/${endpoint}`, payload, signal);
24851
25155
  }
24852
25156
  if (!result.ok) throw new Error(result.error.message);
24853
25157
  return result.value;
@@ -59538,7 +59842,8 @@ ${scope} [data-dockkit-strip-tabs] {
59538
59842
  const root = currentDocument;
59539
59843
  const t = resolveCodingNsTranslator(locale);
59540
59844
  let disposed = false;
59541
- let timer;
59845
+ let poll;
59846
+ const lifetime = new AbortController();
59542
59847
  let loginRefreshTimer;
59543
59848
  let loginRefreshInFlight = false;
59544
59849
  let observer;
@@ -59555,13 +59860,14 @@ ${scope} [data-dockkit-strip-tabs] {
59555
59860
  let latency;
59556
59861
  let busy = false;
59557
59862
  const call = async (endpoint, payload) => {
59863
+ const signal = AbortSignal.any([lifetime.signal, AbortSignal.timeout(1e4)]);
59558
59864
  let response;
59559
59865
  try {
59560
- response = await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload);
59866
+ response = await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload, signal);
59561
59867
  } catch (error) {
59562
59868
  const message = error instanceof Error ? error.message : String(error);
59563
59869
  if (!/HTTP (?:404|405)\b/u.test(message)) throw error;
59564
- response = await rpc.call("/api", `codingns/${endpoint}`, payload);
59870
+ response = await rpc.call("/api", `codingns/${endpoint}`, payload, signal);
59565
59871
  }
59566
59872
  if (!response.ok) throw new Error(response.error.message);
59567
59873
  return response.value;
@@ -59571,16 +59877,20 @@ ${scope} [data-dockkit-strip-tabs] {
59571
59877
  const started = performance.now();
59572
59878
  const [nextAuth, nextLocal, nextStatus] = await Promise.allSettled([
59573
59879
  call("auth/snapshot", {}),
59574
- fetchLocalIdentity(root),
59575
- call("host/status", {})
59880
+ fetchLocalIdentity(root, AbortSignal.any([lifetime.signal, AbortSignal.timeout(1e4)])),
59881
+ call("host/status", {}).then((value) => ({
59882
+ value,
59883
+ latency: Math.max(0, Math.round(performance.now() - started))
59884
+ }))
59576
59885
  ]);
59886
+ if (disposed) return;
59577
59887
  if (nextAuth.status === "fulfilled") auth = nextAuth.value;
59578
59888
  local = nextLocal.status === "fulfilled" ? nextLocal.value : null;
59579
59889
  localSessionExpiresAt = local?.expiresAt ?? null;
59580
59890
  localRelay = readRelayLoginIdentity();
59581
59891
  if (nextStatus.status === "fulfilled") {
59582
- status = nextStatus.value;
59583
- latency = Math.max(0, Math.round(performance.now() - started));
59892
+ status = nextStatus.value.value;
59893
+ latency = nextStatus.value.latency;
59584
59894
  }
59585
59895
  renderAll();
59586
59896
  const menu = root.querySelector(`[${MENU_ATTRIBUTE}]`);
@@ -59589,6 +59899,7 @@ ${scope} [data-dockkit-strip-tabs] {
59589
59899
  renderMenu(menu);
59590
59900
  if (button !== null) positionMenuUpperRight(menu, button);
59591
59901
  }
59902
+ return nextStatus.status === "fulfilled" && nextAuth.status === "fulfilled";
59592
59903
  };
59593
59904
  const scan = () => {
59594
59905
  if (disposed) return;
@@ -59703,17 +60014,16 @@ ${scope} [data-dockkit-strip-tabs] {
59703
60014
  renderAll();
59704
60015
  };
59705
60016
  root.defaultView?.addEventListener(LOGIN_PROTECTION_SESSION_EVENT, onLoginProtectionSessionChanged);
59706
- timer = setInterval(() => {
59707
- refresh();
59708
- }, POLL_MS);
60017
+ poll = startSerialPolling(refresh, POLL_MS, { document: root });
59709
60018
  loginRefreshTimer = setInterval(() => {
59710
60019
  refreshLoginProtection();
59711
60020
  }, LOGIN_REFRESH_POLL_MS);
59712
- refresh().then(() => refreshLoginProtection());
60021
+ refreshLoginProtection();
59713
60022
  return { dispose() {
59714
60023
  if (disposed) return;
59715
60024
  disposed = true;
59716
- if (timer !== void 0) clearInterval(timer);
60025
+ lifetime.abort();
60026
+ poll?.dispose();
59717
60027
  if (loginRefreshTimer !== void 0) clearInterval(loginRefreshTimer);
59718
60028
  observer?.disconnect();
59719
60029
  resizeObserver?.disconnect();
@@ -59737,6 +60047,7 @@ ${scope} [data-dockkit-strip-tabs] {
59737
60047
  method: "POST",
59738
60048
  credentials: "same-origin",
59739
60049
  cache: "no-store",
60050
+ signal: AbortSignal.any([lifetime.signal, AbortSignal.timeout(1e4)]),
59740
60051
  headers: { Accept: "application/json" }
59741
60052
  });
59742
60053
  if (!response.ok) local = null;
@@ -59862,8 +60173,8 @@ ${scope} [data-dockkit-strip-tabs] {
59862
60173
  latency
59863
60174
  }), "span"));
59864
60175
  if (status !== void 0) {
59865
- menu.append(resourceRow(root, "CPU", status.cpuPercent));
59866
- menu.append(resourceRow(root, t("accountBar.memory"), status.memoryPercent));
60176
+ menu.append(resourceRow(root, t("accountBar.hostCpu"), status.cpuPercent));
60177
+ menu.append(resourceRow(root, t("accountBar.hostMemory"), status.memoryPercent));
59867
60178
  menu.append(textNode(root, `${formatBytes$1(status.memoryUsedBytes)} / ${formatBytes$1(status.memoryTotalBytes)}`, "span"));
59868
60179
  }
59869
60180
  const peerHost = root.createElement("button");
@@ -59911,10 +60222,11 @@ ${scope} [data-dockkit-strip-tabs] {
59911
60222
  }
59912
60223
  }
59913
60224
  }
59914
- async function fetchLocalIdentity(dom) {
60225
+ async function fetchLocalIdentity(dom, signal) {
59915
60226
  const protocol = dom.defaultView?.location.protocol;
59916
60227
  if (protocol !== "http:" && protocol !== "https:") return null;
59917
60228
  const response = await (dom.defaultView?.fetch.bind(dom.defaultView) ?? fetch)("/__codingns/session", {
60229
+ ...signal === void 0 ? {} : { signal },
59918
60230
  credentials: "same-origin",
59919
60231
  cache: "no-store",
59920
60232
  headers: { Accept: "application/json" }
@@ -62488,7 +62800,7 @@ ${scope} [data-dockkit-strip-tabs] {
62488
62800
  start: async (context) => {
62489
62801
  const shim = globalThis[DSH_PEER_HOST_PREBOOT_SHIM_GLOBAL];
62490
62802
  const projection = createPeerHostNativeProjection();
62491
- const transport = shim === void 0 ? void 0 : createPeerHostPageTransport(projection, context.services.uiContext);
62803
+ const transport = shim === void 0 ? void 0 : createPeerHostPageTransport(projection, context.services.uiContext, context.services.locale);
62492
62804
  const management = createPeerHostManagementApi(context.services.rpc);
62493
62805
  if (shim !== void 0) {
62494
62806
  shim.activate(transport.hooks);
@@ -62570,7 +62882,8 @@ ${scope} [data-dockkit-strip-tabs] {
62570
62882
  settingsPanel: PeerHostPanel
62571
62883
  };
62572
62884
  /** 将 DSH preboot shim 绑定到当前页面的 Host RPC;不调用 Connection.rpc,避免递归。 */
62573
- function createPeerHostPageTransport(projection = createPeerHostNativeProjection(), uiContext) {
62885
+ function createPeerHostPageTransport(projection = createPeerHostNativeProjection(), uiContext, locale) {
62886
+ const t = resolveCodingNsTranslator(locale);
62574
62887
  const fetchImpl = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
62575
62888
  const scopes = /* @__PURE__ */ new Map();
62576
62889
  const remoteHostScopes = /* @__PURE__ */ new Map();
@@ -62674,7 +62987,11 @@ ${scope} [data-dockkit-strip-tabs] {
62674
62987
  if (direct !== void 0) return direct;
62675
62988
  return method === "session/modelCatalog" && !containsResourceId(value) ? navigationScope() : void 0;
62676
62989
  };
62677
- const scopeForCliRequest = (endpoint, value) => {
62990
+ const scopeForPluginRequest = (endpoint, value) => {
62991
+ if (isDebugPluginEndpoint(endpoint)) {
62992
+ const input = asRecord(value);
62993
+ return findScope(input?.workspaceId) ?? findScope(input?.sessionId);
62994
+ }
62678
62995
  const direct = findScope(value);
62679
62996
  if (direct !== void 0) return direct;
62680
62997
  if (endpoint !== "cli/catalog" && endpoint !== "cli/models" || containsResourceId(value)) return void 0;
@@ -62718,10 +63035,6 @@ ${scope} [data-dockkit-strip-tabs] {
62718
63035
  }
62719
63036
  return false;
62720
63037
  };
62721
- const cliEndpoint = (channel, endpoint) => {
62722
- if (channel === "/codingns" && endpoint.startsWith("cli/")) return endpoint;
62723
- if (channel === "/api" && endpoint.startsWith("codingns/cli/")) return endpoint.slice(9);
62724
- };
62725
63038
  const rewriteCliPayload = (value, scope, key = "") => {
62726
63039
  if (typeof value === "string") {
62727
63040
  const parsed = parseVirtualSessionId(value);
@@ -62732,8 +63045,8 @@ ${scope} [data-dockkit-strip-tabs] {
62732
63045
  if (record === null) return value;
62733
63046
  return Object.fromEntries(Object.entries(record).map(([childKey, child]) => [childKey, rewriteCliPayload(child, scope, childKey)]));
62734
63047
  };
62735
- const remoteCliRpc = async (scope, endpoint, payload, signal) => {
62736
- if (scope.targetHostId === null) throw new Error("PeerHost CLI 请求缺少目标 Host");
63048
+ const remotePluginRpc = async (scope, endpoint, payload, signal) => {
63049
+ if (scope.targetHostId === null) throw new Error("PeerHost 插件请求缺少目标 Host");
62737
63050
  const response = asRecord(await codingNsCall("peerHost/request", {
62738
63051
  peerHostId: scope.targetHostId,
62739
63052
  scope,
@@ -62742,16 +63055,33 @@ ${scope} [data-dockkit-strip-tabs] {
62742
63055
  body: JSON.stringify({
62743
63056
  rpcId: createRequestId(),
62744
63057
  method: endpoint,
62745
- payload: rewriteCliPayload(payload, scope)
63058
+ payload: endpoint.startsWith("git/") ? {
63059
+ ...asRecord(payload),
63060
+ workspaceId: scope.workspaceId
63061
+ } : endpoint.startsWith("cli/") ? rewriteCliPayload(payload, scope) : rewriteDebugPayload(payload, scope)
62746
63062
  })
62747
63063
  }, signal));
62748
63064
  const status = typeof response?.status === "number" ? response.status : 500;
62749
63065
  const body = typeof response?.body === "string" ? response.body : "";
62750
- if (status < 200 || status >= 300) throw new Error(`远端 Host CLI RPC 失败: HTTP ${status}`);
63066
+ if (status < 200 || status >= 300) {
63067
+ let error = null;
63068
+ try {
63069
+ error = asRecord(asRecord(JSON.parse(body))?.error);
63070
+ } catch {}
63071
+ if (typeof error?.code === "string" && typeof error.message === "string") return {
63072
+ ok: false,
63073
+ error: {
63074
+ code: error.code,
63075
+ message: error.message
63076
+ }
63077
+ };
63078
+ throw new Error(`远端 Host 插件 RPC 失败: HTTP ${status}`);
63079
+ }
62751
63080
  try {
62752
- return asRecord(JSON.parse(body))?.result;
63081
+ const envelope = asRecord(JSON.parse(body));
63082
+ return endpoint.startsWith("git/") ? projectGitWorkspaceIds(envelope?.result, scope.workspaceId, createVirtualWorkspaceId(scope.targetHostId, scope.workspaceId)) : envelope?.result;
62753
63083
  } catch {
62754
- throw new Error("远端 Host CLI RPC 响应不是 JSON");
63084
+ throw new Error("远端 Host 插件 RPC 响应不是 JSON");
62755
63085
  }
62756
63086
  };
62757
63087
  const mergeRemoteAdapterMap = async (localResult, signal) => {
@@ -62759,7 +63089,7 @@ ${scope} [data-dockkit-strip-tabs] {
62759
63089
  if (localEnvelope?.ok !== true || !Array.isArray(localEnvelope.value)) return localResult;
62760
63090
  const rows = [...localEnvelope.value];
62761
63091
  for (const [targetHostId, scope] of remoteHostScopes) try {
62762
- const remoteEnvelope = asRecord(await remoteCliRpc(scope, "cli/session/adapter-map", {}, signal));
63092
+ const remoteEnvelope = asRecord(await remotePluginRpc(scope, "cli/session/adapter-map", {}, signal));
62763
63093
  if (remoteEnvelope?.ok !== true || !Array.isArray(remoteEnvelope.value)) continue;
62764
63094
  for (const raw of remoteEnvelope.value) {
62765
63095
  const row = asRecord(raw);
@@ -62844,12 +63174,27 @@ ${scope} [data-dockkit-strip-tabs] {
62844
63174
  const value = asRecord(payload);
62845
63175
  const channel = typeof value?.channel === "string" ? value.channel : "/codingns";
62846
63176
  const body = value?.payload;
62847
- const cli = cliEndpoint(channel, method);
62848
- if (cli === "cli/session/adapter-map") return await mergeRemoteAdapterMap(await request(channel, method, body, signal), signal);
62849
- if (cli !== void 0) {
62850
- const scope = scopeForCliRequest(cli, body);
63177
+ const endpoint = peerHostPluginEndpoint(channel, method);
63178
+ if (endpoint === "cli/session/adapter-map") return await mergeRemoteAdapterMap(await request(channel, method, body, signal), signal);
63179
+ if (endpoint !== void 0) {
63180
+ if (isDebugPluginEndpoint(endpoint) && hasVirtualDebugScope(body) && scopeForPluginRequest(endpoint, body) === void 0) return {
63181
+ ok: false,
63182
+ error: {
63183
+ code: "PEER_HOST_SCOPE_MISMATCH",
63184
+ message: t("peerHost.debugWorkspaceUnavailable")
63185
+ }
63186
+ };
63187
+ const workspaceId = asRecord(body)?.workspaceId;
63188
+ const scope = endpoint.startsWith("git/") ? findScope(workspaceId) : scopeForPluginRequest(endpoint, body);
63189
+ if (endpoint.startsWith("git/") && typeof workspaceId === "string" && parseVirtualWorkspaceId(workspaceId) !== null && scope === void 0) return {
63190
+ ok: false,
63191
+ error: {
63192
+ code: "PEER_HOST_SCOPE_MISMATCH",
63193
+ message: t("peerHost.gitWorkspaceUnavailable")
63194
+ }
63195
+ };
62851
63196
  if (scope !== void 0 && scope.targetHostId !== null) try {
62852
- return await remoteCliRpc(scope, cli, body, signal);
63197
+ return await remotePluginRpc(scope, endpoint, body, signal);
62853
63198
  } catch (error) {
62854
63199
  return {
62855
63200
  ok: false,
@@ -62924,8 +63269,17 @@ ${scope} [data-dockkit-strip-tabs] {
62924
63269
  },
62925
63270
  /** 该请求是否落在某个远端 Host 的作用域内;Desktop 连接路由用它决定是否分流。 */
62926
63271
  matchesScope(value, method) {
63272
+ const endpoint = method?.replace(/^codingns\//u, "") ?? "";
63273
+ if (isDebugPluginEndpoint(endpoint)) {
63274
+ const scope = scopeForPluginRequest(endpoint, value);
63275
+ return scope === void 0 ? hasVirtualDebugScope(value) : scope.targetHostId !== null;
63276
+ }
63277
+ if (method?.startsWith("git/") || method?.startsWith("codingns/git/")) {
63278
+ const workspaceId = asRecord(value)?.workspaceId;
63279
+ return typeof workspaceId === "string" && parseVirtualWorkspaceId(workspaceId) !== null;
63280
+ }
62927
63281
  const cli = method === void 0 ? void 0 : method === "cli/catalog" || method === "cli/models" ? method : method.startsWith("codingns/cli/") ? method.slice(9) : void 0;
62928
- const scope = cli === void 0 ? scopeForNativeRequest(method ?? "", value) : scopeForCliRequest(cli, value);
63282
+ const scope = cli === void 0 ? scopeForNativeRequest(method ?? "", value) : scopeForPluginRequest(cli, value);
62929
63283
  return scope !== void 0 && scope.targetHostId !== null;
62930
63284
  },
62931
63285
  watchNavigation() {
@@ -62983,6 +63337,43 @@ ${scope} [data-dockkit-strip-tabs] {
62983
63337
  }
62984
63338
  };
62985
63339
  }
63340
+ /** 两种 Connection 通道共用插件白名单,避免页面 Transport 与原生连接分流不一致。 */
63341
+ function peerHostPluginEndpoint(channel, method) {
63342
+ const endpoint = channel === "/codingns" ? method : channel === "/api" && method.startsWith("codingns/") ? method.slice(9) : "";
63343
+ return endpoint.startsWith("cli/") || endpoint.startsWith("git/") || endpoint.startsWith("debug/") || endpoint === "terminal/status" ? endpoint : void 0;
63344
+ }
63345
+ function isDebugPluginEndpoint(endpoint) {
63346
+ return endpoint.startsWith("debug/") || endpoint === "terminal/status";
63347
+ }
63348
+ function hasVirtualDebugScope(value) {
63349
+ const input = asRecord(value);
63350
+ return typeof input?.workspaceId === "string" && parseVirtualWorkspaceId(input.workspaceId) !== null || typeof input?.sessionId === "string" && parseVirtualSessionId(input.sessionId) !== null;
63351
+ }
63352
+ /** 只投影响应中的工作区标识;Diff、提交正文和文件路径均保持原文。 */
63353
+ function projectGitWorkspaceIds(value, workspaceId, virtualWorkspaceId) {
63354
+ if (Array.isArray(value)) return value.map((item) => projectGitWorkspaceIds(item, workspaceId, virtualWorkspaceId));
63355
+ const record = asRecord(value);
63356
+ if (record === null) return value;
63357
+ return Object.fromEntries(Object.entries(record).map(([key, child]) => [key, key === "workspaceId" && child === workspaceId ? virtualWorkspaceId : projectGitWorkspaceIds(child, workspaceId, virtualWorkspaceId)]));
63358
+ }
63359
+ /** 只还原调试请求顶层资源标识,配置里的命令、参数和环境变量必须原样保存。 */
63360
+ function rewriteDebugPayload(value, scope) {
63361
+ const input = asRecord(value);
63362
+ if (input === null) return value;
63363
+ const result = { ...input };
63364
+ const workspace = typeof input.workspaceId === "string" ? parseVirtualWorkspaceId(input.workspaceId) : null;
63365
+ if (workspace !== null) {
63366
+ if (workspace.hostId !== scope.targetHostId || workspace.workspaceId !== scope.workspaceId) throw new Error("调试请求的 Workspace 与目标 Host 作用域不一致");
63367
+ result.workspaceId = workspace.workspaceId;
63368
+ }
63369
+ for (const key of ["sessionId", "dshSessionId"]) {
63370
+ const session = typeof input[key] === "string" ? parseVirtualSessionId(input[key]) : null;
63371
+ if (session === null) continue;
63372
+ if (session.hostId !== scope.targetHostId) throw new Error("调试请求的 Session 与目标 Host 作用域不一致");
63373
+ result[key] = session.sessionId;
63374
+ }
63375
+ return result;
63376
+ }
62986
63377
  /**
62987
63378
  * Desktop 拓扑下把 PeerHost 聚合路由挂到 DSH 原生 Connection 上。
62988
63379
  *
@@ -63005,12 +63396,12 @@ ${scope} [data-dockkit-strip-tabs] {
63005
63396
  if (originalCall === void 0) return void 0;
63006
63397
  const originalCallRemote = remote.openRemoteStream;
63007
63398
  const isPeerScoped = (channel, endpoint, payload) => channel === "/api" && isDshNativeRemoteMethod(endpoint) && options.matchesScope(payload, endpoint);
63008
- const isPeerCli = (channel, endpoint, payload) => {
63009
- const cliEndpoint = channel === "/codingns" && endpoint.startsWith("cli/") ? endpoint : channel === "/api" && endpoint.startsWith("codingns/cli/") ? endpoint.slice(9) : void 0;
63010
- return cliEndpoint !== void 0 && (cliEndpoint === "cli/session/adapter-map" || options.matchesScope(payload, endpoint));
63399
+ const isPeerPlugin = (channel, endpoint, payload) => {
63400
+ const pluginEndpoint = peerHostPluginEndpoint(channel, endpoint);
63401
+ return pluginEndpoint !== void 0 && (pluginEndpoint === "cli/session/adapter-map" || options.matchesScope(payload, endpoint));
63011
63402
  };
63012
63403
  rpc.call = async (channel, endpoint, payload, signal) => {
63013
- if (isPeerScoped(channel, endpoint, payload) || isPeerCli(channel, endpoint, payload)) return await options.hooks.rpc({
63404
+ if (isPeerScoped(channel, endpoint, payload) || isPeerPlugin(channel, endpoint, payload)) return await options.hooks.rpc({
63014
63405
  method: endpoint,
63015
63406
  payload: {
63016
63407
  channel,
@@ -63283,6 +63674,27 @@ ${scope} [data-dockkit-strip-tabs] {
63283
63674
  }, message);
63284
63675
  }
63285
63676
  //#endregion
63677
+ //#region src/client/rpc-call.ts
63678
+ init_transport();
63679
+ const apiRoutes = /* @__PURE__ */ new WeakMap();
63680
+ /** 只在路由确实不存在或方法不兼容时回退,普通超时不能重复提交写操作。 */
63681
+ async function callCodingNsRpcResult(rpc, endpoint, payload, signal) {
63682
+ if (apiRoutes.get(rpc)?.has(endpoint)) return rpc.call("/api", `codingns/${endpoint}`, payload, signal);
63683
+ try {
63684
+ return await rpc.call(CODINGNS_RPC_CHANNEL, endpoint, payload, signal);
63685
+ } catch (error) {
63686
+ if (signal?.aborted || !/HTTP (?:404|405)\b/u.test(error instanceof Error ? error.message : String(error))) throw error;
63687
+ const result = await rpc.call("/api", `codingns/${endpoint}`, payload, signal);
63688
+ let routes = apiRoutes.get(rpc);
63689
+ if (routes === void 0) {
63690
+ routes = /* @__PURE__ */ new Set();
63691
+ apiRoutes.set(rpc, routes);
63692
+ }
63693
+ routes.add(endpoint);
63694
+ return result;
63695
+ }
63696
+ }
63697
+ //#endregion
63286
63698
  //#region src/client/features/assistant-workbench-entry.ts
63287
63699
  /** 三个入口打开同一根级工作台,不在设置卡片里再挂一份助理。 */
63288
63700
  const ASSISTANT_WORKBENCH_OPEN_EVENT = "codingns-open-assistant";
@@ -64478,7 +64890,6 @@ ${scope} [data-dockkit-strip-tabs] {
64478
64890
  };
64479
64891
  //#endregion
64480
64892
  //#region src/client/sherpa-voice-adapter.ts
64481
- init_transport();
64482
64893
  /** 浏览器侧 Sherpa 数据面:设备和权限在 Client,识别在 Host。 */
64483
64894
  var ClientSherpaVoiceAdapter = class {
64484
64895
  listeners = /* @__PURE__ */ new Set();
@@ -64621,7 +65032,7 @@ ${scope} [data-dockkit-strip-tabs] {
64621
65032
  if (this.output.outputDeviceSupported && this.selectedOutputDeviceId !== void 0) await this.output.setOutputDevice(this.selectedOutputDeviceId);
64622
65033
  }
64623
65034
  const leaseStarted = performance.now();
64624
- const leaseRequest = this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/start", {
65035
+ const leaseRequest = callCodingNsRpcResult(this.services.rpc, "assistant/voice/start", {
64625
65036
  ownerId: this.configuredOwner,
64626
65037
  voiceSessionId: callId
64627
65038
  }, abort.signal);
@@ -64746,7 +65157,7 @@ ${scope} [data-dockkit-strip-tabs] {
64746
65157
  if (pendingLease?.ok && !(isRecord$2(pendingLease.value) && pendingLease.value.unavailable === true)) this.hostLeaseActive = true;
64747
65158
  if (this.hostLeaseActive) {
64748
65159
  this.hostLeaseActive = false;
64749
- await this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/stop", { ownerId: this.configuredOwner }).catch(() => void 0);
65160
+ await callCodingNsRpcResult(this.services.rpc, "assistant/voice/stop", { ownerId: this.configuredOwner }).catch(() => void 0);
64750
65161
  }
64751
65162
  this.epoch += 1;
64752
65163
  this.emit({
@@ -64766,7 +65177,7 @@ ${scope} [data-dockkit-strip-tabs] {
64766
65177
  if (!this.active) return;
64767
65178
  this.cancelReply();
64768
65179
  this.uploader?.clearPending();
64769
- const result = await this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/interrupt", { ownerId: this.configuredOwner });
65180
+ const result = await callCodingNsRpcResult(this.services.rpc, "assistant/voice/interrupt", { ownerId: this.configuredOwner });
64770
65181
  if (!result.ok) throw new Error(result.error.message);
64771
65182
  if (!this.active) return;
64772
65183
  this.epoch = readEpoch(isRecord$2(result.value) ? result.value : {}, this.epoch + 1);
@@ -64839,7 +65250,7 @@ ${scope} [data-dockkit-strip-tabs] {
64839
65250
  this.cancelReply();
64840
65251
  if (!this.active) return;
64841
65252
  const epoch = this.epoch;
64842
- const operation = this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/chat/clear", {
65253
+ const operation = callCodingNsRpcResult(this.services.rpc, "assistant/voice/chat/clear", {
64843
65254
  ownerId: this.configuredOwner,
64844
65255
  epoch
64845
65256
  }).then((result) => {
@@ -64998,7 +65409,7 @@ ${scope} [data-dockkit-strip-tabs] {
64998
65409
  state: "thinking",
64999
65410
  epoch
65000
65411
  });
65001
- let result = await this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/chat/start", {
65412
+ let result = await callCodingNsRpcResult(this.services.rpc, "assistant/voice/chat/start", {
65002
65413
  ...payload,
65003
65414
  text
65004
65415
  }, reply.abort.signal);
@@ -65063,7 +65474,7 @@ ${scope} [data-dockkit-strip-tabs] {
65063
65474
  if (!isCurrent()) return;
65064
65475
  const pollStarted = performance.now();
65065
65476
  polls++;
65066
- result = await this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/chat/read", payload, reply.abort.signal);
65477
+ result = await callCodingNsRpcResult(this.services.rpc, "assistant/voice/chat/read", payload, reply.abort.signal);
65067
65478
  if (performance.now() - pollStarted >= 250) trace("client.turn.slow_poll", { durationMs: performance.now() - pollStarted });
65068
65479
  }
65069
65480
  } catch (error) {
@@ -65100,7 +65511,7 @@ ${scope} [data-dockkit-strip-tabs] {
65100
65511
  });
65101
65512
  reply?.abort.abort();
65102
65513
  this.cancelOutput();
65103
- if (reply !== void 0) this.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/chat/cancel", {
65514
+ if (reply !== void 0) callCodingNsRpcResult(this.services.rpc, "assistant/voice/chat/cancel", {
65104
65515
  ownerId: this.configuredOwner,
65105
65516
  epoch: reply.epoch,
65106
65517
  requestId: reply.requestId
@@ -65910,6 +66321,8 @@ ${scope} [data-dockkit-strip-tabs] {
65910
66321
  fetchStatus;
65911
66322
  module;
65912
66323
  attempt = 0;
66324
+ retryAt = 0;
66325
+ revision = assistantAvatarRuntimeRevision();
65913
66326
  constructor(importModule = (url) => import(
65914
66327
  /* @vite-ignore */
65915
66328
  url
@@ -65918,16 +66331,21 @@ ${scope} [data-dockkit-strip-tabs] {
65918
66331
  this.fetchStatus = fetchStatus;
65919
66332
  }
65920
66333
  load(location) {
66334
+ if (this.revision !== assistantAvatarRuntimeRevision() || this.retryAt > 0 && Date.now() >= this.retryAt) {
66335
+ this.revision = assistantAvatarRuntimeRevision();
66336
+ this.module = void 0;
66337
+ this.retryAt = 0;
66338
+ }
65921
66339
  if (this.module !== void 0) return this.module;
65922
66340
  const url = new URL(ASSISTANT_AVATAR_RUNTIME_PATH, location);
65923
66341
  url.searchParams.set("v", "2.1.1");
65924
- if (this.attempt > 0) url.searchParams.set("retry", String(this.attempt));
65925
- this.module = withLoadDeadline(this.importModule(url.href), 45e3).then((module) => {
66342
+ const attempt = this.attempt++;
66343
+ if (attempt > 0) url.searchParams.set("retry", String(attempt));
66344
+ const request = withLoadDeadline(this.importModule(url.href), 45e3).then((module) => {
65926
66345
  if (typeof module.init !== "function") throw new Error("avatar_runtime_invalid");
65927
66346
  return module;
65928
66347
  }).catch(async (error) => {
65929
- this.module = void 0;
65930
- this.attempt++;
66348
+ if (this.module === request) this.retryAt = Date.now() + 3e4;
65931
66349
  let status;
65932
66350
  try {
65933
66351
  status = (await this.fetchStatus(url, {
@@ -65939,7 +66357,8 @@ ${scope} [data-dockkit-strip-tabs] {
65939
66357
  if (status !== void 0 && status !== 200) throw new Error(`avatar_runtime_http_${status}`);
65940
66358
  throw error;
65941
66359
  });
65942
- return this.module;
66360
+ this.module = request;
66361
+ return request;
65943
66362
  }
65944
66363
  };
65945
66364
  const runtimeModuleLoader = new AssistantLive2dModuleLoader();
@@ -68700,7 +69119,9 @@ ${scope} [data-dockkit-strip-tabs] {
68700
69119
  this.requireWritable();
68701
69120
  this.requireEngineConsent();
68702
69121
  signal?.throwIfAborted();
68703
- return readEngineStatus(await this.call("installEngine", {}, signal));
69122
+ const result = readEngineStatus(await this.call("installEngine", {}, signal));
69123
+ invalidateAssistantAvatarRuntime();
69124
+ return result;
68704
69125
  }
68705
69126
  async getCatalog(signal) {
68706
69127
  this.requireConsent();
@@ -82777,7 +83198,6 @@ ${scope} [data-dockkit-strip-tabs] {
82777
83198
  }
82778
83199
  //#endregion
82779
83200
  //#region src/client/features/global-voice-assistant.ts
82780
- init_transport();
82781
83201
  init_locale();
82782
83202
  const GLOBAL_ASSISTANT_BUTTON_SIZE = 38;
82783
83203
  /** Client 根级语音入口;使用 shell.overlay,绝不绑定当前 session。 */
@@ -82805,7 +83225,7 @@ ${scope} [data-dockkit-strip-tabs] {
82805
83225
  ownerId: actionOwnerId,
82806
83226
  services: context.services
82807
83227
  });
82808
- context.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/register-client", {
83228
+ callCodingNsRpcResult(context.services.rpc, "assistant/voice/register-client", {
82809
83229
  ownerId: actionOwnerId,
82810
83230
  capabilities: adapter.capabilities,
82811
83231
  secureContext: inspectBrowserVoiceSecurity().secure
@@ -82814,7 +83234,7 @@ ${scope} [data-dockkit-strip-tabs] {
82814
83234
  context.resources.add(() => {
82815
83235
  disposeAdapter();
82816
83236
  adapter.dispose();
82817
- context.services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/unregister-client", { ownerId: actionOwnerId }).catch(() => void 0);
83237
+ callCodingNsRpcResult(context.services.rpc, "assistant/voice/unregister-client", { ownerId: actionOwnerId }).catch(() => void 0);
82818
83238
  });
82819
83239
  const disposer = ui.slots.inject("shell.overlay", () => ui.slots.register({
82820
83240
  name: "shell.overlay",
@@ -82869,7 +83289,7 @@ ${scope} [data-dockkit-strip-tabs] {
82869
83289
  active: false
82870
83290
  });
82871
83291
  const unsubscribe = adapter.subscribe((event) => {
82872
- if (event.type === "state" || event.type === "wake" || event.type === "barge-in" || event.type === "error") services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/event", {
83292
+ if (event.type === "state" || event.type === "wake" || event.type === "barge-in" || event.type === "error") callCodingNsRpcResult(services.rpc, "assistant/voice/event", {
82873
83293
  ownerId,
82874
83294
  event,
82875
83295
  sequence: ++eventSequenceRef.current
@@ -82931,11 +83351,19 @@ ${scope} [data-dockkit-strip-tabs] {
82931
83351
  ]);
82932
83352
  (0, react.useEffect)(() => {
82933
83353
  if (adapter === void 0) return void 0;
83354
+ let pending = false;
83355
+ const lifetime = new AbortController();
82934
83356
  const timer = setInterval(() => {
82935
- if (adapter.ownerId === void 0) return;
82936
- services.rpc.call(CODINGNS_RPC_CHANNEL, "assistant/voice/heartbeat", { ownerId }).catch(() => void 0);
83357
+ if (adapter.ownerId === void 0 || pending) return;
83358
+ pending = true;
83359
+ callCodingNsRpcResult(services.rpc, "assistant/voice/heartbeat", { ownerId }, AbortSignal.any([lifetime.signal, AbortSignal.timeout(8e3)])).catch(() => void 0).finally(() => {
83360
+ pending = false;
83361
+ });
82937
83362
  }, 1e4);
82938
- return () => clearInterval(timer);
83363
+ return () => {
83364
+ clearInterval(timer);
83365
+ lifetime.abort();
83366
+ };
82939
83367
  }, [
82940
83368
  adapter,
82941
83369
  ownerId,