ds-harness-remote 0.5.7 → 0.5.10

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 (234) hide show
  1. package/dist/acp/adapter.d.ts +1 -1
  2. package/dist/acp/adapter.d.ts.map +1 -1
  3. package/dist/acp/adapters/antigravity/transcript-loader.d.ts.map +1 -1
  4. package/dist/acp/adapters/antigravity/transcript-loader.js +4 -1
  5. package/dist/acp/adapters/antigravity/transcript-loader.js.map +1 -1
  6. package/dist/acp/adapters/claude-history.d.ts +3 -0
  7. package/dist/acp/adapters/claude-history.d.ts.map +1 -0
  8. package/dist/acp/adapters/claude-history.js +118 -0
  9. package/dist/acp/adapters/claude-history.js.map +1 -0
  10. package/dist/acp/adapters/claude-process.d.ts +21 -0
  11. package/dist/acp/adapters/claude-process.d.ts.map +1 -0
  12. package/dist/acp/adapters/claude-process.js +147 -0
  13. package/dist/acp/adapters/claude-process.js.map +1 -0
  14. package/dist/acp/adapters/cursor-process.d.ts +9 -4
  15. package/dist/acp/adapters/cursor-process.d.ts.map +1 -1
  16. package/dist/acp/adapters/cursor-process.js +31 -3
  17. package/dist/acp/adapters/cursor-process.js.map +1 -1
  18. package/dist/acp/adapters/opencode-process.d.ts +67 -0
  19. package/dist/acp/adapters/opencode-process.d.ts.map +1 -0
  20. package/dist/acp/adapters/opencode-process.js +272 -0
  21. package/dist/acp/adapters/opencode-process.js.map +1 -0
  22. package/dist/acp/adapters/opencode.d.ts +8 -0
  23. package/dist/acp/adapters/opencode.d.ts.map +1 -0
  24. package/dist/acp/adapters/opencode.js +8 -0
  25. package/dist/acp/adapters/opencode.js.map +1 -0
  26. package/dist/acp/adapters/pi-process.d.ts +42 -0
  27. package/dist/acp/adapters/pi-process.d.ts.map +1 -0
  28. package/dist/acp/adapters/pi-process.js +410 -0
  29. package/dist/acp/adapters/pi-process.js.map +1 -0
  30. package/dist/acp/gateway.d.ts +10 -0
  31. package/dist/acp/gateway.d.ts.map +1 -1
  32. package/dist/acp/gateway.js +344 -103
  33. package/dist/acp/gateway.js.map +1 -1
  34. package/dist/acp/method-policy.d.ts +19 -19
  35. package/dist/acp/method-policy.js +5 -5
  36. package/dist/acp/method-policy.js.map +1 -1
  37. package/dist/acp/pi-tool-result.d.ts +9 -0
  38. package/dist/acp/pi-tool-result.d.ts.map +1 -0
  39. package/dist/acp/pi-tool-result.js +22 -0
  40. package/dist/acp/pi-tool-result.js.map +1 -0
  41. package/dist/acp/virtual-catalog.d.ts +50 -0
  42. package/dist/acp/virtual-catalog.d.ts.map +1 -0
  43. package/dist/acp/virtual-catalog.js +103 -0
  44. package/dist/acp/virtual-catalog.js.map +1 -0
  45. package/dist/acp/virtual-contract.d.ts +165 -0
  46. package/dist/acp/virtual-contract.d.ts.map +1 -0
  47. package/dist/acp/virtual-contract.js +216 -0
  48. package/dist/acp/virtual-contract.js.map +1 -0
  49. package/dist/acp/virtual-event-carrier.d.ts +50 -0
  50. package/dist/acp/virtual-event-carrier.d.ts.map +1 -0
  51. package/dist/acp/virtual-event-carrier.js +222 -0
  52. package/dist/acp/virtual-event-carrier.js.map +1 -0
  53. package/dist/acp/virtual-harness.d.ts +13 -112
  54. package/dist/acp/virtual-harness.d.ts.map +1 -1
  55. package/dist/acp/virtual-harness.js +129 -911
  56. package/dist/acp/virtual-harness.js.map +1 -1
  57. package/dist/acp/virtual-live.d.ts +78 -0
  58. package/dist/acp/virtual-live.d.ts.map +1 -0
  59. package/dist/acp/virtual-live.js +513 -0
  60. package/dist/acp/virtual-live.js.map +1 -0
  61. package/dist/acp/workspace-tools.js +2 -2
  62. package/dist/acp/workspace-tools.js.map +1 -1
  63. package/dist/acp.d.ts.map +1 -1
  64. package/dist/acp.js +1 -0
  65. package/dist/acp.js.map +1 -1
  66. package/dist/client/header.d.ts +10 -0
  67. package/dist/client/header.d.ts.map +1 -0
  68. package/dist/client/header.js +169 -0
  69. package/dist/client/header.js.map +1 -0
  70. package/dist/client/icons.d.ts +3 -0
  71. package/dist/client/icons.d.ts.map +1 -0
  72. package/dist/client/icons.js +3 -0
  73. package/dist/client/icons.js.map +1 -0
  74. package/dist/client/navigation.d.ts +5 -0
  75. package/dist/client/navigation.d.ts.map +1 -0
  76. package/dist/client/navigation.js +30 -0
  77. package/dist/client/navigation.js.map +1 -0
  78. package/dist/client/presentation.d.ts +17 -0
  79. package/dist/client/presentation.d.ts.map +1 -0
  80. package/dist/client/presentation.js +208 -0
  81. package/dist/client/presentation.js.map +1 -0
  82. package/dist/client/progress.d.ts +10 -0
  83. package/dist/client/progress.d.ts.map +1 -0
  84. package/dist/client/progress.js +82 -0
  85. package/dist/client/progress.js.map +1 -0
  86. package/dist/client/settings.d.ts +10 -0
  87. package/dist/client/settings.d.ts.map +1 -0
  88. package/dist/client/settings.js +335 -0
  89. package/dist/client/settings.js.map +1 -0
  90. package/dist/client/shell.d.ts +6 -0
  91. package/dist/client/shell.d.ts.map +1 -0
  92. package/dist/client/shell.js +128 -0
  93. package/dist/client/shell.js.map +1 -0
  94. package/dist/client/types.d.ts +264 -0
  95. package/dist/client/types.d.ts.map +1 -0
  96. package/dist/client/types.js +2 -0
  97. package/dist/client/types.js.map +1 -0
  98. package/dist/client/workspaces.d.ts +11 -0
  99. package/dist/client/workspaces.d.ts.map +1 -0
  100. package/dist/client/workspaces.js +1179 -0
  101. package/dist/client/workspaces.js.map +1 -0
  102. package/dist/client-capabilities.d.ts +6 -0
  103. package/dist/client-capabilities.d.ts.map +1 -0
  104. package/dist/client-capabilities.js +88 -0
  105. package/dist/client-capabilities.js.map +1 -0
  106. package/dist/client-codex-streams.d.ts +23 -0
  107. package/dist/client-codex-streams.d.ts.map +1 -0
  108. package/dist/client-codex-streams.js +156 -0
  109. package/dist/client-codex-streams.js.map +1 -0
  110. package/dist/client-connection.d.ts +38 -0
  111. package/dist/client-connection.d.ts.map +1 -0
  112. package/dist/client-connection.js +210 -0
  113. package/dist/client-connection.js.map +1 -0
  114. package/dist/client-control.d.ts +48 -0
  115. package/dist/client-control.d.ts.map +1 -0
  116. package/dist/client-control.js +273 -0
  117. package/dist/client-control.js.map +1 -0
  118. package/dist/client-locale.d.ts +8 -0
  119. package/dist/client-locale.d.ts.map +1 -1
  120. package/dist/client-locale.js +16 -0
  121. package/dist/client-locale.js.map +1 -1
  122. package/dist/client-runtime-contract.d.ts +161 -0
  123. package/dist/client-runtime-contract.d.ts.map +1 -0
  124. package/dist/client-runtime-contract.js +127 -0
  125. package/dist/client-runtime-contract.js.map +1 -0
  126. package/dist/client-runtime.d.ts +24 -126
  127. package/dist/client-runtime.d.ts.map +1 -1
  128. package/dist/client-runtime.js +171 -867
  129. package/dist/client-runtime.js.map +1 -1
  130. package/dist/client-secure-transport.d.ts +1 -0
  131. package/dist/client-secure-transport.d.ts.map +1 -1
  132. package/dist/client-secure-transport.js +35 -16
  133. package/dist/client-secure-transport.js.map +1 -1
  134. package/dist/client-workspace-queries.d.ts +12 -0
  135. package/dist/client-workspace-queries.d.ts.map +1 -0
  136. package/dist/client-workspace-queries.js +66 -0
  137. package/dist/client-workspace-queries.js.map +1 -0
  138. package/dist/client.d.ts.map +1 -1
  139. package/dist/client.github.js +2091 -1896
  140. package/dist/client.js +2091 -1896
  141. package/dist/client.js.map +1 -1
  142. package/dist/codex/domain.d.ts.map +1 -1
  143. package/dist/codex/domain.js +67 -46
  144. package/dist/codex/domain.js.map +1 -1
  145. package/dist/codex/method-policy.d.ts +9 -9
  146. package/dist/codex/virtual-catalog.d.ts +90 -0
  147. package/dist/codex/virtual-catalog.d.ts.map +1 -0
  148. package/dist/codex/virtual-catalog.js +317 -0
  149. package/dist/codex/virtual-catalog.js.map +1 -0
  150. package/dist/codex/virtual-contract.d.ts +96 -0
  151. package/dist/codex/virtual-contract.d.ts.map +1 -0
  152. package/dist/codex/virtual-contract.js +192 -0
  153. package/dist/codex/virtual-contract.js.map +1 -0
  154. package/dist/codex/virtual-event-carrier.d.ts +52 -0
  155. package/dist/codex/virtual-event-carrier.d.ts.map +1 -0
  156. package/dist/codex/virtual-event-carrier.js +212 -0
  157. package/dist/codex/virtual-event-carrier.js.map +1 -0
  158. package/dist/codex/virtual-harness.d.ts +16 -117
  159. package/dist/codex/virtual-harness.d.ts.map +1 -1
  160. package/dist/codex/virtual-harness.js +123 -1909
  161. package/dist/codex/virtual-harness.js.map +1 -1
  162. package/dist/codex/virtual-history.d.ts +74 -0
  163. package/dist/codex/virtual-history.d.ts.map +1 -0
  164. package/dist/codex/virtual-history.js +546 -0
  165. package/dist/codex/virtual-history.js.map +1 -0
  166. package/dist/codex/virtual-live.d.ts +75 -0
  167. package/dist/codex/virtual-live.d.ts.map +1 -0
  168. package/dist/codex/virtual-live.js +563 -0
  169. package/dist/codex/virtual-live.js.map +1 -0
  170. package/dist/codex/virtual-values.d.ts +29 -0
  171. package/dist/codex/virtual-values.d.ts.map +1 -0
  172. package/dist/codex/virtual-values.js +75 -0
  173. package/dist/codex/virtual-values.js.map +1 -0
  174. package/dist/config.js +4 -4
  175. package/dist/config.js.map +1 -1
  176. package/dist/control-runtime.js +2 -2
  177. package/dist/control-runtime.js.map +1 -1
  178. package/dist/harness-remote-bridge.d.ts +2 -1
  179. package/dist/harness-remote-bridge.d.ts.map +1 -1
  180. package/dist/harness-remote-bridge.js +13 -5
  181. package/dist/harness-remote-bridge.js.map +1 -1
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js +23304 -15332
  184. package/dist/index.js.map +4 -4
  185. package/dist/plugin-route-dispatcher.d.ts +2 -2
  186. package/dist/plugin-route-dispatcher.d.ts.map +1 -1
  187. package/dist/plugin-route-dispatcher.js +2 -2
  188. package/dist/plugin-route-dispatcher.js.map +1 -1
  189. package/dist/remote-terminal-controller.d.ts +90 -0
  190. package/dist/remote-terminal-controller.d.ts.map +1 -0
  191. package/dist/remote-terminal-controller.js +494 -0
  192. package/dist/remote-terminal-controller.js.map +1 -0
  193. package/dist/remote-terminal-provider.d.ts +46 -0
  194. package/dist/remote-terminal-provider.d.ts.map +1 -0
  195. package/dist/remote-terminal-provider.js +147 -0
  196. package/dist/remote-terminal-provider.js.map +1 -0
  197. package/dist/remote-typert-gateway.js +7 -1
  198. package/dist/remote-typert-gateway.js.map +1 -1
  199. package/dist/server-api.d.ts +3 -0
  200. package/dist/server-api.d.ts.map +1 -1
  201. package/dist/server-api.js +24 -9
  202. package/dist/server-api.js.map +1 -1
  203. package/dist/server-connection.d.ts +1 -0
  204. package/dist/server-connection.d.ts.map +1 -1
  205. package/dist/server-connection.js +8 -1
  206. package/dist/server-connection.js.map +1 -1
  207. package/dist/service.d.ts +1 -1
  208. package/dist/service.d.ts.map +1 -1
  209. package/dist/service.js +15 -8
  210. package/dist/service.js.map +1 -1
  211. package/dist/terminal-carrier-compat.d.ts +14 -0
  212. package/dist/terminal-carrier-compat.d.ts.map +1 -0
  213. package/dist/terminal-carrier-compat.js +259 -0
  214. package/dist/terminal-carrier-compat.js.map +1 -0
  215. package/dist/terminal-policy.d.ts +6 -0
  216. package/dist/terminal-policy.d.ts.map +1 -1
  217. package/dist/terminal-policy.js +24 -6
  218. package/dist/terminal-policy.js.map +1 -1
  219. package/dist/typert-gateway-contract.d.ts +6 -1
  220. package/dist/typert-gateway-contract.d.ts.map +1 -1
  221. package/dist/typert-gateway-switch.d.ts +2 -1
  222. package/dist/typert-gateway-switch.d.ts.map +1 -1
  223. package/dist/typert-gateway-switch.js +39 -18
  224. package/dist/typert-gateway-switch.js.map +1 -1
  225. package/dist/version.d.ts +1 -1
  226. package/dist/version.d.ts.map +1 -1
  227. package/dist/version.js +1 -1
  228. package/dist/version.js.map +1 -1
  229. package/dist/workspace-bridge.d.ts +6 -89
  230. package/dist/workspace-bridge.d.ts.map +1 -1
  231. package/dist/workspace-bridge.js +37 -294
  232. package/dist/workspace-bridge.js.map +1 -1
  233. package/dsh-plugin.json +1 -1
  234. package/package.json +24 -20
package/dist/client.js CHANGED
@@ -1619,295 +1619,6 @@ Minimum version required to store current data is: ` + bestVersion + `.
1619
1619
  }
1620
1620
  });
1621
1621
 
1622
- // src/client.ts
1623
- var import_qrcode = __toESM(require_browser(), 1);
1624
-
1625
- // src/remote-file-content-provider.ts
1626
- function shouldUseRemoteFileViewer(status) {
1627
- return status.mode === "remote" && status.remoteFeatures?.fileViewer === !0;
1628
- }
1629
- var REMOTE_FILE_SAVE_AS_MAX_BYTES = 100 * 1024 * 1024, REMOTE_FILE_FAST_SAVE_AS_MAX_BYTES = 1024 * 1024 * 1024;
1630
- function shouldAllowRemoteFileSaveAs(status) {
1631
- return shouldUseRemoteFileViewer(status) && (status.transport === "LAN" || status.transport === "P2P" || status.transport === "TURN");
1632
- }
1633
- function remoteFileSaveAsMaxBytes(status) {
1634
- return status.transport === "LAN" || status.transport === "P2P" ? REMOTE_FILE_FAST_SAVE_AS_MAX_BYTES : REMOTE_FILE_SAVE_AS_MAX_BYTES;
1635
- }
1636
- function createRemoteFileContentProvider(call, options = {}) {
1637
- return {
1638
- id: "dsh-remote-files",
1639
- priority: 1e4,
1640
- supports: () => !0,
1641
- saveAsAllowed: () => ({
1642
- allowed: currentSaveAsAllowed(options.saveAsAllowed),
1643
- maxBytes: currentSaveAsMaxBytes(options.saveAsMaxBytes)
1644
- }),
1645
- async stat(locator, signal) {
1646
- let value = await call("fileviewer.stat", { path: locator }, signal);
1647
- if (value.exists)
1648
- return {
1649
- name: value.name,
1650
- size: value.isDirectory ? 0 : value.size,
1651
- mime: value.mime,
1652
- mtimeMs: value.mtimeMs,
1653
- isDirectory: value.isDirectory
1654
- };
1655
- },
1656
- async read(locator, request) {
1657
- if (!Number.isInteger(request.offset) || request.offset < 0) throw new Error("A non-negative integer offset is required.");
1658
- if (!Number.isInteger(request.length) || request.length <= 0) throw new Error("A positive integer length is required.");
1659
- let chunks = [], received = 0;
1660
- for (; received < request.length; ) {
1661
- request.signal.throwIfAborted();
1662
- let length = Math.min(524288, request.length - received), offset = request.offset + received, range = await call("fileviewer.readRange", { path: locator, offset, length }, request.signal);
1663
- if (range.offset !== offset) throw new Error("The Remote Host returned a mismatched file range.");
1664
- let bytes = decodeBase64(range.data);
1665
- if (bytes.byteLength > length) throw new Error("The Remote Host returned more file bytes than requested.");
1666
- if (chunks.push(bytes), received += bytes.byteLength, range.eof || bytes.byteLength === 0) break;
1667
- }
1668
- let merged = new Uint8Array(received), cursor = 0;
1669
- for (let chunk of chunks)
1670
- merged.set(chunk, cursor), cursor += chunk.byteLength;
1671
- return merged;
1672
- },
1673
- async list(locator, signal) {
1674
- return (await call("fileviewer.list", { path: locator }, signal)).entries.map((entry) => ({
1675
- locator: entry.path,
1676
- name: entry.name,
1677
- size: entry.isDirectory ? 0 : entry.size ?? 0,
1678
- mtimeMs: entry.mtimeMs,
1679
- isDirectory: entry.isDirectory
1680
- }));
1681
- }
1682
- };
1683
- }
1684
- function currentSaveAsAllowed(value) {
1685
- return typeof value == "function" ? value() : value === !0;
1686
- }
1687
- function currentSaveAsMaxBytes(value) {
1688
- return typeof value == "function" ? value() : value ?? REMOTE_FILE_SAVE_AS_MAX_BYTES;
1689
- }
1690
- function decodeBase64(value) {
1691
- let binary = atob(value), bytes = new Uint8Array(binary.length);
1692
- for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
1693
- return bytes;
1694
- }
1695
-
1696
- // src/control-route.ts
1697
- var CONTROL_RPC_PREFIX = "/ds-harness-remote", STATUS_STREAM_ENDPOINT = "status.events", STATUS_STREAM_PATH = `${CONTROL_RPC_PREFIX}/${STATUS_STREAM_ENDPOINT}`;
1698
-
1699
- // src/plugin-route-client.ts
1700
- var PluginRouteFailure = class extends Error {
1701
- constructor(code, message) {
1702
- super(message);
1703
- this.code = code;
1704
- }
1705
- };
1706
- function createPluginRouteFetch(original, baseUrl, options = {}) {
1707
- let routeUrl = new URL("api/bot", baseUrl), nextRpcId = 0, control = async (method, payload, signal) => {
1708
- let rpcId = `plugin-route-${++nextRpcId}`, response = await original(new URL(`${CONTROL_RPC_PREFIX.slice(1)}/${method}`, baseUrl), {
1709
- method: "POST",
1710
- credentials: "same-origin",
1711
- headers: { "content-type": "application/json" },
1712
- body: JSON.stringify({ type: "client-request", rpcId, method, payload }),
1713
- signal
1714
- });
1715
- if (!response.ok) throw new PluginRouteFailure("remote-plugin/control-unavailable", `The local Remote control request failed (HTTP ${response.status}). Reload the Remote plugin.`);
1716
- let envelope = await response.json();
1717
- if (!isRecord(envelope) || envelope.type !== "server-response" || envelope.rpcId !== rpcId || !isRecord(envelope.result))
1718
- throw new PluginRouteFailure("remote-plugin/control-invalid", "The local Remote control response is invalid. Reload the Remote plugin.");
1719
- if (envelope.result.ok !== !0) {
1720
- let error = isRecord(envelope.result.error) ? envelope.result.error : void 0, code = (isRecord(error?.details) ? error.details : void 0)?.remoteCode ?? error?.code;
1721
- throw code === "FEATURE_NOT_SUPPORTED" || code === "METHOD_NOT_FOUND" ? new PluginRouteFailure("remote-plugin/host-unsupported", "The selected Host does not support plugin route forwarding. Update and reload Remote on the Host, then reconnect.") : code === "REMOTE_NOT_CONNECTED" || code === "TRANSPORT_CLOSED" ? new PluginRouteFailure("remote-plugin/disconnected", "The Remote Host is disconnected. Reconnect to load DS Bot.") : code === "INVALID_MESSAGE" ? new PluginRouteFailure("remote-plugin/operation-not-allowed", "This DS Bot operation is not allowed over Remote. Use the Host locally.") : new PluginRouteFailure("remote-plugin/control-rejected", "The Remote plugin route request was rejected by the control channel.");
1722
- }
1723
- return envelope.result.value;
1724
- };
1725
- return async (input, init) => {
1726
- let requestUrl = new URL(input instanceof Request ? input.url : String(input), baseUrl);
1727
- if ((init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase() !== "POST" || requestUrl.href !== routeUrl.href) return original(input, init);
1728
- let lifetime = (init?.signal !== void 0 ? init.signal ?? void 0 : input instanceof Request ? input.signal : void 0) ?? AbortSignal.timeout(45e3);
1729
- try {
1730
- lifetime.throwIfAborted();
1731
- let status = await control("status", {}, AbortSignal.any([lifetime, AbortSignal.timeout(1e4)]));
1732
- if (lifetime.throwIfAborted(), !isRecord(status)) throw new PluginRouteFailure("remote-plugin/authority-unavailable", "The Remote plugin route authority is unavailable.");
1733
- if (status.mode === "local") return original(input, init);
1734
- if (status.mode !== "remote") throw new PluginRouteFailure("remote-plugin/authority-unavailable", "The Remote plugin route authority is unavailable.");
1735
- if (status.connected !== !0) throw new PluginRouteFailure("remote-plugin/disconnected", "The Remote Host is disconnected. Reconnect to load DS Bot.");
1736
- if (!isRecord(status.remoteFeatures) || status.remoteFeatures.pluginRoute !== !0) throw new PluginRouteFailure("remote-plugin/host-unsupported", "The selected Host does not support plugin route forwarding. Update and reload Remote on the Host, then reconnect.");
1737
- if (status.backend !== void 0 && status.backend !== "harness") throw new PluginRouteFailure("remote-plugin/backend-unsupported", "DS Bot requires the Remote Harness catalog. Select a Harness workspace on this Host.");
1738
- let body = await (input instanceof Request ? new Request(input, init) : new Request(requestUrl, init)).clone().json();
1739
- if (!isRecord(body)) throw new Error("The plugin route body must be a JSON object.");
1740
- let result = await control("plugin.route", { route: "api/bot", body }, lifetime);
1741
- if (!isRecord(result) || !Number.isInteger(result.status) || result.status < 200 || result.status > 599)
1742
- throw new Error("The plugin route response is invalid.");
1743
- let statusCode = result.status;
1744
- if (statusCode === 404) throw new PluginRouteFailure("remote-plugin/bot-not-loaded", "The Host has no DS Bot route. Enable ds-bot in the same DSH instance/profile as the connected Host.");
1745
- if (statusCode === 503) throw new PluginRouteFailure("remote-plugin/host-carrier-unavailable", "The Host plugin route carrier is unavailable. Update and reload Remote on the Host.");
1746
- if (statusCode >= 200 && statusCode < 300 && options.beforeResponse !== void 0)
1747
- try {
1748
- await waitWithSignal(options.beforeResponse(status, body, result.json, lifetime), lifetime);
1749
- } catch {
1750
- throw lifetime.throwIfAborted(), new PluginRouteFailure("remote-plugin/catalog-unavailable", "The Remote Harness Session catalog is not ready. Reconnect before loading DS Bot.");
1751
- }
1752
- return lifetime.throwIfAborted(), new Response([204, 205, 304].includes(statusCode) ? null : JSON.stringify(result.json ?? null), {
1753
- status: statusCode,
1754
- headers: { "content-type": "application/json" }
1755
- });
1756
- } catch (error) {
1757
- return lifetime.throwIfAborted(), new Response(JSON.stringify({
1758
- ok: !1,
1759
- error: {
1760
- code: error instanceof PluginRouteFailure ? error.code : "remote-plugin/unavailable",
1761
- message: error instanceof PluginRouteFailure ? error.message : "The Remote plugin route is unavailable.",
1762
- details: {}
1763
- }
1764
- }), { status: 200, headers: { "content-type": "application/json" } });
1765
- }
1766
- };
1767
- }
1768
- function createPluginRouteCatalogGuard(readSessions) {
1769
- return async (_status, body, json, signal) => {
1770
- if (!isRecord(json) || json.ok !== !0 || !isRecord(json.value)) return;
1771
- let required = botSessionIds(body.endpoint, json.value);
1772
- if (required.size === 0) return;
1773
- let sessions = await readSessions(), containsSessions = () => {
1774
- let snapshot = sessions.list.getSnapshot(), known = new Set(snapshot.ids);
1775
- return snapshot.phase === "ready" && [...required].every((id) => known.has(id));
1776
- };
1777
- for (let attempt = 0; attempt < 2; attempt++) {
1778
- if (signal.throwIfAborted(), containsSessions()) return;
1779
- if (sessions.refresh === void 0) break;
1780
- await sessions.refresh();
1781
- }
1782
- if (signal.throwIfAborted(), !containsSessions()) throw new Error("The Remote Session catalog does not contain the published Sessions.");
1783
- };
1784
- }
1785
- function botSessionIds(endpoint, value) {
1786
- let ids = /* @__PURE__ */ new Set(), add = (id) => {
1787
- if (id != null) {
1788
- if (typeof id != "string" || id.length === 0) throw new Error("Invalid Bot Session identity.");
1789
- ids.add(id);
1790
- }
1791
- }, addArray = (input) => {
1792
- if (input !== void 0) {
1793
- if (!Array.isArray(input)) throw new Error("Invalid Bot Session identities.");
1794
- input.forEach(add);
1795
- }
1796
- }, bot = (input) => {
1797
- if (!isRecord(input)) throw new Error("Invalid Bot catalog entry.");
1798
- add(input.id), add(input.sessionId), addArray(input.parts), Array.isArray(input.segments) && input.segments.forEach((segment) => {
1799
- if (!isRecord(segment)) throw new Error("Invalid Bot Session segment.");
1800
- add(segment.sessionId);
1801
- });
1802
- }, room = (input) => {
1803
- if (!isRecord(input)) throw new Error("Invalid Bot room entry.");
1804
- add(input.id), addArray(input.parts), isRecord(input.sessions) && Object.values(input.sessions).forEach(add);
1805
- }, agent = (input) => {
1806
- if (!isRecord(input)) throw new Error("Invalid Bot agent entry.");
1807
- addArray(input.sessions);
1808
- }, roster = () => {
1809
- for (let [key, visit] of [["bots", bot], ["rooms", room], ["agents", agent]])
1810
- if (value[key] !== void 0) {
1811
- if (!Array.isArray(value[key])) throw new Error("Invalid Bot roster.");
1812
- value[key].forEach(visit);
1813
- }
1814
- };
1815
- switch (endpoint) {
1816
- case "state":
1817
- case "delete-bot":
1818
- case "delete-room":
1819
- case "set-main":
1820
- case "remove-agent":
1821
- roster();
1822
- break;
1823
- case "create-bot":
1824
- case "duplicate-bot":
1825
- case "update-bot":
1826
- bot(value);
1827
- break;
1828
- case "create-room":
1829
- room(value);
1830
- break;
1831
- case "update-room":
1832
- room(value.room);
1833
- break;
1834
- case "add-agent":
1835
- agent(value);
1836
- break;
1837
- case "agent-session":
1838
- case "agent-adopt":
1839
- add(value.sessionId);
1840
- break;
1841
- case "set-flags":
1842
- Array.isArray(value.sessions) ? agent(value) : Array.isArray(value.members) ? room(value) : bot(value);
1843
- break;
1844
- }
1845
- return ids;
1846
- }
1847
- function waitWithSignal(pending, signal) {
1848
- return new Promise((resolve, reject) => {
1849
- let onAbort = () => reject(signal.reason);
1850
- signal.addEventListener("abort", onAbort, { once: !0 }), signal.aborted && onAbort(), pending.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
1851
- });
1852
- }
1853
- function isRecord(value) {
1854
- return typeof value == "object" && value !== null && !Array.isArray(value);
1855
- }
1856
-
1857
- // src/status-stream.ts
1858
- function parseStatus(data) {
1859
- if (typeof data == "string")
1860
- try {
1861
- let parsed = JSON.parse(data);
1862
- return parsed === null || typeof parsed != "object" ? void 0 : parsed;
1863
- } catch {
1864
- return;
1865
- }
1866
- }
1867
- function createStatusFeed(options) {
1868
- let listeners = /* @__PURE__ */ new Set(), pollIntervalMs = options.pollIntervalMs ?? 1500, openTimeoutMs = options.openTimeoutMs ?? 4e3, createSource = options.createSource ?? ((url) => new EventSource(url)), status, source, openTimer, pollTimer, publish = (next) => {
1869
- status = next;
1870
- for (let listener of [...listeners]) listener(next);
1871
- }, teardown = () => {
1872
- openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0), pollTimer !== void 0 && (clearInterval(pollTimer), pollTimer = void 0), source?.close(), source = void 0;
1873
- }, poll = () => {
1874
- options.readStatus().then((next) => {
1875
- pollTimer !== void 0 && publish(next);
1876
- }).catch(() => {
1877
- });
1878
- }, fallbackToPolling = (reason) => {
1879
- pollTimer !== void 0 || listeners.size === 0 || (openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0), source?.close(), source = void 0, options.onFallback?.(reason), poll(), pollTimer = setInterval(poll, pollIntervalMs));
1880
- }, openStream = () => {
1881
- let opened;
1882
- try {
1883
- opened = createSource(options.url);
1884
- } catch {
1885
- fallbackToPolling("unsupported");
1886
- return;
1887
- }
1888
- source = opened;
1889
- let received = !1;
1890
- openTimer = setTimeout(() => {
1891
- received || fallbackToPolling("silent");
1892
- }, openTimeoutMs), opened.onmessage = (event) => {
1893
- received = !0, openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0);
1894
- let next = parseStatus(event.data);
1895
- next !== void 0 && publish(next);
1896
- }, opened.onerror = () => {
1897
- opened.readyState === 2 && fallbackToPolling("unavailable");
1898
- };
1899
- };
1900
- return {
1901
- getSnapshot: () => status,
1902
- subscribe: (listener) => (listeners.add(listener), status !== void 0 && listener(status), listeners.size === 1 && openStream(), () => {
1903
- listeners.delete(listener), listeners.size === 0 && teardown();
1904
- }),
1905
- close: () => {
1906
- listeners.clear(), teardown();
1907
- }
1908
- };
1909
- }
1910
-
1911
1622
  // src/client-locale.ts
1912
1623
  var localeNamespace = "ds-harness-remote", en = {
1913
1624
  terminalRemote: "Remote terminal",
@@ -2063,15 +1774,21 @@ Minimum version required to store current data is: ` + bestVersion + `.
2063
1774
  addCodexWorkspace: "Add CodeX workspace",
2064
1775
  addCursorWorkspace: "Add Cursor workspace",
2065
1776
  addAntigravityWorkspace: "Add Antigravity workspace",
1777
+ addPiWorkspace: "Add PI workspace",
1778
+ addOpencodeWorkspace: "Add OpenCode workspace",
2066
1779
  noCodexWorkspaces: "No CodeX workspaces yet.",
2067
1780
  noCursorWorkspaces: "No Cursor workspaces yet. Add a project directory to start.",
2068
1781
  noAntigravityWorkspaces: "No Antigravity workspaces yet. Add a project directory to start.",
1782
+ noPiWorkspaces: "No PI workspaces yet. Add a project directory to start.",
1783
+ noOpencodeWorkspaces: "No OpenCode workspaces yet. Add a project directory to start.",
2069
1784
  cancelAddWorkspace: "Cancel",
2070
1785
  confirmAddWorkspace: "Add and open",
2071
1786
  showAllWorkspaces: "Show all DSH workspaces",
2072
1787
  showAllCodexWorkspaces: "Show all CodeX workspaces",
2073
1788
  showAllCursorWorkspaces: "Show all Cursor workspaces",
2074
1789
  showAllAntigravityWorkspaces: "Show all Antigravity workspaces",
1790
+ showAllPiWorkspaces: "Show all PI workspaces",
1791
+ showAllOpencodeWorkspaces: "Show all OpenCode workspaces",
2075
1792
  remoteModeLabel: "Remote mode \xB7 {name}",
2076
1793
  remoteNetworkP2p: "P2P",
2077
1794
  remoteNetworkTurn: "TURN",
@@ -2166,6 +1883,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
2166
1883
  codexVirtualWorkspace: "CodeX virtual workspace",
2167
1884
  cursorVirtualWorkspace: "Cursor virtual workspace",
2168
1885
  antigravityVirtualWorkspace: "Antigravity virtual workspace",
1886
+ piVirtualWorkspace: "PI virtual workspace",
1887
+ opencodeVirtualWorkspace: "OpenCode virtual workspace",
2169
1888
  codexVirtualSessions: "Sessions"
2170
1889
  }, zh = {
2171
1890
  terminalRemote: "\u8FDC\u7A0B\u7EC8\u7AEF",
@@ -2321,15 +2040,21 @@ Minimum version required to store current data is: ` + bestVersion + `.
2321
2040
  addCodexWorkspace: "\u6DFB\u52A0 CodeX \u5DE5\u4F5C\u533A",
2322
2041
  addCursorWorkspace: "\u6DFB\u52A0 Cursor \u5DE5\u4F5C\u533A",
2323
2042
  addAntigravityWorkspace: "\u6DFB\u52A0 Antigravity \u5DE5\u4F5C\u533A",
2043
+ addPiWorkspace: "\u6DFB\u52A0 PI \u5DE5\u4F5C\u533A",
2044
+ addOpencodeWorkspace: "\u6DFB\u52A0 OpenCode \u5DE5\u4F5C\u533A",
2324
2045
  noCodexWorkspaces: "\u8FD8\u6CA1\u6709 CodeX \u5DE5\u4F5C\u533A\u3002",
2325
2046
  noCursorWorkspaces: "\u8FD8\u6CA1\u6709 Cursor \u5DE5\u4F5C\u533A\u3002\u6DFB\u52A0\u9879\u76EE\u76EE\u5F55\u5373\u53EF\u5F00\u59CB\u3002",
2326
2047
  noAntigravityWorkspaces: "\u8FD8\u6CA1\u6709 Antigravity \u5DE5\u4F5C\u533A\u3002\u6DFB\u52A0\u9879\u76EE\u76EE\u5F55\u5373\u53EF\u5F00\u59CB\u3002",
2048
+ noPiWorkspaces: "\u8FD8\u6CA1\u6709 PI \u5DE5\u4F5C\u533A\u3002\u6DFB\u52A0\u9879\u76EE\u76EE\u5F55\u5373\u53EF\u5F00\u59CB\u3002",
2049
+ noOpencodeWorkspaces: "\u8FD8\u6CA1\u6709 OpenCode \u5DE5\u4F5C\u533A\u3002\u6DFB\u52A0\u9879\u76EE\u76EE\u5F55\u5373\u53EF\u5F00\u59CB\u3002",
2327
2050
  cancelAddWorkspace: "\u53D6\u6D88",
2328
2051
  confirmAddWorkspace: "\u786E\u8BA4\u5E76\u6253\u5F00",
2329
2052
  showAllWorkspaces: "\u663E\u793A\u5168\u90E8 DSH \u5DE5\u4F5C\u533A",
2330
2053
  showAllCodexWorkspaces: "\u663E\u793A\u5168\u90E8 CodeX \u5DE5\u4F5C\u533A",
2331
2054
  showAllCursorWorkspaces: "\u663E\u793A\u5168\u90E8 Cursor \u5DE5\u4F5C\u533A",
2332
2055
  showAllAntigravityWorkspaces: "\u663E\u793A\u5168\u90E8 Antigravity \u5DE5\u4F5C\u533A",
2056
+ showAllPiWorkspaces: "\u663E\u793A\u5168\u90E8 PI \u5DE5\u4F5C\u533A",
2057
+ showAllOpencodeWorkspaces: "\u663E\u793A\u5168\u90E8 OpenCode \u5DE5\u4F5C\u533A",
2333
2058
  remoteModeLabel: "\u8FDC\u7A0B\u6A21\u5F0F \xB7 {name}",
2334
2059
  remoteNetworkP2p: "P2P",
2335
2060
  remoteNetworkTurn: "TURN",
@@ -2424,49 +2149,13 @@ Minimum version required to store current data is: ` + bestVersion + `.
2424
2149
  codexVirtualWorkspace: "CodeX \u5DE5\u4F5C\u533A",
2425
2150
  cursorVirtualWorkspace: "Cursor \u5DE5\u4F5C\u533A",
2426
2151
  antigravityVirtualWorkspace: "Antigravity \u5DE5\u4F5C\u533A",
2152
+ piVirtualWorkspace: "PI \u5DE5\u4F5C\u533A",
2153
+ opencodeVirtualWorkspace: "OpenCode \u5DE5\u4F5C\u533A",
2427
2154
  codexVirtualSessions: "Sessions"
2428
2155
  };
2429
2156
 
2430
- // src/client.ts
2431
- var clientModuleId = "ds-harness-remote", pendingWorkspaceSelectionKey = "dsh-remote:pending-workspace-selection", deepSeekWorkspaceIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAACVBMVEUAAADy8vXx8fUsA3vyAAAAAXRSTlMAQObYZgAAAOxJREFUWMPtlsEOwyAMQxP+/6OnTZMGxHGcot3wDYgfhkJbs6urprzveGtu9d1NgEdto8w93GuA7zPS2RFg7ynsCOAokbtAmLr2YaeKgJ6fxpT8jCAC0qSqPyNoO5DXdvyouj4ClFAdYaDxK09uiBDCIYBf6CxLesnR0uF2pG+JmhCqrUb0AOvjjoQaYDTCEAAgMg5grhAeAQIB+/M15IcKlnUIp4CkTCd0AKb4zVsRSJVGYEVzT0agK107IMGMEurvromEpaX4wzk/IKw378kq4LafED6Oowxfk7AP2q8W16EdM3p29Eyvrv6vF0WIBfBziKyCAAAAAElFTkSuQmCC", gptWorkspaceIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAclBMVEX////v7+++wMf////s7O3k5OTExcrX2Ny6vMTv8PPW19yXmqRqboJmaHd3eoaqrLPs7fGMjpfb3eKlpq1eYXOxs7pWWWd+gY5HSVdRVGVub3k+QU74+Pg4OkcvMT1ISlUoKjUiIy4fICueoKkaGyUSFB21Bp+qAAAAAXRSTlMAQObYZgAABChJREFUWMPtl916qjoQhlsdEwIECEgMYCBxx/u/xT1DrFUL1LO1DtY8LSLJvPnmB4gfH//sr7TPDfvdebf/xXZbkE/4zZ0MVhGHd9zJDsv+7F3//Z69tT5wljAu3tXw+TIlzXKJlhflYmJ+5uF5WpWhb54X+C/zZCmT2wJA4dJZwus0UYjIGqWyMhVbEp4yKNRRqlv0opW5PJLJ4rFJXvP4JKDRMqturBZjkMVJFYjR6iHQDQDI4+k2k51wZbWrqwp4mR/1CVYATyko9TFGxBUqL5IvMbXSWt0T8bkGgFLqgqZBI/Uxbx5UAxLaNcCNLBpttM7wbCc1pmJOpWAsDtey68UaQMyrFgb9uxLPjqg3+nGluyKN0XUdWw0BJ0NvTFFqgzpr9J+Dh4w0Ga1qkqBNswagxdRgFPAbgHRQG5jumGWyMxrTIaRRa4AzFs0YrNMXgI4MJWnsKYFhGNMnIh/mBOPsV8CZBFjN9w8ArowxnZzDr5IcvxTaKpxJCVsoI3SWysz1UM4AqQdzlCgho1IKrK+x1mKFzisANtgEU8E7GwHDgOqxe4w9tnM166wbaA2xBMBLrTWcAGYGdCiYVUJUrMCF+7l6gklrW1RwPi8ByjuActANqhKzVWoYrFGcCFzbDgNaBrTWpncFQMcI2DfWoAiDqRCiHcYM/ZdCEKkZqfR8spj4F0CiJjv2gHL6URNoCQDaYacL6O1oFDO2eQDUFP7AKdCRdC4CRDZaNifbjA41l/uYb/SZMAFNTBGzY7sG4J2jTsJgToOzIzXF3HZqBpSOAGduXbkGEKV1OqVGqRJpRxtvwbSw5IqAiUJItwBCOT9R32FCGo3nCkAN3t0UTBRC6zDONcBeOee9pr4T+ASbnDOdc5OmtREwEEB5w8Wqgt4bOV5c7Lt9iiK8zdP/IsBbutUGX4gNwEVCqd3FUt/xYnRWt7BvPBYQjwjAGXa3ASguHVAZ/WXKlA3eZDX1wRegFsr7E2wAlB9xFbx/7MV70kFT8aqNgLL3F8nFBmA3hrn/IJHjKJOK2oj1WI4Z4FzwN/81AOhgYD6v2xbIvaZIurLC9AfvB1WLTYAoXejF1xeBL5cpBIyEbmxkZymIXwDQh1BAfOrhI1lfwtgz8tozF5T4ttf3+32AyxC6klwAgw/YVTHpoK82xYt3wLP/Bw4AAI4D7/01TLKXBj9NEz2wEuGiKpoy68S/FwCLMQAZ3gXhihaCa25vQo6RyToOz9PE6wYjJgGi1YnqZX8qMIK+TDlnargGzSv4NvFjlwXf/nfLLMrAB4O/Xl3BH0d+RIASFgDA8IYMIXgr2+cBsbDdPSwAAHjSZFmb3txETCKIxc0uWwI8rxsLJcTiVndNwyMgKljbbNN2/zcEAja2+4RgIDYN2Bu/WtAOaEodnu2dnzz/7I/Y/w/LaEcX/MdfAAAAAElFTkSuQmCC";
2432
- function storedWorkspaceSelection() {
2433
- let raw = window.sessionStorage.getItem(pendingWorkspaceSelectionKey);
2434
- if (raw !== null)
2435
- try {
2436
- let value = JSON.parse(raw);
2437
- if (typeof value.targetDeviceId != "string" || typeof value.workspaceId != "string") throw new Error("invalid");
2438
- if (value.backend !== void 0 && value.backend !== "harness" && value.backend !== "codex" && value.backend !== "cursor" && value.backend !== "antigravity") throw new Error("invalid");
2439
- if (value.sessionId !== void 0 && typeof value.sessionId != "string") throw new Error("invalid");
2440
- return value;
2441
- } catch {
2442
- window.sessionStorage.removeItem(pendingWorkspaceSelectionKey);
2443
- return;
2444
- }
2445
- }
2446
- function workspacesReady(snapshot) {
2447
- return snapshot.baselinesReady === !0 || snapshot.phase === "ready";
2448
- }
2449
- var defaultPreferredTransports = ["lan", "p2p", "turn", "relay"], controlRouteBackoffStepsMs = [1e3, 2e3, 5e3, 1e4, 3e4], ControlRouteUnavailableError = class extends Error {
2450
- constructor(message) {
2451
- super(message), this.name = "ControlRouteUnavailableError";
2452
- }
2453
- }, originalPluginFetch = window.fetch, readyPluginSessions, pluginSessions = new Promise((resolve) => {
2454
- readyPluginSessions = resolve;
2455
- }), pluginRouteFetch = typeof originalPluginFetch == "function" && typeof document < "u" ? createPluginRouteFetch(originalPluginFetch.bind(window), document.baseURI, {
2456
- beforeResponse: createPluginRouteCatalogGuard(() => pluginSessions)
2457
- }) : void 0;
2458
- pluginRouteFetch !== void 0 && (window.fetch = pluginRouteFetch);
2459
- function controlRouteUnavailableStatus() {
2460
- return {
2461
- mode: "local",
2462
- available: !1,
2463
- controlUnavailable: !0,
2464
- connected: !1,
2465
- transport: "Disconnected",
2466
- remoteFeatures: { commandList: !1, fileViewer: !1, terminal: !1, codex: !1, pluginRoute: !1, cursor: !1, antigravity: !1 },
2467
- hostAuthorizationAvailable: !1
2468
- };
2469
- }
2157
+ // src/client/presentation.ts
2158
+ var defaultPreferredTransports = ["lan", "p2p", "turn", "relay"];
2470
2159
  function normalizedPreferredTransports(value) {
2471
2160
  return value === void 0 || value.length === 0 ? [...defaultPreferredTransports] : [...value];
2472
2161
  }
@@ -2564,1427 +2253,2230 @@ Minimum version required to store current data is: ` + bestVersion + `.
2564
2253
  function connectionStatusClass(status) {
2565
2254
  return status?.online ? " isOnline" : status?.reconnecting ? " isReconnecting" : status === void 0 ? "" : " isOffline";
2566
2255
  }
2567
- window.__ModuleLoader__.load({
2568
- id: clientModuleId,
2569
- factory: (require2) => {
2570
- let module = { exports: {} }, React = require2("react"), inject = [
2571
- "connection",
2572
- "slots",
2573
- "locale",
2574
- "workspaces",
2575
- "sessions"
2576
- ];
2577
- function RemoteProgressView(props) {
2578
- let progress = props.progress;
2579
- if (progress === void 0) return null;
2580
- let percent = Math.max(0, Math.min(100, Math.round(progress.percent))), activeTransports = new Set(progress.activeTransports ?? []), detail = progress.transports !== void 0 && activeTransports.size > 0 ? React.createElement(
2581
- "span",
2582
- { className: "dshRemoteProgressRoute" },
2583
- props.t(progress.routeVerb === "using" ? "remoteProgressUsingPrefix" : "remoteProgressTryingPrefix"),
2584
- progress.transports.map((transport, index) => React.createElement(
2585
- React.Fragment,
2586
- { key: `${transport}:${index}` },
2587
- index === 0 ? null : React.createElement("span", { className: "dshRemoteProgressRouteArrow", "aria-hidden": !0 }, " -> "),
2588
- React.createElement("span", {
2589
- className: activeTransports.has(transport) ? "isActive" : void 0
2590
- }, transportDiagnosticLabel(transport))
2591
- ))
2592
- ) : props.t(progress.detail);
2593
- return React.createElement(
2594
- "div",
2256
+ function messageOf(reason) {
2257
+ return reason instanceof Error ? reason.message : String(reason);
2258
+ }
2259
+ function formatPlatform(value) {
2260
+ let normalized = value.toLowerCase();
2261
+ return normalized === "darwin" || normalized === "macos" ? "macOS" : normalized === "win32" || normalized === "windows" ? "Windows" : normalized === "linux" ? "Linux" : normalized === "android" ? "Android" : value;
2262
+ }
2263
+ function connectedClientModeLabel(mode, t) {
2264
+ return t(mode === "LAN" ? "remoteNetworkLan" : mode === "P2P" ? "remoteNetworkP2p" : mode === "TURN" ? "remoteNetworkTurn" : mode === "Relay" ? "remoteNetworkRelay" : "connected");
2265
+ }
2266
+
2267
+ // src/client/header.ts
2268
+ function createRemoteSessionHeaderAction(React) {
2269
+ function RemoteSessionHeaderAction(props) {
2270
+ let { t } = props, status = React.useSyncExternalStore(
2271
+ props.statusFeed.subscribe,
2272
+ props.statusFeed.getSnapshot,
2273
+ props.statusFeed.getSnapshot
2274
+ ), [busy, setBusy] = React.useState(!1), [routeOpen, setRouteOpen] = React.useState(!1);
2275
+ if (React.useEffect(() => {
2276
+ if (status?.mode === "remote")
2277
+ return hideLocalSessionActions();
2278
+ }, [status?.mode]), React.useEffect(() => (document.documentElement.classList.toggle(
2279
+ "dshRemoteCodexTargetActive",
2280
+ status?.mode === "remote" && status.backend === "codex"
2281
+ ), document.documentElement.classList.toggle(
2282
+ "dshRemoteCursorTargetActive",
2283
+ status?.mode === "remote" && status.backend === "cursor"
2284
+ ), document.documentElement.classList.toggle(
2285
+ "dshRemoteAntigravityTargetActive",
2286
+ status?.mode === "remote" && status.backend === "antigravity"
2287
+ ), document.documentElement.classList.toggle(
2288
+ "dshRemotePiTargetActive",
2289
+ status?.mode === "remote" && status.backend === "pi"
2290
+ ), document.documentElement.classList.toggle(
2291
+ "dshRemoteOpencodeTargetActive",
2292
+ status?.mode === "remote" && status.backend === "opencode"
2293
+ ), () => {
2294
+ document.documentElement.classList.remove("dshRemoteCodexTargetActive"), document.documentElement.classList.remove("dshRemoteCursorTargetActive"), document.documentElement.classList.remove("dshRemoteAntigravityTargetActive"), document.documentElement.classList.remove("dshRemotePiTargetActive"), document.documentElement.classList.remove("dshRemoteOpencodeTargetActive");
2295
+ }), [status?.mode, status?.backend]), React.useEffect(() => {
2296
+ if (!routeOpen) return;
2297
+ let closeOnEscape = (event) => {
2298
+ event.key === "Escape" && setRouteOpen(!1);
2299
+ };
2300
+ return document.addEventListener("keydown", closeOnEscape), () => document.removeEventListener("keydown", closeOnEscape);
2301
+ }, [routeOpen]), status?.mode !== "remote") return null;
2302
+ let exit = async () => {
2303
+ setBusy(!0);
2304
+ try {
2305
+ await props.control("mode.set", { mode: "local" }), window.location.reload();
2306
+ } finally {
2307
+ setBusy(!1);
2308
+ }
2309
+ }, transport = status.network?.webRtc?.mode ?? status.transport ?? "Disconnected", networkLabel = t(transport === "P2P" ? "remoteNetworkP2p" : transport === "TURN" ? "remoteNetworkTurn" : transport === "Relay" ? "remoteNetworkRelay" : transport === "LAN" ? "remoteNetworkLan" : "remoteNetworkOffline"), networkOnline = status.connected === !0 && transport !== "Disconnected", routeVia = t(transport === "P2P" ? "connectionRouteP2p" : transport === "TURN" ? "connectionRouteTurn" : transport === "Relay" ? "connectionRouteRelay" : "connectionRouteLan"), routeViaDetail = t(transport === "P2P" ? "connectionRouteP2pDetail" : transport === "TURN" ? "connectionRouteTurnDetail" : transport === "Relay" ? "connectionRouteRelayDetail" : "connectionRouteLanDetail"), network = status.network, webRtc = network?.webRtc, controlStateLabel = network?.controlChannelState === "connecting" ? t("controlStateConnecting") : network?.controlChannelState === "open" ? t("controlStateOpen") : network?.controlChannelState === "closing" ? t("controlStateClosing") : t("controlStateClosed"), detailValue = (value) => value === void 0 || value === "" ? t("notProvided") : String(value), candidateLabel = (value) => value === "host" ? t("candidateHost") : value === "srflx" ? t("candidateSrflx") : value === "prflx" ? t("candidatePrflx") : value === "relay" ? t("candidateRelay") : detailValue(value), fact = (label, value, mono = !1) => React.createElement(
2310
+ "div",
2311
+ null,
2312
+ React.createElement("dt", null, label),
2313
+ React.createElement("dd", { className: mono ? "isMono" : void 0, title: mono ? value : void 0 }, value)
2314
+ );
2315
+ return React.createElement(
2316
+ "div",
2317
+ { className: "dshRemoteSessionHeader", role: "status" },
2318
+ React.createElement("svg", {
2319
+ viewBox: "0 0 24 24",
2320
+ fill: "none",
2321
+ stroke: "currentColor",
2322
+ strokeWidth: 1.7,
2323
+ strokeLinecap: "round",
2324
+ strokeLinejoin: "round",
2325
+ "aria-hidden": !0
2326
+ }, React.createElement("rect", { x: 3, y: 4, width: 18, height: 13, rx: 2 }), React.createElement("path", { d: "M8 21h8M12 17v4" })),
2327
+ React.createElement("span", { className: "dshRemoteSessionTarget" }, t("remoteModeLabel", { name: status.target?.name ?? t("host") })),
2328
+ React.createElement("button", {
2329
+ type: "button",
2330
+ className: `dshRemoteNetwork${networkOnline ? " isOnline" : " isOffline"}`,
2331
+ title: networkLabel,
2332
+ disabled: !networkOnline,
2333
+ "aria-haspopup": "dialog",
2334
+ "aria-expanded": routeOpen,
2335
+ onClick: () => setRouteOpen((value) => !value)
2336
+ }, React.createElement("i", { "aria-hidden": !0 }), networkLabel),
2337
+ networkOnline ? React.createElement("span", { className: "dshRemoteEncrypted" }, t("remoteLinkEncrypted")) : null,
2338
+ React.createElement("button", { type: "button", className: "dshRemoteHeaderExitLink", disabled: busy, onClick: () => void exit() }, t("exitRemote")),
2339
+ routeOpen ? React.createElement("div", {
2340
+ className: "dshRemoteRouteBackdrop",
2341
+ role: "presentation",
2342
+ onMouseDown: (event) => {
2343
+ event.target === event.currentTarget && setRouteOpen(!1);
2344
+ }
2345
+ }, React.createElement(
2346
+ "section",
2595
2347
  {
2596
- className: "dshRemoteProgress",
2597
- role: "status",
2598
- "aria-live": "polite"
2348
+ className: "dshRemoteRoutePanel",
2349
+ role: "dialog",
2350
+ "aria-label": t("connectionRouteTitle")
2599
2351
  },
2600
2352
  React.createElement(
2601
- "div",
2602
- { className: "dshRemoteProgressHeader" },
2603
- React.createElement("strong", null, props.t(progress.label)),
2604
- React.createElement("span", null, `${percent}%`)
2353
+ "header",
2354
+ null,
2355
+ React.createElement("strong", null, t("connectionRouteTitle")),
2356
+ React.createElement("button", { type: "button", "aria-label": t("close"), onClick: () => setRouteOpen(!1) }, "\xD7")
2605
2357
  ),
2606
- React.createElement("p", null, detail),
2607
- React.createElement("div", {
2608
- className: "dshRemoteProgressBar",
2609
- role: "progressbar",
2610
- "aria-valuemin": 0,
2611
- "aria-valuemax": 100,
2612
- "aria-valuenow": percent,
2613
- "aria-label": props.t(progress.label)
2614
- }, React.createElement("span", { style: { transform: `scaleX(${percent / 100})` } }))
2615
- );
2358
+ React.createElement(
2359
+ "ol",
2360
+ null,
2361
+ React.createElement(
2362
+ "li",
2363
+ null,
2364
+ React.createElement("small", null, t("connectionRouteFrom")),
2365
+ React.createElement("strong", null, network?.local.name ?? t("connectionRouteCurrentDevice")),
2366
+ network === void 0 ? null : React.createElement("span", null, `${network.local.platform} \xB7 ${shortDeviceId(network.local.deviceId)}`)
2367
+ ),
2368
+ React.createElement(
2369
+ "li",
2370
+ null,
2371
+ React.createElement("small", null, t("connectionRouteVia")),
2372
+ React.createElement("strong", null, routeVia),
2373
+ React.createElement("span", null, routeViaDetail)
2374
+ ),
2375
+ React.createElement(
2376
+ "li",
2377
+ null,
2378
+ React.createElement("small", null, t("connectionRouteTo")),
2379
+ React.createElement("strong", null, network?.remote.name ?? status.target?.name ?? t("host")),
2380
+ React.createElement("span", null, network === void 0 ? t("connectionRouteHost") : `${network.remote.platform} \xB7 ${shortDeviceId(network.remote.deviceId)}`)
2381
+ )
2382
+ ),
2383
+ network === void 0 ? null : React.createElement(
2384
+ "section",
2385
+ { className: "dshRemoteRouteSection" },
2386
+ React.createElement("h3", null, t("connectionDetailsConnection")),
2387
+ React.createElement(
2388
+ "dl",
2389
+ null,
2390
+ fact(t("connectionId"), detailValue(network.connectionId), !0),
2391
+ fact(t("connectedAt"), network.connectedAt === void 0 ? t("notProvided") : formatLocalTime(network.connectedAt)),
2392
+ fact(t("preferredTransports"), network.preferredTransports.map((value) => transportLabel(value, t)).join(" \u2192 ")),
2393
+ fact(t("controlChannel"), `WebSocket \xB7 ${controlStateLabel}`),
2394
+ fact(t("controlAddress"), network.controlChannelUrl, !0)
2395
+ )
2396
+ ),
2397
+ webRtc === void 0 ? null : React.createElement(
2398
+ "section",
2399
+ { className: "dshRemoteRouteSection" },
2400
+ React.createElement("h3", null, t("connectionDetailsWebRtc")),
2401
+ React.createElement(
2402
+ "dl",
2403
+ null,
2404
+ fact(t("peerState"), `${webRtc.connectionState} \xB7 ICE ${webRtc.iceConnectionState}`),
2405
+ fact(t("dataChannel"), detailValue(webRtc.dataChannelState)),
2406
+ fact(t("localCandidate"), candidateLabel(webRtc.localCandidateType)),
2407
+ fact(t("remoteCandidate"), candidateLabel(webRtc.remoteCandidateType)),
2408
+ fact(t("localAddress"), detailValue(webRtc.localAddress), !0),
2409
+ fact(t("remoteAddress"), detailValue(webRtc.remoteAddress), !0),
2410
+ fact(t("networkProtocol"), detailValue(webRtc.protocol?.toUpperCase())),
2411
+ fact(t("relayProtocol"), detailValue(webRtc.relayProtocol?.toUpperCase())),
2412
+ fact(t("roundTripTime"), webRtc.currentRoundTripTimeMs === void 0 ? t("notProvided") : `${webRtc.currentRoundTripTimeMs.toLocaleString()} ms`),
2413
+ fact(t("availableBitrate"), webRtc.availableOutgoingBitrate === void 0 ? t("notProvided") : formatBitrate(webRtc.availableOutgoingBitrate)),
2414
+ fact(t("bytesSent"), webRtc.bytesSent === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesSent)),
2415
+ fact(t("bytesReceived"), webRtc.bytesReceived === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesReceived))
2416
+ )
2417
+ ),
2418
+ React.createElement("p", null, t("connectionRouteEncrypted"))
2419
+ )) : null
2420
+ );
2421
+ }
2422
+ return RemoteSessionHeaderAction;
2423
+ }
2424
+ function hideLocalSessionActions() {
2425
+ let selector = 'button,a,[role="button"]', hiddenAttribute = "data-dsh-remote-hidden-action", localAction = /(?:open|打开).{0,12}vs\s*code|vs\s*code.{0,12}(?:open|打开)|session\s*logs?|download.{0,12}session\s*logs?|会话日志|下载.{0,8}日志/i, inspect = (root) => {
2426
+ let candidates = root instanceof Element && root.matches(selector) ? [root, ...Array.from(root.querySelectorAll(selector))] : Array.from(root.querySelectorAll(selector));
2427
+ for (let candidate of candidates) {
2428
+ if (candidate.closest(".dshRemoteSessionHeader") !== null) continue;
2429
+ let label = [
2430
+ candidate.getAttribute("aria-label"),
2431
+ candidate.getAttribute("title"),
2432
+ candidate.getAttribute("data-tooltip"),
2433
+ candidate.textContent
2434
+ ].filter(Boolean).join(" ");
2435
+ localAction.test(label) && candidate.setAttribute(hiddenAttribute, "");
2616
2436
  }
2617
- async function runConnectHostProgress(preferredTransports, targetDeviceId, control, connectedStep, setProgress, progressRun, action, readyProgress) {
2618
- let runId = progressRun.current + 1;
2619
- progressRun.current = runId;
2620
- let polling = !0, pollTimer, connectedAt, apply2 = (next) => {
2621
- progressRun.current === runId && setProgress(next);
2622
- }, poll = async () => {
2623
- try {
2624
- let status = await control("status");
2625
- if (!polling || progressRun.current !== runId) return;
2626
- (status.connectionProgress?.phase === "connected" || status.connectedTargetDeviceId === targetDeviceId) && connectedAt === void 0 && (connectedAt = Date.now());
2627
- let next = observedConnectionProgress(status, targetDeviceId, preferredTransports, connectedStep, connectedAt);
2628
- next !== void 0 && apply2(next);
2629
- } catch {
2630
- } finally {
2631
- polling && progressRun.current === runId && (pollTimer = window.setTimeout(() => {
2632
- poll();
2633
- }, 300));
2634
- }
2635
- };
2636
- apply2({ label: "remoteProgressCheckingHost", detail: "remoteProgressCheckingHostDetail", percent: 12 });
2637
- let pending = action();
2638
- poll();
2639
- try {
2640
- let result = await pending;
2641
- return polling = !1, pollTimer !== void 0 && window.clearTimeout(pollTimer), apply2(readyProgress?.(result) ?? { label: "remoteProgressReady", detail: "remoteProgressReadyDetail", percent: 100 }), await new Promise((resolve) => window.setTimeout(resolve, 520)), result;
2642
- } finally {
2643
- polling = !1, pollTimer !== void 0 && window.clearTimeout(pollTimer), progressRun.current === runId && setProgress(void 0);
2644
- }
2437
+ };
2438
+ inspect(document.body);
2439
+ let observer = new MutationObserver((records) => {
2440
+ for (let record of records) {
2441
+ record.type === "attributes" && inspect(record.target);
2442
+ for (let node of Array.from(record.addedNodes))
2443
+ node instanceof Element && inspect(node);
2444
+ }
2445
+ });
2446
+ return observer.observe(document.body, {
2447
+ subtree: !0,
2448
+ childList: !0,
2449
+ attributes: !0,
2450
+ attributeFilter: ["aria-label", "title", "data-tooltip"]
2451
+ }), () => {
2452
+ observer.disconnect(), document.querySelectorAll(`[${hiddenAttribute}]`).forEach((element) => element.removeAttribute(hiddenAttribute));
2453
+ };
2454
+ }
2455
+
2456
+ // src/client/navigation.ts
2457
+ var pendingWorkspaceSelectionKey = "dsh-remote:pending-workspace-selection";
2458
+ function storedWorkspaceSelection() {
2459
+ let raw = window.sessionStorage.getItem(pendingWorkspaceSelectionKey);
2460
+ if (raw !== null)
2461
+ try {
2462
+ let value = JSON.parse(raw);
2463
+ if (typeof value.targetDeviceId != "string" || typeof value.workspaceId != "string") throw new Error("invalid");
2464
+ if (value.backend !== void 0 && value.backend !== "harness" && value.backend !== "codex" && value.backend !== "cursor" && value.backend !== "antigravity" && value.backend !== "pi" && value.backend !== "opencode") throw new Error("invalid");
2465
+ if (value.sessionId !== void 0 && typeof value.sessionId != "string") throw new Error("invalid");
2466
+ return value;
2467
+ } catch {
2468
+ window.sessionStorage.removeItem(pendingWorkspaceSelectionKey);
2469
+ return;
2470
+ }
2471
+ }
2472
+ function workspacesReady(snapshot) {
2473
+ return snapshot.baselinesReady === !0 || snapshot.phase === "ready";
2474
+ }
2475
+
2476
+ // src/client/progress.ts
2477
+ function createRemoteProgressView(React) {
2478
+ function RemoteProgressView(props) {
2479
+ let progress = props.progress;
2480
+ if (progress === void 0) return null;
2481
+ let percent = Math.max(0, Math.min(100, Math.round(progress.percent))), activeTransports = new Set(progress.activeTransports ?? []), detail = progress.transports !== void 0 && activeTransports.size > 0 ? React.createElement(
2482
+ "span",
2483
+ { className: "dshRemoteProgressRoute" },
2484
+ props.t(progress.routeVerb === "using" ? "remoteProgressUsingPrefix" : "remoteProgressTryingPrefix"),
2485
+ progress.transports.map((transport, index) => React.createElement(
2486
+ React.Fragment,
2487
+ { key: `${transport}:${index}` },
2488
+ index === 0 ? null : React.createElement("span", { className: "dshRemoteProgressRouteArrow", "aria-hidden": !0 }, " -> "),
2489
+ React.createElement("span", {
2490
+ className: activeTransports.has(transport) ? "isActive" : void 0
2491
+ }, transportDiagnosticLabel(transport))
2492
+ ))
2493
+ ) : props.t(progress.detail);
2494
+ return React.createElement(
2495
+ "div",
2496
+ {
2497
+ className: "dshRemoteProgress",
2498
+ role: "status",
2499
+ "aria-live": "polite"
2500
+ },
2501
+ React.createElement(
2502
+ "div",
2503
+ { className: "dshRemoteProgressHeader" },
2504
+ React.createElement("strong", null, props.t(progress.label)),
2505
+ React.createElement("span", null, `${percent}%`)
2506
+ ),
2507
+ React.createElement("p", null, detail),
2508
+ React.createElement("div", {
2509
+ className: "dshRemoteProgressBar",
2510
+ role: "progressbar",
2511
+ "aria-valuemin": 0,
2512
+ "aria-valuemax": 100,
2513
+ "aria-valuenow": percent,
2514
+ "aria-label": props.t(progress.label)
2515
+ }, React.createElement("span", { style: { transform: `scaleX(${percent / 100})` } }))
2516
+ );
2517
+ }
2518
+ return RemoteProgressView;
2519
+ }
2520
+ async function runConnectHostProgress(preferredTransports, targetDeviceId, control, connectedStep, setProgress, progressRun, action, readyProgress) {
2521
+ let runId = progressRun.current + 1;
2522
+ progressRun.current = runId;
2523
+ let polling = !0, pollTimer, connectedAt, apply = (next) => {
2524
+ progressRun.current === runId && setProgress(next);
2525
+ }, poll = async () => {
2526
+ try {
2527
+ let status = await control("status");
2528
+ if (!polling || progressRun.current !== runId) return;
2529
+ (status.connectionProgress?.phase === "connected" || status.connectedTargetDeviceId === targetDeviceId) && connectedAt === void 0 && (connectedAt = Date.now());
2530
+ let next = observedConnectionProgress(status, targetDeviceId, preferredTransports, connectedStep, connectedAt);
2531
+ next !== void 0 && apply(next);
2532
+ } catch {
2533
+ } finally {
2534
+ polling && progressRun.current === runId && (pollTimer = window.setTimeout(() => {
2535
+ poll();
2536
+ }, 300));
2645
2537
  }
2646
- function RemotePluginOptions(props) {
2647
- let { t } = props, [open, setOpen] = React.useState(props.view === "page"), [serverUrl, setServerUrl] = React.useState(""), [portsBusy, setPortsBusy] = React.useState(!1), [previewPorts, setPreviewPorts] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [terminalEnabled, setTerminalEnabled] = React.useState(!1), [terminalBusy, setTerminalBusy] = React.useState(!1), [acpBackends, setAcpBackends] = React.useState([]), [acpAvailability, setAcpAvailability] = React.useState({}), [acpChecking, setAcpChecking] = React.useState({}), [acpCheckResults, setAcpCheckResults] = React.useState({}), [addingAcp, setAddingAcp] = React.useState(!1), [acpName, setAcpName] = React.useState(""), [acpCommand, setAcpCommand] = React.useState(""), [acpArguments, setAcpArguments] = React.useState("acp"), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [hostName, setHostName] = React.useState(""), [hostDeviceId, setHostDeviceId] = React.useState(""), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyView = (view) => {
2648
- setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setTerminalEnabled(view.config.terminal?.enabled ?? !0), setPreviewPorts((view.config.loopback?.ports ?? []).join(", ")), setAcpBackends((view.config.acp?.backends ?? []).map((item) => ({ id: item.id, enabled: item.enabled !== !1 }))), setAcpAvailability(view.acpAvailability ?? {}), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
2649
- }, load = async () => {
2650
- let [view, status] = await Promise.all([
2651
- props.control("settings.get"),
2652
- props.control("status").catch(() => {
2653
- })
2654
- ]);
2655
- applyView(view), setHostStatus(status?.host), setHostName(status?.deviceName ?? ""), setHostDeviceId(status?.host?.deviceId ?? "");
2656
- };
2657
- React.useEffect(() => {
2658
- load().catch((reason) => setError(messageOf(reason)));
2659
- }, []), React.useEffect(() => {
2660
- if (association !== void 0)
2661
- return props.statusFeed.subscribe((status) => {
2662
- setHostStatus(status.host), setHostName(status.deviceName ?? ""), setHostDeviceId(status.host?.deviceId ?? "");
2663
- });
2664
- }, [association !== void 0]);
2665
- let save = async (event) => {
2666
- if (event?.preventDefault(), !(!writable || !serverDirty)) {
2667
- setBusy(!0), setNotice(void 0), setError(void 0);
2668
- try {
2669
- let view = await props.control("settings.server.set", {
2670
- serverUrl
2671
- });
2672
- applyView(view), setNotice({ key: "serverSaved" });
2673
- } catch (reason) {
2674
- setError(messageOf(reason));
2675
- } finally {
2676
- setBusy(!1);
2677
- }
2678
- }
2679
- }, logout = async () => {
2680
- setBusy(!0), setError(void 0), setNotice(void 0);
2681
- try {
2682
- let view = await props.control("settings.logout");
2683
- applyView(view), setRegistrationCode(""), setNotice({ key: "signedOut" });
2684
- } catch (reason) {
2685
- setError(messageOf(reason));
2686
- } finally {
2687
- setBusy(!1);
2688
- }
2689
- }, reconnectHost = async () => {
2690
- setReconnectBusy(!0), setError(void 0), setNotice(void 0);
2691
- try {
2692
- let status = await props.control("host.reconnect");
2693
- setHostStatus(status.host), setNotice({ key: "reconnectStarted" });
2694
- } catch (reason) {
2695
- setError(messageOf(reason));
2696
- } finally {
2697
- setReconnectBusy(!1);
2698
- }
2699
- }, setCurrentDeviceControl = async (enabled) => {
2700
- setBusy(!0), setError(void 0), setNotice(void 0);
2701
- try {
2702
- let status = await props.control("host.authorization.set", { enabled });
2703
- setHostStatus(status.host);
2704
- } catch (reason) {
2705
- setError(messageOf(reason));
2706
- } finally {
2707
- setBusy(!1);
2708
- }
2709
- }, setTerminalRemote = async (enabled) => {
2710
- let previous = terminalEnabled, portsDraft = previewPorts;
2711
- setTerminalEnabled(enabled), setTerminalBusy(!0), setError(void 0), setNotice(void 0);
2712
- try {
2713
- let view = await props.control("settings.development.set", { terminalEnabled: enabled });
2714
- applyView(view), setPreviewPorts(portsDraft), setNotice({ key: "terminalSaved" });
2715
- } catch (reason) {
2716
- setTerminalEnabled(previous), setError(messageOf(reason));
2717
- } finally {
2718
- setTerminalBusy(!1);
2719
- }
2720
- }, savePreviewPorts = async () => {
2721
- setPortsBusy(!0), setError(void 0), setNotice(void 0);
2722
- try {
2723
- let ports = previewPorts.trim() === "" ? [] : previewPorts.split(/[,,]/).map((value) => Number(value.trim())), view = await props.control("settings.development.set", { ports });
2724
- applyView(view), setNotice({ key: "developmentSaved" });
2725
- } catch (reason) {
2726
- setError(messageOf(reason));
2727
- } finally {
2728
- setPortsBusy(!1);
2729
- }
2730
- }, checkAcp = async (backend) => {
2731
- if (!acpChecking[backend]) {
2732
- setAcpChecking((current) => ({ ...current, [backend]: !0 })), setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), setError(void 0);
2733
- try {
2734
- let view = await props.control("settings.get");
2735
- applyView(view);
2736
- let available = view.acpAvailability?.[backend] === !0;
2737
- !available && view.writable && view.config.acp?.backends?.some((item) => item.id === backend && item.enabled !== !1) && applyView(await props.control("settings.acp.set", { backend, enabled: !1 })), setAcpCheckResults((current) => ({ ...current, [backend]: available })), setNotice({ key: available ? "acpAvailable" : "acpUnavailable" }), window.setTimeout(() => setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), 5e3);
2738
- } catch (reason) {
2739
- setError(messageOf(reason));
2740
- } finally {
2741
- setAcpChecking((current) => ({ ...current, [backend]: !1 }));
2742
- }
2743
- }
2744
- }, addAcp = async () => {
2745
- setBusy(!0), setError(void 0);
2538
+ };
2539
+ apply({ label: "remoteProgressCheckingHost", detail: "remoteProgressCheckingHostDetail", percent: 12 });
2540
+ let pending = action();
2541
+ poll();
2542
+ try {
2543
+ let result = await pending;
2544
+ return polling = !1, pollTimer !== void 0 && window.clearTimeout(pollTimer), apply(readyProgress?.(result) ?? { label: "remoteProgressReady", detail: "remoteProgressReadyDetail", percent: 100 }), await new Promise((resolve) => window.setTimeout(resolve, 520)), result;
2545
+ } finally {
2546
+ polling = !1, pollTimer !== void 0 && window.clearTimeout(pollTimer), progressRun.current === runId && setProgress(void 0);
2547
+ }
2548
+ }
2549
+
2550
+ // src/client/settings.ts
2551
+ function createRemotePluginOptions(React) {
2552
+ function RemotePluginOptions(props) {
2553
+ let { t } = props, [open, setOpen] = React.useState(props.view === "page"), [serverUrl, setServerUrl] = React.useState(""), [portsBusy, setPortsBusy] = React.useState(!1), [previewPorts, setPreviewPorts] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [terminalEnabled, setTerminalEnabled] = React.useState(!1), [terminalBusy, setTerminalBusy] = React.useState(!1), [acpBackends, setAcpBackends] = React.useState([]), [acpAvailability, setAcpAvailability] = React.useState({}), [acpChecking, setAcpChecking] = React.useState({}), [acpCheckResults, setAcpCheckResults] = React.useState({}), [addingAcp, setAddingAcp] = React.useState(!1), [acpName, setAcpName] = React.useState(""), [acpCommand, setAcpCommand] = React.useState(""), [acpArguments, setAcpArguments] = React.useState("acp"), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [hostName, setHostName] = React.useState(""), [hostDeviceId, setHostDeviceId] = React.useState(""), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyView = (view) => {
2554
+ setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setTerminalEnabled(view.config.terminal?.enabled ?? !0), setPreviewPorts((view.config.loopback?.ports ?? []).join(", ")), setAcpBackends((view.config.acp?.backends ?? []).map((item) => ({ id: item.id, enabled: item.enabled !== !1 }))), setAcpAvailability(view.acpAvailability ?? {}), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
2555
+ }, load = async () => {
2556
+ let [view, status] = await Promise.all([
2557
+ props.control("settings.get"),
2558
+ props.control("status").catch(() => {
2559
+ })
2560
+ ]);
2561
+ applyView(view), setHostStatus(status?.host), setHostName(status?.deviceName ?? ""), setHostDeviceId(status?.host?.deviceId ?? "");
2562
+ };
2563
+ React.useEffect(() => {
2564
+ load().catch((reason) => setError(messageOf(reason)));
2565
+ }, []), React.useEffect(() => {
2566
+ if (association !== void 0)
2567
+ return props.statusFeed.subscribe((status) => {
2568
+ setHostStatus(status.host), setHostName(status.deviceName ?? ""), setHostDeviceId(status.host?.deviceId ?? "");
2569
+ });
2570
+ }, [association !== void 0]);
2571
+ let save = async (event) => {
2572
+ if (event?.preventDefault(), !(!writable || !serverDirty)) {
2573
+ setBusy(!0), setNotice(void 0), setError(void 0);
2746
2574
  try {
2747
- let view = await props.control("settings.acp.add", {
2748
- id: acpName.trim(),
2749
- command: acpCommand.trim(),
2750
- args: acpArguments.trim() === "" ? [] : acpArguments.trim().split(/\s+/)
2575
+ let view = await props.control("settings.server.set", {
2576
+ serverUrl
2751
2577
  });
2752
- applyView(view), setAddingAcp(!1), setAcpName(""), setAcpCommand(""), setAcpArguments("acp");
2578
+ applyView(view), setNotice({ key: "serverSaved" });
2753
2579
  } catch (reason) {
2754
2580
  setError(messageOf(reason));
2755
2581
  } finally {
2756
2582
  setBusy(!1);
2757
2583
  }
2758
- }, removeAcp = async (backend) => {
2759
- setBusy(!0), setError(void 0);
2584
+ }
2585
+ }, logout = async () => {
2586
+ setBusy(!0), setError(void 0), setNotice(void 0);
2587
+ try {
2588
+ let view = await props.control("settings.logout");
2589
+ applyView(view), setRegistrationCode(""), setNotice({ key: "signedOut" });
2590
+ } catch (reason) {
2591
+ setError(messageOf(reason));
2592
+ } finally {
2593
+ setBusy(!1);
2594
+ }
2595
+ }, reconnectHost = async () => {
2596
+ setReconnectBusy(!0), setError(void 0), setNotice(void 0);
2597
+ try {
2598
+ let status = await props.control("host.reconnect");
2599
+ setHostStatus(status.host), setNotice({ key: "reconnectStarted" });
2600
+ } catch (reason) {
2601
+ setError(messageOf(reason));
2602
+ } finally {
2603
+ setReconnectBusy(!1);
2604
+ }
2605
+ }, setCurrentDeviceControl = async (enabled) => {
2606
+ setBusy(!0), setError(void 0), setNotice(void 0);
2607
+ try {
2608
+ let status = await props.control("host.authorization.set", { enabled });
2609
+ setHostStatus(status.host);
2610
+ } catch (reason) {
2611
+ setError(messageOf(reason));
2612
+ } finally {
2613
+ setBusy(!1);
2614
+ }
2615
+ }, setTerminalRemote = async (enabled) => {
2616
+ let previous = terminalEnabled, portsDraft = previewPorts;
2617
+ setTerminalEnabled(enabled), setTerminalBusy(!0), setError(void 0), setNotice(void 0);
2618
+ try {
2619
+ let view = await props.control("settings.development.set", { terminalEnabled: enabled });
2620
+ applyView(view), setPreviewPorts(portsDraft), setNotice({ key: "terminalSaved" });
2621
+ } catch (reason) {
2622
+ setTerminalEnabled(previous), setError(messageOf(reason));
2623
+ } finally {
2624
+ setTerminalBusy(!1);
2625
+ }
2626
+ }, savePreviewPorts = async () => {
2627
+ setPortsBusy(!0), setError(void 0), setNotice(void 0);
2628
+ try {
2629
+ let ports = previewPorts.trim() === "" ? [] : previewPorts.split(/[,,]/).map((value) => Number(value.trim())), view = await props.control("settings.development.set", { ports });
2630
+ applyView(view), setNotice({ key: "developmentSaved" });
2631
+ } catch (reason) {
2632
+ setError(messageOf(reason));
2633
+ } finally {
2634
+ setPortsBusy(!1);
2635
+ }
2636
+ }, checkAcp = async (backend) => {
2637
+ if (!acpChecking[backend]) {
2638
+ setAcpChecking((current) => ({ ...current, [backend]: !0 })), setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), setError(void 0);
2760
2639
  try {
2761
- let view = await props.control("settings.acp.remove", { id: backend });
2640
+ let view = await props.control("settings.get");
2762
2641
  applyView(view);
2642
+ let available = view.acpAvailability?.[backend] === !0;
2643
+ !available && view.writable && view.config.acp?.backends?.some((item) => item.id === backend && item.enabled !== !1) && applyView(await props.control("settings.acp.set", { backend, enabled: !1 })), setAcpCheckResults((current) => ({ ...current, [backend]: available })), setNotice({ key: available ? "acpAvailable" : "acpUnavailable" }), window.setTimeout(() => setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), 5e3);
2763
2644
  } catch (reason) {
2764
2645
  setError(messageOf(reason));
2765
2646
  } finally {
2766
- setBusy(!1);
2647
+ setAcpChecking((current) => ({ ...current, [backend]: !1 }));
2767
2648
  }
2768
- }, discard = () => {
2769
- settingsView !== void 0 && applyView(settingsView), setRegistrationCode(""), setNotice(void 0), setError(void 0);
2770
- }, developmentSetting = React.createElement(
2771
- "section",
2772
- { className: "dshRemoteDevelopmentSettings" },
2649
+ }
2650
+ }, addAcp = async () => {
2651
+ setBusy(!0), setError(void 0);
2652
+ try {
2653
+ let view = await props.control("settings.acp.add", {
2654
+ id: acpName.trim(),
2655
+ command: acpCommand.trim(),
2656
+ args: acpArguments.trim() === "" ? [] : acpArguments.trim().split(/\s+/)
2657
+ });
2658
+ applyView(view), setAddingAcp(!1), setAcpName(""), setAcpCommand(""), setAcpArguments("acp");
2659
+ } catch (reason) {
2660
+ setError(messageOf(reason));
2661
+ } finally {
2662
+ setBusy(!1);
2663
+ }
2664
+ }, removeAcp = async (backend) => {
2665
+ setBusy(!0), setError(void 0);
2666
+ try {
2667
+ let view = await props.control("settings.acp.remove", { id: backend });
2668
+ applyView(view);
2669
+ } catch (reason) {
2670
+ setError(messageOf(reason));
2671
+ } finally {
2672
+ setBusy(!1);
2673
+ }
2674
+ }, discard = () => {
2675
+ settingsView !== void 0 && applyView(settingsView), setRegistrationCode(""), setNotice(void 0), setError(void 0);
2676
+ }, developmentSetting = React.createElement(
2677
+ "section",
2678
+ { className: "dshRemoteDevelopmentSettings" },
2679
+ React.createElement(
2680
+ "div",
2681
+ { className: "dshRemoteAuthorizationSetting" },
2682
+ React.createElement(
2683
+ "div",
2684
+ null,
2685
+ React.createElement("strong", null, t("terminalRemote")),
2686
+ React.createElement("p", null, t("terminalRemoteHint"))
2687
+ ),
2688
+ React.createElement("input", {
2689
+ type: "checkbox",
2690
+ role: "switch",
2691
+ checked: terminalEnabled,
2692
+ disabled: busy || terminalBusy || !writable,
2693
+ "aria-label": t("terminalRemote"),
2694
+ onChange: (event) => void setTerminalRemote(event.target.checked)
2695
+ })
2696
+ ),
2697
+ React.createElement(
2698
+ "div",
2699
+ { className: "dshRemotePathField" },
2700
+ React.createElement("label", { htmlFor: "dsh-remote-preview-ports" }, t("previewPorts")),
2701
+ React.createElement(
2702
+ "div",
2703
+ { className: "dshRemotePortsRow" },
2704
+ React.createElement("input", {
2705
+ id: "dsh-remote-preview-ports",
2706
+ value: previewPorts,
2707
+ maxLength: 128,
2708
+ size: 24,
2709
+ disabled: !writable,
2710
+ placeholder: "3000, 5173",
2711
+ "aria-label": t("previewPorts"),
2712
+ onChange: (event) => setPreviewPorts(event.target.value)
2713
+ }),
2714
+ React.createElement("button", {
2715
+ type: "button",
2716
+ disabled: portsBusy || terminalBusy || !writable,
2717
+ onClick: () => void savePreviewPorts()
2718
+ }, t("developmentSave"))
2719
+ ),
2720
+ React.createElement("small", null, t("previewPortsHint"))
2721
+ )
2722
+ ), acpSetting = React.createElement(
2723
+ "details",
2724
+ { className: "dshRemoteAuthorizationSetting dshRemoteAcpSetting" },
2725
+ React.createElement(
2726
+ "summary",
2727
+ null,
2773
2728
  React.createElement(
2774
2729
  "div",
2775
- { className: "dshRemoteAuthorizationSetting" },
2730
+ { className: "dshRemoteAcpSummaryText" },
2731
+ React.createElement("strong", null, t("agentBackends")),
2732
+ React.createElement("p", null, t("acpHint"), React.createElement("a", {
2733
+ href: "https://github.com/liguobao/ds-harness-remote/blob/feat/cursor-remote/docs/acp-remote.md",
2734
+ target: "_blank",
2735
+ rel: "noopener noreferrer",
2736
+ onClick: (event) => event.stopPropagation()
2737
+ }, t("acpDocumentation")))
2738
+ )
2739
+ ),
2740
+ React.createElement(
2741
+ "div",
2742
+ { className: "dshRemoteAcpList" },
2743
+ acpBackends.map((item) => React.createElement(
2744
+ "div",
2745
+ { key: item.id, className: "dshRemoteAuthorizationSetting" },
2746
+ React.createElement("div", null, React.createElement("strong", null, item.id === "codex" ? "CodeX" : item.id === "cursor" ? "Cursor" : item.id === "antigravity" ? "AGY" : item.id === "pi" ? "PI" : item.id === "opencode" ? "OpenCode" : item.id), null),
2776
2747
  React.createElement(
2777
- "div",
2778
- null,
2779
- React.createElement("strong", null, t("terminalRemote")),
2780
- React.createElement("p", null, t("terminalRemoteHint"))
2748
+ "span",
2749
+ { className: "dshRemoteAcpCheckCell" },
2750
+ React.createElement(
2751
+ "a",
2752
+ { href: `#check-acp-${item.id}`, className: `dshRemoteAcpCheckLink${acpChecking[item.id] ? " isChecking" : acpCheckResults[item.id] === void 0 ? "" : acpCheckResults[item.id] ? " isPassed" : " isFailed"}`, onClick: (event) => {
2753
+ event.preventDefault(), checkAcp(item.id);
2754
+ } },
2755
+ acpChecking[item.id] ? t("checkingAcp") : acpCheckResults[item.id] === void 0 ? t("checkAcp") : t(acpCheckResults[item.id] ? "acpCheckPassed" : "acpCheckFailed")
2756
+ )
2781
2757
  ),
2758
+ ["codex", "cursor", "antigravity", "pi", "opencode"].includes(item.id) ? null : React.createElement("a", { href: `#remove-acp-${item.id}`, className: "dshRemoteAcpRemoveLink", onClick: (event) => {
2759
+ event.preventDefault(), removeAcp(item.id);
2760
+ } }, t("removeAcp")),
2782
2761
  React.createElement("input", {
2783
2762
  type: "checkbox",
2784
2763
  role: "switch",
2785
- checked: terminalEnabled,
2786
- disabled: busy || terminalBusy || !writable,
2787
- "aria-label": t("terminalRemote"),
2788
- onChange: (event) => void setTerminalRemote(event.target.checked)
2764
+ checked: settingsView?.config.acp?.enabled === !0 && item.enabled && acpAvailability[item.id] === !0,
2765
+ "aria-label": item.id,
2766
+ disabled: busy || !writable || acpChecking[item.id] === !0 || acpAvailability[item.id] !== !0,
2767
+ onChange: (event) => void props.control("settings.acp.set", { backend: item.id, enabled: event.target.checked }).then((view) => {
2768
+ applyView(view), setAcpBackends((view.config.acp?.backends ?? []).map((v) => ({ id: v.id, enabled: v.enabled !== !1 })));
2769
+ }).catch((reason) => setError(messageOf(reason)))
2789
2770
  })
2790
- ),
2791
- React.createElement(
2771
+ )),
2772
+ addingAcp ? React.createElement(
2792
2773
  "div",
2793
- { className: "dshRemotePathField" },
2794
- React.createElement("label", { htmlFor: "dsh-remote-preview-ports" }, t("previewPorts")),
2795
- React.createElement(
2796
- "div",
2797
- { className: "dshRemotePortsRow" },
2798
- React.createElement("input", {
2799
- id: "dsh-remote-preview-ports",
2800
- value: previewPorts,
2801
- maxLength: 128,
2802
- size: 24,
2803
- disabled: !writable,
2804
- placeholder: "3000, 5173",
2805
- "aria-label": t("previewPorts"),
2806
- onChange: (event) => setPreviewPorts(event.target.value)
2807
- }),
2808
- React.createElement("button", {
2809
- type: "button",
2810
- disabled: portsBusy || terminalBusy || !writable,
2811
- onClick: () => void savePreviewPorts()
2812
- }, t("developmentSave"))
2813
- ),
2814
- React.createElement("small", null, t("previewPortsHint"))
2815
- )
2816
- ), acpSetting = React.createElement(
2817
- "details",
2818
- { className: "dshRemoteAuthorizationSetting dshRemoteAcpSetting" },
2774
+ { className: "dshRemoteAcpAddForm" },
2775
+ React.createElement("label", null, t("acpName"), React.createElement("input", { value: acpName, size: 16, placeholder: t("acpName"), "aria-label": t("acpName"), onChange: (event) => setAcpName(event.target.value) })),
2776
+ React.createElement("label", null, t("acpCommand"), React.createElement("input", { value: acpCommand, size: 20, placeholder: t("acpCommand"), "aria-label": t("acpCommand"), onChange: (event) => setAcpCommand(event.target.value) })),
2777
+ React.createElement("label", null, t("acpArguments"), React.createElement("input", { value: acpArguments, size: 20, placeholder: t("acpArguments"), "aria-label": t("acpArguments"), onChange: (event) => setAcpArguments(event.target.value) })),
2778
+ React.createElement("button", { type: "button", disabled: busy || acpName.trim() === "" || acpCommand.trim() === "", onClick: () => void addAcp() }, t("addAcp"))
2779
+ ) : React.createElement("a", { href: "#add-acp", className: "dshRemoteAcpAddLink", onClick: (event) => {
2780
+ event.preventDefault(), setAddingAcp(!0);
2781
+ } }, t("addAcp"))
2782
+ )
2783
+ );
2784
+ return props.view === "summary" ? React.createElement("span", null, t("pluginDescription")) : React.createElement(
2785
+ props.view === "page" ? "div" : "li",
2786
+ { className: `dshRemotePluginCard${open ? " isOpen" : ""}${props.view === "page" ? " dshRemotePluginModern" : ""}` },
2787
+ React.createElement(
2788
+ "div",
2789
+ { className: "dshRemotePluginCardHeader" },
2819
2790
  React.createElement(
2820
- "summary",
2821
- null,
2791
+ "button",
2792
+ {
2793
+ type: "button",
2794
+ className: "dshRemotePluginCardToggle",
2795
+ "aria-expanded": open,
2796
+ "aria-label": t(open ? "collapseSettings" : "expandSettings", { name: t("pluginTitle") }),
2797
+ onClick: () => setOpen((current) => !current)
2798
+ },
2822
2799
  React.createElement(
2823
- "div",
2824
- { className: "dshRemoteAcpSummaryText" },
2825
- React.createElement("strong", null, t("agentBackends")),
2826
- React.createElement("p", null, t("acpHint"), React.createElement("a", {
2827
- href: "https://github.com/liguobao/ds-harness-remote/blob/feat/cursor-remote/docs/acp-remote.md",
2828
- target: "_blank",
2829
- rel: "noopener noreferrer",
2830
- onClick: (event) => event.stopPropagation()
2831
- }, t("acpDocumentation")))
2832
- )
2833
- ),
2834
- React.createElement(
2835
- "div",
2836
- { className: "dshRemoteAcpList" },
2837
- acpBackends.map((item) => React.createElement(
2838
- "div",
2839
- { key: item.id, className: "dshRemoteAuthorizationSetting" },
2840
- React.createElement("div", null, React.createElement("strong", null, item.id === "codex" ? "CodeX" : item.id === "cursor" ? "Cursor" : item.id === "antigravity" ? "AGY" : item.id), null),
2841
- React.createElement(
2842
- "span",
2843
- { className: "dshRemoteAcpCheckCell" },
2844
- React.createElement(
2845
- "a",
2846
- { href: `#check-acp-${item.id}`, className: `dshRemoteAcpCheckLink${acpChecking[item.id] ? " isChecking" : acpCheckResults[item.id] === void 0 ? "" : acpCheckResults[item.id] ? " isPassed" : " isFailed"}`, onClick: (event) => {
2847
- event.preventDefault(), checkAcp(item.id);
2848
- } },
2849
- acpChecking[item.id] ? t("checkingAcp") : acpCheckResults[item.id] === void 0 ? t("checkAcp") : t(acpCheckResults[item.id] ? "acpCheckPassed" : "acpCheckFailed")
2850
- )
2851
- ),
2852
- ["codex", "cursor", "antigravity"].includes(item.id) ? null : React.createElement("a", { href: `#remove-acp-${item.id}`, className: "dshRemoteAcpRemoveLink", onClick: (event) => {
2853
- event.preventDefault(), removeAcp(item.id);
2854
- } }, t("removeAcp")),
2855
- React.createElement("input", {
2856
- type: "checkbox",
2857
- role: "switch",
2858
- checked: settingsView?.config.acp?.enabled === !0 && item.enabled && acpAvailability[item.id] === !0,
2859
- "aria-label": item.id,
2860
- disabled: busy || !writable || acpChecking[item.id] === !0 || acpAvailability[item.id] !== !0,
2861
- onChange: (event) => void props.control("settings.acp.set", { backend: item.id, enabled: event.target.checked }).then((view) => {
2862
- applyView(view), setAcpBackends((view.config.acp?.backends ?? []).map((v) => ({ id: v.id, enabled: v.enabled !== !1 })));
2863
- }).catch((reason) => setError(messageOf(reason)))
2864
- })
2865
- )),
2866
- addingAcp ? React.createElement(
2867
- "div",
2868
- { className: "dshRemoteAcpAddForm" },
2869
- React.createElement("label", null, t("acpName"), React.createElement("input", { value: acpName, size: 16, placeholder: t("acpName"), "aria-label": t("acpName"), onChange: (event) => setAcpName(event.target.value) })),
2870
- React.createElement("label", null, t("acpCommand"), React.createElement("input", { value: acpCommand, size: 20, placeholder: t("acpCommand"), "aria-label": t("acpCommand"), onChange: (event) => setAcpCommand(event.target.value) })),
2871
- React.createElement("label", null, t("acpArguments"), React.createElement("input", { value: acpArguments, size: 20, placeholder: t("acpArguments"), "aria-label": t("acpArguments"), onChange: (event) => setAcpArguments(event.target.value) })),
2872
- React.createElement("button", { type: "button", disabled: busy || acpName.trim() === "" || acpCommand.trim() === "", onClick: () => void addAcp() }, t("addAcp"))
2873
- ) : React.createElement("a", { href: "#add-acp", className: "dshRemoteAcpAddLink", onClick: (event) => {
2874
- event.preventDefault(), setAddingAcp(!0);
2875
- } }, t("addAcp"))
2800
+ "span",
2801
+ { className: "dshRemotePluginCardHeading" },
2802
+ React.createElement("strong", null, t("pluginTitle")),
2803
+ React.createElement("span", null, t("pluginDescription"))
2804
+ ),
2805
+ draftDirty ? React.createElement("span", { className: "dshRemotePluginCardStatus" }, t("unsaved")) : association === void 0 ? null : React.createElement("span", {
2806
+ className: `dshRemotePluginCardStatus${connectionStatusClass(hostStatus)}`
2807
+ }, hostStatus === void 0 ? t("associated") : connectionStatusLabel(hostStatus, t)),
2808
+ React.createElement("span", { className: "dshRemotePluginCardChevron", "aria-hidden": !0 }, "\u2304")
2876
2809
  )
2877
- );
2878
- return props.view === "summary" ? React.createElement("span", null, t("pluginDescription")) : React.createElement(
2879
- props.view === "page" ? "div" : "li",
2880
- { className: `dshRemotePluginCard${open ? " isOpen" : ""}${props.view === "page" ? " dshRemotePluginModern" : ""}` },
2881
- React.createElement(
2810
+ ),
2811
+ open ? React.createElement(
2812
+ "div",
2813
+ { className: "dshRemotePluginCardBody" },
2814
+ loaded ? association !== void 0 ? React.createElement(
2882
2815
  "div",
2883
- { className: "dshRemotePluginCardHeader" },
2816
+ { className: "dshRemoteSettings" },
2884
2817
  React.createElement(
2885
- "button",
2886
- {
2887
- type: "button",
2888
- className: "dshRemotePluginCardToggle",
2889
- "aria-expanded": open,
2890
- "aria-label": t(open ? "collapseSettings" : "expandSettings", { name: t("pluginTitle") }),
2891
- onClick: () => setOpen((current) => !current)
2892
- },
2893
- React.createElement(
2894
- "span",
2895
- { className: "dshRemotePluginCardHeading" },
2896
- React.createElement("strong", null, t("pluginTitle")),
2897
- React.createElement("span", null, t("pluginDescription"))
2898
- ),
2899
- draftDirty ? React.createElement("span", { className: "dshRemotePluginCardStatus" }, t("unsaved")) : association === void 0 ? null : React.createElement("span", {
2900
- className: `dshRemotePluginCardStatus${connectionStatusClass(hostStatus)}`
2901
- }, hostStatus === void 0 ? t("associated") : connectionStatusLabel(hostStatus, t)),
2902
- React.createElement("span", { className: "dshRemotePluginCardChevron", "aria-hidden": !0 }, "\u2304")
2903
- )
2904
- ),
2905
- open ? React.createElement(
2906
- "div",
2907
- { className: "dshRemotePluginCardBody" },
2908
- loaded ? association !== void 0 ? React.createElement(
2909
2818
  "div",
2910
- { className: "dshRemoteSettings" },
2911
- React.createElement(
2912
- "div",
2913
- { className: "dshRemoteSettingsTop" },
2914
- React.createElement(
2915
- "div",
2916
- { className: "dshRemoteAssociation" },
2917
- React.createElement("span", null, t(association.account === void 0 ? "authorization" : "account")),
2918
- React.createElement("strong", null, association.account ?? t("authorizationComplete")),
2919
- React.createElement("p", null, association.account === void 0 ? serverUrl : t("authorizedOn", { role: "Remote", serverUrl }))
2920
- )
2921
- ),
2819
+ { className: "dshRemoteSettingsTop" },
2922
2820
  React.createElement(
2923
2821
  "div",
2924
- { className: "dshRemoteHostIdentity" },
2925
- React.createElement(
2926
- "div",
2927
- null,
2928
- React.createElement("span", null, t("hostName")),
2929
- React.createElement("strong", null, hostName || "\u2014")
2930
- ),
2931
- React.createElement(
2932
- "div",
2933
- null,
2934
- React.createElement("span", null, t("deviceId")),
2935
- React.createElement("code", null, hostDeviceId || "\u2014")
2936
- )
2937
- ),
2822
+ { className: "dshRemoteAssociation" },
2823
+ React.createElement("span", null, t(association.account === void 0 ? "authorization" : "account")),
2824
+ React.createElement("strong", null, association.account ?? t("authorizationComplete")),
2825
+ React.createElement("p", null, association.account === void 0 ? serverUrl : t("authorizedOn", { role: "Remote", serverUrl }))
2826
+ )
2827
+ ),
2828
+ React.createElement(
2829
+ "div",
2830
+ { className: "dshRemoteHostIdentity" },
2938
2831
  React.createElement(
2939
2832
  "div",
2940
- { className: "dshRemoteField" },
2941
- React.createElement("label", { htmlFor: "dsh-remote-server-url-authorized" }, t("serverUrl")),
2942
- React.createElement("input", {
2943
- id: "dsh-remote-server-url-authorized",
2944
- type: "url",
2945
- value: serverUrl,
2946
- disabled: !0,
2947
- required: !0,
2948
- placeholder: "https://dsh.r2049.cn",
2949
- onChange: (event) => {
2950
- setServerUrl(event.target.value), setNotice(void 0);
2951
- }
2952
- }),
2953
- React.createElement("p", null, t("serverUrlHint"))
2833
+ null,
2834
+ React.createElement("span", null, t("hostName")),
2835
+ React.createElement("strong", null, hostName || "\u2014")
2954
2836
  ),
2955
- developmentSetting,
2956
- acpSetting,
2957
2837
  React.createElement(
2958
2838
  "div",
2959
- { className: "dshRemoteAuthorizationSetting" },
2960
- React.createElement(
2961
- "div",
2962
- null,
2963
- React.createElement("strong", null, t("allowControlCurrentDevice")),
2964
- React.createElement("p", null, t("thisMachineHost"))
2965
- ),
2966
- React.createElement("input", {
2967
- type: "checkbox",
2968
- role: "switch",
2969
- disabled: busy,
2970
- "aria-label": t("allowControlCurrentDevice"),
2971
- checked: hostStatus?.authorized === !0,
2972
- onChange: (event) => void setCurrentDeviceControl(event.target.checked)
2973
- })
2974
- ),
2839
+ null,
2840
+ React.createElement("span", null, t("deviceId")),
2841
+ React.createElement("code", null, hostDeviceId || "\u2014")
2842
+ )
2843
+ ),
2844
+ React.createElement(
2845
+ "div",
2846
+ { className: "dshRemoteField" },
2847
+ React.createElement("label", { htmlFor: "dsh-remote-server-url-authorized" }, t("serverUrl")),
2848
+ React.createElement("input", {
2849
+ id: "dsh-remote-server-url-authorized",
2850
+ type: "url",
2851
+ value: serverUrl,
2852
+ disabled: !0,
2853
+ required: !0,
2854
+ placeholder: "https://dsh.r2049.cn",
2855
+ onChange: (event) => {
2856
+ setServerUrl(event.target.value), setNotice(void 0);
2857
+ }
2858
+ }),
2859
+ React.createElement("p", null, t("serverUrlHint"))
2860
+ ),
2861
+ developmentSetting,
2862
+ acpSetting,
2863
+ React.createElement(
2864
+ "div",
2865
+ { className: "dshRemoteAuthorizationSetting" },
2975
2866
  React.createElement(
2976
2867
  "div",
2977
- { className: "dshRemoteConnection", "aria-live": "polite" },
2978
- React.createElement(
2979
- "div",
2980
- { className: "dshRemoteConnectionSummary" },
2981
- React.createElement("span", null, t("connection")),
2982
- React.createElement(
2983
- "strong",
2984
- null,
2985
- React.createElement("span", {
2986
- className: `dshRemoteConnectionDot${connectionStatusClass(hostStatus)}`,
2987
- "aria-hidden": !0
2988
- }),
2989
- connectionStatusLabel(hostStatus, t)
2990
- ),
2991
- React.createElement("p", null, hostStatus === void 0 ? t("checkingConnection") : hostStatus.lastActiveAt === void 0 ? t("neverConnected") : t("lastActive", { time: formatLocalTime(hostStatus.lastActiveAt) }))
2992
- ),
2993
- React.createElement("button", {
2994
- type: "button",
2995
- className: "dshRemoteReconnect",
2996
- disabled: reconnectBusy || hostStatus?.configured === !1,
2997
- onClick: () => void reconnectHost()
2998
- }, t(reconnectBusy ? "reconnectingAction" : "reconnect"))
2868
+ null,
2869
+ React.createElement("strong", null, t("allowControlCurrentDevice")),
2870
+ React.createElement("p", null, t("thisMachineHost"))
2999
2871
  ),
3000
- hostStatus?.error === void 0 || hostStatus.online ? null : React.createElement("p", { className: "dshRemoteConnectionIssue", role: "status" }, connectionErrorMessage(hostStatus.error, t)),
3001
- writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
3002
- React.createElement(
3003
- "div",
3004
- { className: "dshRemoteSettingsFooter" },
3005
- React.createElement("p", {
3006
- className: error !== void 0 ? "dshRemoteError" : "dshRemoteNotice",
3007
- role: error !== void 0 ? "alert" : "status"
3008
- }, error ?? (notice === void 0 ? "" : t(notice.key, notice.params))),
3009
- draftDirty ? React.createElement(
3010
- React.Fragment,
3011
- null,
3012
- React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy, onClick: discard }, t("discard")),
3013
- React.createElement("button", { type: "button", className: "dshRemoteSave", disabled: busy || !writable, onClick: () => void save() }, t(busy ? "saving" : "save")),
3014
- React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy || !writable, onClick: () => void logout() }, t(busy ? "signingOut" : "signOut"))
3015
- ) : React.createElement("button", {
3016
- type: "button",
3017
- className: "dshRemoteDiscard",
3018
- disabled: busy || !writable,
3019
- onClick: () => void logout()
3020
- }, t(busy ? "signingOut" : "signOut"))
3021
- )
3022
- ) : React.createElement(
3023
- "form",
3024
- { className: "dshRemoteSettings", noValidate: !0, onSubmit: (event) => void save(event) },
2872
+ React.createElement("input", {
2873
+ type: "checkbox",
2874
+ role: "switch",
2875
+ disabled: busy,
2876
+ "aria-label": t("allowControlCurrentDevice"),
2877
+ checked: hostStatus?.authorized === !0,
2878
+ onChange: (event) => void setCurrentDeviceControl(event.target.checked)
2879
+ })
2880
+ ),
2881
+ React.createElement(
2882
+ "div",
2883
+ { className: "dshRemoteConnection", "aria-live": "polite" },
3025
2884
  React.createElement(
3026
2885
  "div",
3027
- { className: "dshRemoteHostIdentity" },
2886
+ { className: "dshRemoteConnectionSummary" },
2887
+ React.createElement("span", null, t("connection")),
3028
2888
  React.createElement(
3029
- "div",
2889
+ "strong",
3030
2890
  null,
3031
- React.createElement("span", null, t("hostName")),
3032
- React.createElement("strong", null, hostName || "\u2014")
2891
+ React.createElement("span", {
2892
+ className: `dshRemoteConnectionDot${connectionStatusClass(hostStatus)}`,
2893
+ "aria-hidden": !0
2894
+ }),
2895
+ connectionStatusLabel(hostStatus, t)
3033
2896
  ),
3034
- React.createElement(
3035
- "div",
3036
- null,
3037
- React.createElement("span", null, t("deviceId")),
3038
- React.createElement("code", null, hostDeviceId || "\u2014")
3039
- )
2897
+ React.createElement("p", null, hostStatus === void 0 ? t("checkingConnection") : hostStatus.lastActiveAt === void 0 ? t("neverConnected") : t("lastActive", { time: formatLocalTime(hostStatus.lastActiveAt) }))
3040
2898
  ),
2899
+ React.createElement("button", {
2900
+ type: "button",
2901
+ className: "dshRemoteReconnect",
2902
+ disabled: reconnectBusy || hostStatus?.configured === !1,
2903
+ onClick: () => void reconnectHost()
2904
+ }, t(reconnectBusy ? "reconnectingAction" : "reconnect"))
2905
+ ),
2906
+ hostStatus?.error === void 0 || hostStatus.online ? null : React.createElement("p", { className: "dshRemoteConnectionIssue", role: "status" }, connectionErrorMessage(hostStatus.error, t)),
2907
+ writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
2908
+ React.createElement(
2909
+ "div",
2910
+ { className: "dshRemoteSettingsFooter" },
2911
+ React.createElement("p", {
2912
+ className: error !== void 0 ? "dshRemoteError" : "dshRemoteNotice",
2913
+ role: error !== void 0 ? "alert" : "status"
2914
+ }, error ?? (notice === void 0 ? "" : t(notice.key, notice.params))),
2915
+ draftDirty ? React.createElement(
2916
+ React.Fragment,
2917
+ null,
2918
+ React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy, onClick: discard }, t("discard")),
2919
+ React.createElement("button", { type: "button", className: "dshRemoteSave", disabled: busy || !writable, onClick: () => void save() }, t(busy ? "saving" : "save")),
2920
+ React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy || !writable, onClick: () => void logout() }, t(busy ? "signingOut" : "signOut"))
2921
+ ) : React.createElement("button", {
2922
+ type: "button",
2923
+ className: "dshRemoteDiscard",
2924
+ disabled: busy || !writable,
2925
+ onClick: () => void logout()
2926
+ }, t(busy ? "signingOut" : "signOut"))
2927
+ )
2928
+ ) : React.createElement(
2929
+ "form",
2930
+ { className: "dshRemoteSettings", noValidate: !0, onSubmit: (event) => void save(event) },
2931
+ React.createElement(
2932
+ "div",
2933
+ { className: "dshRemoteHostIdentity" },
3041
2934
  React.createElement(
3042
2935
  "div",
3043
- { className: "dshRemoteField" },
3044
- React.createElement("label", { htmlFor: "dsh-remote-server-url" }, t("serverUrl")),
3045
- React.createElement("input", {
3046
- id: "dsh-remote-server-url",
3047
- type: "url",
3048
- value: serverUrl,
3049
- disabled: busy || !writable,
3050
- required: !0,
3051
- placeholder: "https://dsh.r2049.cn",
3052
- onChange: (event) => {
3053
- setServerUrl(event.target.value), setNotice(void 0);
3054
- }
3055
- }),
3056
- React.createElement("p", null, t("serverUrlHint"))
2936
+ null,
2937
+ React.createElement("span", null, t("hostName")),
2938
+ React.createElement("strong", null, hostName || "\u2014")
3057
2939
  ),
3058
- developmentSetting,
3059
- acpSetting,
3060
- React.createElement("p", { className: "dshRemoteSettingsState" }, t("authorizeFromRemote")),
3061
- writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
3062
2940
  React.createElement(
3063
2941
  "div",
3064
- { className: "dshRemoteSettingsFooter" },
3065
- React.createElement("p", {
3066
- className: error !== void 0 ? "dshRemoteError" : "dshRemoteNotice",
3067
- role: error !== void 0 ? "alert" : "status"
3068
- }, error ?? (notice === void 0 ? "" : t(notice.key, notice.params))),
3069
- React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy || !draftDirty, onClick: discard }, t("discard")),
3070
- React.createElement("button", { type: "submit", className: "dshRemoteSave", disabled: busy || !writable || !serverDirty }, t(busy ? "saving" : "save"))
2942
+ null,
2943
+ React.createElement("span", null, t("deviceId")),
2944
+ React.createElement("code", null, hostDeviceId || "\u2014")
3071
2945
  )
3072
- ) : React.createElement("p", { className: "dshRemoteSettingsState" }, error ?? t("loadingSettings"))
3073
- ) : null
3074
- );
2946
+ ),
2947
+ React.createElement(
2948
+ "div",
2949
+ { className: "dshRemoteField" },
2950
+ React.createElement("label", { htmlFor: "dsh-remote-server-url" }, t("serverUrl")),
2951
+ React.createElement("input", {
2952
+ id: "dsh-remote-server-url",
2953
+ type: "url",
2954
+ value: serverUrl,
2955
+ disabled: busy || !writable,
2956
+ required: !0,
2957
+ placeholder: "https://dsh.r2049.cn",
2958
+ onChange: (event) => {
2959
+ setServerUrl(event.target.value), setNotice(void 0);
2960
+ }
2961
+ }),
2962
+ React.createElement("p", null, t("serverUrlHint"))
2963
+ ),
2964
+ developmentSetting,
2965
+ acpSetting,
2966
+ React.createElement("p", { className: "dshRemoteSettingsState" }, t("authorizeFromRemote")),
2967
+ writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
2968
+ React.createElement(
2969
+ "div",
2970
+ { className: "dshRemoteSettingsFooter" },
2971
+ React.createElement("p", {
2972
+ className: error !== void 0 ? "dshRemoteError" : "dshRemoteNotice",
2973
+ role: error !== void 0 ? "alert" : "status"
2974
+ }, error ?? (notice === void 0 ? "" : t(notice.key, notice.params))),
2975
+ React.createElement("button", { type: "button", className: "dshRemoteDiscard", disabled: busy || !draftDirty, onClick: discard }, t("discard")),
2976
+ React.createElement("button", { type: "submit", className: "dshRemoteSave", disabled: busy || !writable || !serverDirty }, t(busy ? "saving" : "save"))
2977
+ )
2978
+ ) : React.createElement("p", { className: "dshRemoteSettingsState" }, error ?? t("loadingSettings"))
2979
+ ) : null
2980
+ );
2981
+ }
2982
+ return RemotePluginOptions;
2983
+ }
2984
+
2985
+ // src/client/shell.ts
2986
+ function installStyle(clientModuleId2) {
2987
+ let style = document.createElement("style");
2988
+ return style.dataset.plugin = clientModuleId2, style.dataset.pluginCss = "dsh-remote", style.textContent = [
2989
+ 'html.dshRemoteTargetActive button[aria-label="\u6DFB\u52A0\u5DE5\u4F5C\u533A"],html.dshRemoteTargetActive button[aria-label="Add workspace"]{display:none!important}',
2990
+ 'html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="\u6307\u4EE4"],html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="Commands"]{display:none!important}',
2991
+ "[data-dsh-remote-hidden-action]{display:none!important}",
2992
+ // The 0.1.6 right sidebar occupies the same shell header area as the
2993
+ // remote status strip. Hide the strip while that sidebar is expanded;
2994
+ // the sidebar itself remains the active context for terminal/files.
2995
+ ":has([data-sidebar-right-open]) .dshRemoteSessionHeader{display:none!important}",
2996
+ // TerminalRecovery renders a retry action in the conversation header.
2997
+ // A failed remote terminal is reported when its tab is opened/closed;
2998
+ // keeping this background recovery action out of the top-left header
2999
+ // avoids overlapping the session controls.
3000
+ '[title^="\u6062\u590D\u7EC8\u7AEF\u5931\u8D25"],[title^="Terminal recovery failed"]{display:none!important}',
3001
+ ".dshRemoteTerminalUnavailable{box-sizing:border-box;margin:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font-size:13px;line-height:1.5}",
3002
+ ".dshRemoteModeButton{min-height:36px;border:0;background:transparent;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;padding:0 10px;border-radius:8px}.dshRemoteModeButton:is(button){cursor:pointer}",
3003
+ ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
3004
+ // Keep additive footer actions in reading order above the Settings seat.
3005
+ '[class*="_footArea"]:has(.dshRemoteSidebarEntry){flex-direction:column!important;align-items:stretch;gap:0}[class*="_footerActions"]:has(.dshRemoteSidebarEntry){display:flex!important;flex-direction:column;align-items:stretch}[class*="_footerActions"]:has(.dshRemoteSidebarEntry.isRail){align-items:center}',
3006
+ '[class*="_footerActions"]:has(.dshRemoteSidebarEntry.isWide) .bt-return{justify-content:flex-start}',
3007
+ // Bot mode seats its account beside Connect plugins. Keep that row intact
3008
+ // and let Remote span a separate row underneath it.
3009
+ '[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide){display:grid!important;grid-template-columns:36px minmax(0,1fr);align-items:center;gap:8px 9px}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_footerActions"]{display:contents!important}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_footerActions"]>div:not(.dshRemoteSidebarEntry){display:contents!important}',
3010
+ '[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide) .bt-connect-wrap{grid-column:2;grid-row:1}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_settingsArea"]{grid-column:1;grid-row:1;width:36px!important}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide) .dshRemoteSidebarEntry.isWide{display:block!important;grid-column:1/-1;grid-row:2;margin:0}',
3011
+ '[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide){grid-template-columns:36px minmax(0,1fr) 36px}[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide) .bt-foot-account{grid-column:1;grid-row:1}[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide)>[class*="_settingsArea"]{grid-column:3}',
3012
+ ".dshRemoteSidebarEntry{box-sizing:border-box;flex:none;width:36px;min-width:36px;display:block}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:36px;height:36px;min-height:36px;justify-content:center;gap:0;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isWide{width:100%;min-width:0;height:36px;margin:4px 0}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{width:100%;min-width:0;justify-content:flex-start;gap:8px;padding:0 14px;border-radius:8px;font:inherit;font-size:14px;line-height:20px;text-align:start}.dshRemoteSidebarLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteSidebarEntry.isRail{height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{margin:8px 0 10px}.dshRemoteSidebarEntry.isActive .dshRemoteComputerIcon{color:var(--dsw-alias-brand-primary)}.dshRemoteSidebarEntry .dshRemoteModeButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteSidebarEntry .dshRemoteModeButton:disabled{opacity:.45;cursor:default}",
3013
+ ".dshRemoteComputerIcon{box-sizing:border-box;width:18px;height:18px;flex:0 0 18px;color:var(--dsw-alias-label-secondary)}",
3014
+ ".dshRemoteSidebarEntry.isWide{position:relative}.dshRemoteSidebarEntry.isWide.isActive .dshRemoteModeButton{padding-inline-end:64px}.dshRemoteExitLink{position:absolute;inset-block-start:0;inset-inline-end:8px;min-width:44px;height:36px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);padding:0 6px;font:inherit;font-size:12px;line-height:20px;white-space:nowrap;cursor:pointer}.dshRemoteExitLink:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default}",
3015
+ // The strip sits inside the 40px Windows caption row, which the shell declares as the
3016
+ // window drag region. Without an explicit opt-out every press starts a window drag and
3017
+ // never reaches these buttons; the shell's own caption controls (sidebar toggle, new
3018
+ // session, the caption menus) opt out of that region the same way.
3019
+ '.dshRemoteSessionHeader{position:fixed;z-index:25;-webkit-app-region:no-drag;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteSessionTarget{min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteHeaderExitLink{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:3px 2px;font:inherit;text-decoration:none;cursor:pointer}.dshRemoteHeaderExitLink:hover{text-decoration:underline;color:var(--dsw-alias-label-primary)}.dshRemoteHeaderExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}.dshRemoteNetwork:focus-visible,.dshRemoteHeaderExitLink:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26;-webkit-app-region:no-drag}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
3020
+ ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:auto;right:104px;transform:none;max-width:calc(100vw - 124px)}}",
3021
+ ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
3022
+ ".dshRemotePage{width:min(720px,100%);max-height:min(760px,calc(100vh - 40px));display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;overflow:hidden;animation:dshRemotePageIn .18s cubic-bezier(.25,1,.5,1)}",
3023
+ ".dshRemotePageHeader{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:14px 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemotePageIntro{min-width:0;flex:1}.dshRemotePageHeader strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:18px;line-height:1.4}.dshRemotePageHeader p{min-width:0;max-width:70ch;margin:3px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.dshRemotePageActions{flex:0 0 auto;display:flex;align-items:center;gap:4px}.dshRemotePageActions>button{height:40px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:inherit;line-height:1;cursor:pointer}.dshRemotePageActions>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemotePageActions>button:disabled{opacity:.45;cursor:default}.dshRemotePageBack,.dshRemotePageRefresh{min-width:48px;padding:0 10px;font:inherit;font-size:13px}.dshRemotePageBack{color:var(--dsw-alias-label-secondary)!important}.dshRemotePageClose{width:40px;padding:0;font-size:24px}",
3024
+ ".dshRemotePageBody{padding:24px;overflow:auto;display:flex;flex-direction:column;gap:24px}.dshRemotePageBody button{font:inherit;color:inherit}",
3025
+ ".dshRemotePageTitleRow{display:flex;align-items:center;gap:10px;min-width:0}.dshRemotePageTitleRow>strong{min-width:0;flex:0 1 auto}.dshRemoteStarLink{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400;text-decoration:none}.dshRemoteStarLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-offset:3px}.dshRemoteStarLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;border-radius:3px}",
3026
+ ".dshRemoteSectionHeading{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:10px}.dshRemoteSectionTitle{min-width:0;display:flex;align-items:center;gap:10px}.dshRemoteSectionTitle>strong{font-size:14px}.dshRemoteSectionActions{display:flex;align-items:center;gap:14px}.dshRemoteSectionActions>button{border:0;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;padding:5px 0;font-size:12px}.dshRemoteSectionActions>button:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}",
3027
+ ".dshRemoteSectionTitle{flex:1}.dshRemoteSectionTitle>.dshRemoteConnectedMenu{margin-left:auto}",
3028
+ '.dshRemoteAcpSetting{display:block!important;width:100%;padding:0}.dshRemoteAcpSetting>summary{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;cursor:pointer;list-style:none}.dshRemoteAcpSetting>summary::-webkit-details-marker{display:none}.dshRemoteAcpSetting>summary::after{content:"\u2304";color:var(--dsw-alias-label-secondary);transition:transform .18s ease-out}.dshRemoteAcpSetting[open]>summary::after{transform:rotate(180deg)}.dshRemoteAcpSummaryText{min-width:0}.dshRemoteAcpSummaryText strong{display:block}.dshRemoteAcpSummaryText p{margin:4px 0 0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.4}.dshRemoteAcpCheckLink{grid-column:2;grid-row:1;color:var(--dsw-alias-brand-primary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpCheckLink:hover{color:var(--dsw-alias-label-primary)}.dshRemoteAcpCheckResult{grid-column:3;grid-row:1;font-size:11px;line-height:1.4;white-space:nowrap}.dshRemoteAcpCheckResult.isPassed{color:var(--dsw-alias-state-success-primary)}.dshRemoteAcpCheckResult.isFailed{color:var(--dsw-alias-state-danger-primary)}.dshRemoteAcpList{display:flex;flex-direction:column;gap:0;margin-top:12px;padding-top:0;border-top:0}.dshRemoteAcpList>.dshRemoteAuthorizationSetting{display:grid;width:100%;grid-template-columns:minmax(0,1fr) auto auto auto auto;align-items:center;column-gap:18px;line-height:1.4}.dshRemoteAcpList>.dshRemoteAuthorizationSetting>span:first-child{min-width:0;line-height:1.4}.dshRemoteAcpList>.dshRemoteAuthorizationSetting>input{grid-column:4;grid-row:1}',
3029
+ ".dshRemoteAcpAddLink{align-self:flex-start;margin-top:12px;color:var(--dsw-alias-brand-primary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpAddForm{display:grid;grid-template-columns:minmax(100px,.8fr) minmax(140px,1fr) minmax(100px,1fr) auto;gap:8px;margin-top:12px}.dshRemoteAcpAddForm input{min-width:0;height:34px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:inherit;padding:0 10px}.dshRemoteAcpAddForm button{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);padding:0 12px;cursor:pointer;font:inherit;font-size:12px}.dshRemoteAcpAddForm button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteAcpRemoveLink{grid-column:3;grid-row:1;color:var(--dsw-alias-label-secondary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpRemoveLink:hover{color:var(--dsw-alias-state-danger-primary)}",
3030
+ ".dshRemoteAcpCheckResult.isPassed,.dshRemoteAcpCheckResult.isFailed{color:var(--dsw-alias-label-secondary)}",
3031
+ ".dshRemoteAcpList>.dshRemoteAuthorizationSetting{grid-template-columns:minmax(0,1fr) 190px 40px 56px;column-gap:18px}.dshRemoteAcpCheckCell{grid-column:2;display:flex;align-items:center;gap:10px;min-width:0}.dshRemoteAcpCheckLink,.dshRemoteAcpRemoveLink{justify-self:start}.dshRemoteAcpCheckResult{position:static}",
3032
+ ".dshRemoteAcpCheckLink.isPassed{color:var(--dsw-alias-state-success-primary)}.dshRemoteAcpCheckLink.isFailed{color:var(--dsw-alias-state-danger-primary)}.dshRemoteAcpCheckLink.isChecking{color:var(--dsw-alias-label-secondary)}",
3033
+ ".dshRemoteCancelWorkspace{min-height:36px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:6px 0;cursor:pointer}.dshRemoteCancelWorkspace:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteCancelWorkspace:disabled{opacity:.5;cursor:default}",
3034
+ '.dshRemoteHostList{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2);max-height:296px;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}.dshRemoteHostList.isCollapsed{max-height:none;overflow-y:visible}.dshRemoteHostList>button{min-height:58px;flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:16px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:10px 4px;cursor:pointer}.dshRemoteHostList>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button:disabled{opacity:.5;cursor:default}.dshRemoteHostList>button[aria-current="true"]{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button>span{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostList>button strong{font-size:14px;font-weight:500}.dshRemoteHostList small{color:var(--dsw-alias-label-secondary);font-size:12px}',
3035
+ '.dshRemoteConnectedMenu{position:relative;flex:0 0 auto;margin-right:4px}.dshRemoteConnectedCount{appearance:none;display:inline-flex;align-items:center;justify-content:center;height:22px;border:0;border-radius:999px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);box-shadow:0 1px 2px rgba(0,0,0,.18),0 0 0 1px rgba(255,255,255,.04) inset;padding:0 10px;font:inherit;font-size:11px;font-weight:500;line-height:17px;white-space:nowrap;cursor:default}.dshRemoteConnectedCount.isOnline{color:var(--dsw-alias-state-success-primary)}.dshRemoteConnectedCount.isInteractive{cursor:pointer}.dshRemoteConnectedCount.isInteractive:hover{filter:brightness(1.08)}.dshRemoteConnectedCount:disabled{opacity:1;cursor:default}.dshRemoteConnectedCount:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteConnectedPanel{position:absolute;top:calc(100% + 8px);right:0;z-index:4;width:min(320px,calc(100vw - 48px));max-height:min(280px,40vh);overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2);box-shadow:0 10px 28px rgba(0,0,0,.28);padding:10px 12px}.dshRemoteConnectedPanelTitle{display:block;margin:0 0 6px;color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600}.dshRemoteClientList{display:flex;flex-direction:column}.dshRemoteClientRow{min-height:44px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteClientRow:last-child{border-bottom:0}.dshRemoteClientRow>span{min-width:0;display:flex;flex-direction:column;gap:2px}.dshRemoteClientRow strong{font-size:13px;font-weight:500}.dshRemoteClientRow small{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteClientOnline{display:inline-flex;align-items:center;gap:6px;color:var(--dsw-alias-state-success-primary)!important}.dshRemoteClientOnline::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}',
3036
+ ".dshRemoteConnectedCount{height:auto;border-radius:0;background:transparent;box-shadow:none;padding:0 4px;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 45%,transparent);text-underline-offset:3px}.dshRemoteConnectedCount.isInteractive:hover{filter:none;text-decoration-color:currentColor}.dshRemoteConnectedCount:focus-visible{outline-offset:3px;border-radius:3px}",
3037
+ '.dshRemoteProgress{display:flex;flex-direction:column;gap:8px;margin:12px 0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}.dshRemoteProgressHeader{display:flex;align-items:center;justify-content:space-between;gap:12px}.dshRemoteProgressHeader strong{font-size:13px;font-weight:600}.dshRemoteProgressHeader span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteProgressBar{height:6px;overflow:hidden;border-radius:999px;background:var(--dsw-alias-bg-layer-3)}.dshRemoteProgressBar>span{display:block;width:100%;height:100%;border-radius:inherit;background:var(--dsw-alias-brand-primary);transform-origin:left center;transition:transform .22s ease-out}[dir="rtl"] .dshRemoteProgressBar>span{transform-origin:right center}.dshRemoteProgress p{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45}.dshRemoteProgressRoute{font-weight:500}.dshRemoteProgressRoute .isActive{color:var(--dsw-alias-state-success-primary);font-weight:700}.dshRemoteProgressRouteArrow{color:var(--dsw-alias-label-tertiary)}@media(prefers-reduced-motion:reduce){.dshRemoteProgressBar>span{transition:none}}',
3038
+ '.dshRemoteBrowser{display:flex;flex-direction:column}.dshRemoteCrumbs{display:flex;align-items:center;gap:4px;overflow:auto;padding:2px 0 10px}.dshRemoteCrumbs>button{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 7px;border-radius:6px;cursor:pointer}.dshRemoteCrumbs>button:not(:last-child)::after{content:" /";color:var(--dsw-alias-label-tertiary)}.dshRemoteCrumbs>button:disabled{color:var(--dsw-alias-label-primary);font-weight:600}',
3039
+ ".dshRemoteWorkspaceLists{overflow:visible}",
3040
+ ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child,.dshRemoteDirectoryList>button>.dshRemoteWorkspaceIcon{grid-row:1/3}.dshRemoteWorkspaceIcon{box-sizing:border-box;width:22px;height:22px;align-self:center;object-fit:contain}.dshRemoteWorkspaceIcon.isGpt{border-radius:6px}.dshRemoteDirectoryList>button>span:not(:first-child),.dshRemoteDirectoryList>button>small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary)}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3041
+ ".dshRemoteAddWorkspace{box-sizing:border-box;width:40px;height:40px;display:inline-grid;place-items:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;cursor:pointer}.dshRemoteAddWorkspace:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteAddWorkspace:disabled{opacity:.5;cursor:default}.dshRemoteAddWorkspaceIcon{width:20px;height:20px}.dshRemoteCodexWorkspaceGroup{margin-top:16px}.dshRemoteWorkspaceSourceHeading{min-height:44px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 4px 7px}.dshRemoteWorkspaceSourceText{min-width:0;display:flex;flex-direction:column;gap:2px}.dshRemoteWorkspaceSourceText>strong{font-size:13px}.dshRemoteWorkspaceSourceText>small{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteCodexWorkspaceList{min-height:0}.dshRemoteDirectoryList>.dshRemoteWorkspaceMore,.dshRemoteCodexWorkspaceGroup>.dshRemoteWorkspaceMore{box-sizing:border-box;width:100%;min-height:48px;display:flex;align-items:center;justify-content:center;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);padding:8px 4px;text-align:center;font-size:16px;cursor:pointer}.dshRemoteWorkspaceMore>span{display:block;line-height:1;transform:translateY(-2px)}.dshRemoteWorkspaceMore:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:transparent}.dshRemoteWorkspaceMore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteWorkspaceMore:disabled{opacity:.5;cursor:default}",
3042
+ ".dshRemotePreviewAction,.dshRemotePreviewForm{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.dshRemotePreviewForm input{width:90px;color:inherit;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);padding:6px}.dshRemotePreviewForm [role=alert]{max-width:360px;white-space:normal}.dshRemoteDevelopmentSettings{width:100%;margin:16px 0}.dshRemoteDevelopmentSettings .dshRemotePathField{display:flex;flex-direction:column;gap:6px;margin:8px 0}.dshRemoteDevelopmentSettings .dshRemotePathField>label{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteDevelopmentSettings .dshRemotePortsRow{display:flex;gap:8px;align-items:stretch;width:100%}.dshRemoteDevelopmentSettings .dshRemotePortsRow>input{box-sizing:border-box;width:100%;flex:1;min-width:0;height:34px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}.dshRemoteDevelopmentSettings button{min-height:34px;color:inherit;background:var(--dsw-alias-bg-layer-1);border:.5px solid var(--dsw-alias-border-l2);border-radius:8px;padding:5px 14px;white-space:nowrap;font-size:13px;line-height:1.5}.dshRemoteAcpAddForm>label{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteAcpAddForm>label>input{box-sizing:border-box;width:100%;height:34px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);padding:0 12px;font:inherit;font-size:13px;line-height:1.5}",
3043
+ ".dshRemoteFolderBrowser{margin-top:14px}.dshRemoteFolderBrowser>p,.dshRemoteFolderList>p{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}.dshRemoteFolderList{max-height:260px;overflow:auto;border-block:1px solid var(--dsw-alias-border-l2)}.dshRemoteFolderList>button{width:100%;min-height:42px;display:flex;align-items:center;gap:9px;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:7px 6px;text-align:left;cursor:pointer}.dshRemoteFolderList>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteFolderBrowser>small{display:block;margin-top:8px;color:var(--dsw-alias-state-warn-label)}",
3044
+ ".dshRemotePathField{display:flex;flex-direction:column;gap:6px;margin-top:20px}.dshRemotePathField>span{font-size:13px;font-weight:600}.dshRemotePathField>input{min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit}.dshRemotePathField>small{color:var(--dsw-alias-label-secondary)}",
3045
+ ".dshRemoteOpenBar{position:sticky;bottom:-96px;display:flex;align-items:center;justify-content:space-between;gap:20px;margin-top:20px;padding:14px 0;background:var(--dsw-alias-bg-layer-1);border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteOpenBar>div{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteOpenBar span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteOpenBar strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.dshRemoteOpenBar>button,.dshRemoteEnable>button{min-height:40px;flex:0 0 auto;border:0;border-radius:8px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);padding:8px 16px;cursor:pointer}.dshRemoteOpenBar>button:disabled,.dshRemoteEnable>button:disabled{opacity:.5;cursor:default}",
3046
+ ".dshRemoteEnable{box-sizing:border-box;width:min(440px,100%);max-width:100%;min-height:388px;margin:0 auto;display:flex;flex-direction:column;align-items:stretch;gap:10px}.dshRemoteEnable p{margin:0;color:var(--dsw-alias-label-secondary);line-height:1.5}",
3047
+ '.dshRemoteLoginTabs{width:min(440px,100%);display:flex;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteLoginTabs>button{position:relative;min-height:38px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:6px 14px;font:inherit;font-size:13px;cursor:pointer}.dshRemoteLoginTabs>button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.dshRemoteLoginTabs>button.isActive{color:var(--dsw-alias-label-primary);font-weight:600}.dshRemoteLoginTabs>button.isActive::after{content:"";position:absolute;right:12px;bottom:-1px;left:12px;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-brand-primary)}.dshRemoteLoginTabs>button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px;border-radius:6px}',
3048
+ ".dshRemoteClientLogin{width:min(440px,100%);display:flex;flex-direction:column;gap:8px}.dshRemoteClientLogin input{min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit}.dshRemoteClientLogin button{align-self:flex-start;min-height:40px;border:0;border-radius:8px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);padding:8px 16px;cursor:pointer}",
3049
+ ".dshRemoteQrLogin{width:min(440px,100%);display:flex;flex-direction:column;align-items:center;gap:8px;padding:6px 0 2px;text-align:center}.dshRemoteQrLogin img,.dshRemoteQrPlaceholder{box-sizing:border-box;width:200px;height:200px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:#fff;padding:8px}.dshRemoteQrOpen{display:flex;flex-direction:column;align-items:center;gap:5px;color:var(--dsw-alias-label-secondary);font-size:12px;text-decoration:none}.dshRemoteQrOpen:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteQrOpen:hover img{border-color:var(--dsw-alias-label-dimmed)}.dshRemoteQrOpen:focus-visible{border-radius:12px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.dshRemoteQrPlaceholder{display:flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-secondary)}.dshRemoteQrLogin>strong{font-size:14px}.dshRemoteQrLogin>p{max-width:48ch;margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.dshRemoteQrLogin>.dshRemoteServiceAddress{margin-top:2px;color:var(--dsw-alias-label-tertiary)}.dshRemoteServiceAddress>a{color:var(--dsw-alias-label-secondary);text-decoration:none}.dshRemoteServiceAddress>a:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteQrLogin>button,.dshRemoteClientLogin>.dshRemoteLoginSwitch{min-height:32px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:4px 8px;font:inherit;font-size:12px;cursor:pointer}.dshRemoteQrLogin>button:hover,.dshRemoteClientLogin>.dshRemoteLoginSwitch:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteClientLogin>.dshRemoteLoginSwitch{align-self:flex-start;background:transparent;color:var(--dsw-alias-label-secondary);padding-left:0}",
3050
+ ".dshRemoteLoginHeading{box-sizing:border-box;width:100%;display:flex;align-items:baseline;gap:10px;overflow:hidden;white-space:nowrap}.dshRemoteLoginTitle{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteLoginHeading>span{flex:0 0 auto;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:400}.dshRemoteLoginTabs{box-sizing:border-box;width:100%;flex-wrap:nowrap;overflow-x:auto}.dshRemoteLoginTabs>button{min-width:max-content;flex:1 0 auto;display:flex;align-items:center;justify-content:center;padding:6px 10px;white-space:nowrap;text-align:center}.dshRemoteLoginTabs>button.isActive::after{right:0;left:0;bottom:0;border-radius:0}.dshRemoteClientLogin,.dshRemoteQrLogin{box-sizing:border-box;width:100%;height:300px;min-height:300px}.dshRemoteClientLogin{align-items:stretch;padding-top:16px}.dshRemoteClientLogin>button{align-self:stretch;width:100%}.dshRemoteQrLogin{padding-top:12px}",
3051
+ '.dshRemoteHostControlToggle{display:flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;white-space:nowrap;cursor:default}.dshRemoteHostControlToggle>input{appearance:none;box-sizing:border-box;position:relative;width:32px;height:18px;flex:0 0 auto;margin:0;border:1px solid var(--dsw-alias-label-secondary);border-radius:999px;background:var(--dsw-alias-bg-layer-3);cursor:pointer;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2);transition:background .16s ease-out,border-color .16s ease-out,box-shadow .16s ease-out}.dshRemoteHostControlToggle>input::after{content:"";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-label-secondary);transition:transform .16s ease-out,background .16s ease-out}.dshRemoteHostControlToggle>input:checked{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-primary);box-shadow:none}.dshRemoteHostControlToggle>input:checked::after{transform:translateX(14px);background:var(--dsw-alias-bg-layer-1)}.dshRemoteHostControlToggle>input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteHostControlToggle>input:disabled{opacity:.5;cursor:default}@media(prefers-reduced-motion:reduce){.dshRemoteHostControlToggle>input,.dshRemoteHostControlToggle>input::after{transition:none}}',
3052
+ ".dshRemoteAccountFooter{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:14px;color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteAccountExit{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;padding:5px 0;font-size:12px;line-height:1.5;white-space:nowrap}.dshRemoteAccountExit:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteAccountExit:disabled{opacity:.5;cursor:default;text-decoration:none}",
3053
+ ".dshRemoteLocalLink{align-self:flex-start;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:4px 0;cursor:pointer}.dshRemoteLocalLink:hover{color:var(--dsw-alias-label-primary)}",
3054
+ "@keyframes dshRemotePageIn{from{opacity:0;transform:translateY(6px) scale(.99)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.dshRemotePage{animation:none}}@media(max-width:620px){.dshRemoteBackdrop{padding:12px}.dshRemotePage{max-height:calc(100vh - 24px)}.dshRemotePageHeader{gap:8px;padding:12px 16px}.dshRemotePage.hasSelectedHost .dshRemotePageBack{max-width:112px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteSectionHeading{align-items:flex-start;flex-direction:column;gap:8px}.dshRemoteWorkspaceHeading{align-items:center;flex-direction:row}.dshRemoteSectionActions{width:100%;justify-content:space-between}.dshRemotePageBody{padding:20px 16px}.dshRemoteOpenBar{align-items:flex-end}.dshRemoteOpenBar>button{min-height:48px}}",
3055
+ ".dshRemoteBackdrop{position:fixed;inset:0;z-index:1000;background:var(--dsw-alias-bg-mask-3);display:grid;place-items:center;padding:20px}",
3056
+ ".dshRemoteDialog{width:min(460px,100%);max-height:80vh;overflow:auto;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:18px;display:grid;gap:12px;box-shadow:var(--dsw-shadow-lv2)}",
3057
+ ".dshRemoteDialog button,.dshRemoteDialog input{font:inherit;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:9px 10px;background:transparent;color:inherit}",
3058
+ ".dshRemoteDialog button:not(:disabled){cursor:pointer}.dshRemoteDialog button:disabled{opacity:.5}",
3059
+ ".dshRemoteHeader{display:flex;align-items:center;justify-content:space-between}.dshRemoteHeader button{border:0;font-size:22px;padding:0 6px}",
3060
+ ".dshRemoteDevices{display:grid;gap:8px}.dshRemoteDevices p{margin:4px 0;color:var(--dsw-alias-label-secondary)}",
3061
+ ".dshRemoteError{margin:0;color:var(--dsw-alias-state-error-primary)}",
3062
+ ".dshRemoteHostAccount{display:grid;gap:8px;border-top:1px solid var(--dsw-alias-border-l3);padding-top:12px}.dshRemoteHostAccount p{margin:0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3063
+ ".dshRemoteLogin{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dshRemoteLogin button{grid-column:1/-1}",
3064
+ // The plugin manager already supplies DSH's detail page chrome and
3065
+ // spacing for `view: page`. Keep the legacy card only for older hosts;
3066
+ // current DSH must not get a second, old-style card inside that page.
3067
+ ".dshRemotePluginCard{list-style:none;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:var(--dsw-radius-xl,16px);transition:border-color .16s,background .16s}",
3068
+ ".dshRemotePluginModern{box-sizing:border-box;width:100%;max-width:none;box-shadow:none;border:0;background:transparent;border-radius:0}.dshRemotePluginModern>.dshRemotePluginCardHeader{display:none}.dshRemotePluginModern>.dshRemotePluginCardBody{border-top:0;margin:0;padding:0}",
3069
+ ".dshRemotePluginCard:hover{border-color:var(--dsw-alias-label-dimmed)}.dshRemotePluginCard.isOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}",
3070
+ ".dshRemotePluginCard.dshRemotePluginModern:hover,.dshRemotePluginCard.dshRemotePluginModern.isOpen{border-color:transparent;background:transparent}",
3071
+ ".dshRemotePluginCardHeader{display:flex;align-items:center}.dshRemotePluginCardToggle{appearance:none;width:100%;min-width:0;font:inherit;color:inherit;text-align:left;cursor:pointer;background:transparent;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 16px}.dshRemotePluginCardToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}",
3072
+ ".dshRemotePluginCardHeading{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}.dshRemotePluginCardHeading>strong{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.dshRemotePluginCardHeading>span{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.dshRemotePluginCardStatus{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.dshRemotePluginCardStatus.isOnline{color:var(--dsw-alias-state-success-primary)}.dshRemotePluginCardStatus.isReconnecting{color:var(--dsw-alias-state-warn-label)}.dshRemotePluginCardStatus.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemotePluginCardChevron{color:var(--dsw-alias-label-tertiary);font-size:18px;line-height:14px;transition:transform .16s}.dshRemotePluginCard.isOpen .dshRemotePluginCardChevron{transform:rotate(180deg)}",
3073
+ ".dshRemotePluginCardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.dshRemoteSettings{display:flex;flex-direction:column;max-width:none}.dshRemoteSettingsTop{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:0 0 12px}.dshRemoteSettingsState{margin:0;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}",
3074
+ ".dshRemotePluginModern .dshRemoteField input{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md,8px);height:40px}.dshRemotePluginModern .dshRemoteSettingsFooter button{border-radius:var(--dsw-radius-md,8px);min-height:32px}",
3075
+ ".dshRemoteHostIdentity{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:12px 0;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteHostIdentity>div{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostIdentity span{color:var(--dsw-alias-label-tertiary);font-size:12px}.dshRemoteHostIdentity strong,.dshRemoteHostIdentity code{min-width:0;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500}.dshRemoteHostIdentity code{font-family:var(--dsw-font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-weight:400}",
3076
+ ".dshRemoteField{display:flex;flex-direction:column;gap:6px;padding:12px 0}.dshRemoteField+.dshRemoteField{border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteField label{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteField input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.dshRemoteField input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.dshRemoteField input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.dshRemoteField p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}",
3077
+ '.dshRemoteAuthorizationSetting{border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;gap:20px;padding:12px 0}.dshRemoteAuthorizationSetting>div{min-width:0}.dshRemoteAuthorizationSetting strong{font-size:13px;font-weight:500}.dshRemoteAuthorizationSetting p{margin:3px 0 0;color:var(--dsw-alias-label-tertiary);font-size:12px}.dshRemoteAuthorizationSetting>input{appearance:none;position:relative;width:38px;height:22px;flex:0 0 auto;margin:0;border:1px solid var(--dsw-alias-label-secondary);border-radius:999px;background:var(--dsw-alias-bg-layer-3);cursor:pointer;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2);transition:background .16s ease-out,border-color .16s ease-out,box-shadow .16s ease-out}.dshRemoteAuthorizationSetting>input::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-secondary);transition:transform .16s ease-out,background .16s ease-out}.dshRemoteAuthorizationSetting>input:checked{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-primary);box-shadow:none}.dshRemoteAuthorizationSetting>input:checked::after{transform:translateX(16px);background:var(--dsw-alias-bg-layer-1)}.dshRemoteAuthorizationSetting>input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteAuthorizationSetting>input:disabled{opacity:.5;cursor:default}@media(prefers-reduced-motion:reduce){.dshRemoteAuthorizationSetting>input,.dshRemoteAuthorizationSetting>input::after{transition:none}}',
3078
+ ".dshRemoteAssociation{min-width:0;flex:1;display:flex;flex-direction:column;gap:4px}.dshRemoteAssociation>span{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.dshRemoteAssociation strong{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:1.5}.dshRemoteAssociation p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}",
3079
+ ".dshRemoteConnection{border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 0}.dshRemoteConnectionSummary{min-width:0;display:flex;flex-direction:column;gap:4px}.dshRemoteConnectionSummary>span{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.dshRemoteConnectionSummary strong{display:flex;align-items:center;gap:7px;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:1.5}.dshRemoteConnectionSummary p,.dshRemoteConnectionIssue{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.dshRemoteConnectionDot{width:8px;height:8px;flex:0 0 auto;border-radius:999px;background:var(--dsw-alias-label-tertiary)}.dshRemoteConnectionDot.isOnline{background:var(--dsw-alias-state-success-primary)}.dshRemoteConnectionDot.isReconnecting{background:var(--dsw-alias-state-warn-primary)}.dshRemoteConnectionDot.isOffline{background:var(--dsw-alias-state-error-primary)}.dshRemoteConnectionIssue{color:var(--dsw-alias-state-error-primary);padding:0 0 12px}.dshRemoteReconnect{appearance:none;flex:0 0 auto;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);min-height:34px;padding:5px 14px;font-size:13px;line-height:1.5}.dshRemoteReconnect:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteReconnect:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.dshRemoteReconnect:disabled{opacity:.4;cursor:default}",
3080
+ ".dshRemoteSettingsFooter{border-top:1px solid var(--dsw-alias-border-l2);display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px}.dshRemoteSettingsFooter .dshRemoteError,.dshRemoteNotice{min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.dshRemoteNotice{color:var(--dsw-alias-label-tertiary)}.dshRemoteDiscard,.dshRemoteSave{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.dshRemoteDiscard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteDiscard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.dshRemoteSave{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.dshRemoteDiscard:disabled,.dshRemoteSave:disabled{opacity:.4;cursor:default}.dshRemoteDiscard:focus-visible,.dshRemoteSave:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}",
3081
+ "@media(max-width:620px){.dshRemotePluginCardStatus{display:none}.dshRemoteSettingsTop{gap:10px}.dshRemoteConnection{align-items:flex-start}.dshRemoteReconnect{min-height:40px}.dshRemotePortsRow{flex-direction:column}.dshRemoteAcpAddForm{grid-template-columns:1fr}.dshRemoteAcpAddForm button{min-height:40px}}"
3082
+ ].join(""), document.head.append(style), () => style.remove();
3083
+ }
3084
+ function installTerminalAvailabilityNotice(feed, t) {
3085
+ let latest, notice, update = () => {
3086
+ let terminal = document.querySelector("[data-sidebar-terminal]"), unavailable = latest?.mode === "remote" && latest.remoteFeatures?.terminal !== !0;
3087
+ if (!terminal || !unavailable) {
3088
+ notice?.remove(), notice = void 0;
3089
+ return;
3075
3090
  }
3076
- function RemoteWorkspaceAction(props) {
3077
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [cursorWorkspaces, setCursorWorkspaces] = React.useState([]), [antigravityWorkspaces, setAntigravityWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [cursorWorkspaceId, setCursorWorkspaceId] = React.useState(void 0), [antigravityWorkspaceId, setAntigravityWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), [showAllCursorWorkspaces, setShowAllCursorWorkspaces] = React.useState(!1), [showAllAntigravityWorkspaces, setShowAllAntigravityWorkspaces] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", cursorWorkspaceHeadingId = "dsh-remote-cursor-workspace-heading", cursorWorkspaceListId = "dsh-remote-cursor-workspace-list", antigravityWorkspaceHeadingId = "dsh-remote-antigravity-workspace-heading", antigravityWorkspaceListId = "dsh-remote-antigravity-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginServerUrl, setLoginServerUrl] = React.useState("https://dsh.r2049.cn"), [loginMethod, setLoginMethod] = React.useState("password"), loginMethodManuallySelected = React.useRef(!1), [oauthProviders, setOAuthProviders] = React.useState([]), [providersLoading, setProvidersLoading] = React.useState(!1), [providersFailed, setProvidersFailed] = React.useState(!1), [providerReload, setProviderReload] = React.useState(0), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), qrFlowRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
3078
- React.useEffect(() => {
3079
- open || (setDevicesOpen(!1), qrFlowRun.current += 1, setBusy(!1));
3080
- }, [open]), React.useEffect(() => {
3081
- if (!open) return;
3082
- let closeOnEscape = (event) => {
3083
- if (event.key === "Escape") {
3084
- if (devicesOpen) {
3085
- event.stopPropagation(), setDevicesOpen(!1);
3086
- return;
3087
- }
3088
- setOpen(!1);
3089
- }
3090
- };
3091
- return window.addEventListener("keydown", closeOnEscape), () => window.removeEventListener("keydown", closeOnEscape);
3092
- }, [open, devicesOpen]), React.useEffect(() => {
3093
- if (!devicesOpen) return;
3094
- let closeOnPointer = (event) => {
3095
- let target = event.target;
3096
- target instanceof Element && target.closest(".dshRemoteConnectedMenu") === null && setDevicesOpen(!1);
3097
- };
3098
- return window.addEventListener("mousedown", closeOnPointer), () => window.removeEventListener("mousedown", closeOnPointer);
3099
- }, [devicesOpen]), React.useEffect(() => {
3100
- (status?.host?.connectedClients?.length ?? 0) === 0 && setDevicesOpen(!1);
3101
- }, [status?.host?.connectedClients?.length]), React.useEffect(() => {
3102
- props.control("status").then(setStatus).catch(() => {
3103
- });
3104
- }, []), React.useEffect(() => {
3105
- status?.serverUrl !== void 0 && loginServerUrl === "https://dsh.r2049.cn" && setLoginServerUrl(status.serverUrl);
3106
- }, [status?.serverUrl]), React.useEffect(() => {
3107
- let remoteActive = status?.mode === "remote";
3108
- return document.documentElement.classList.toggle("dshRemoteTargetActive", remoteActive), () => {
3109
- remoteActive && document.documentElement.classList.remove("dshRemoteTargetActive");
3110
- };
3111
- }, [status?.mode]);
3112
- let startQrLogin = async (provider) => {
3113
- let run = ++qrFlowRun.current;
3114
- setBusy(!0), setError(void 0), setQrExpired(!1);
3115
- try {
3116
- let session = await props.control("client.account.qr.start", { provider }), image = await import_qrcode.default.toDataURL(session.scanUrl, {
3117
- width: 184,
3118
- margin: 1,
3119
- errorCorrectionLevel: "L"
3120
- });
3121
- if (run !== qrFlowRun.current) return;
3122
- setQrSession(session), setQrImage(image);
3123
- } catch (reason) {
3124
- run === qrFlowRun.current && setError(messageOf(reason));
3125
- } finally {
3126
- run === qrFlowRun.current && setBusy(!1);
3091
+ notice !== void 0 && notice.isConnected || (notice = document.createElement("div"), notice.className = "dshRemoteTerminalUnavailable", notice.setAttribute("role", "alert"), notice.textContent = t("terminalRemoteUnavailable"), terminal.prepend(notice));
3092
+ }, unsubscribe = feed.subscribe((status) => {
3093
+ latest = status, update();
3094
+ }), observer = new MutationObserver(update);
3095
+ return observer.observe(document.body, { childList: !0, subtree: !0 }), update(), () => {
3096
+ unsubscribe(), observer.disconnect(), notice?.remove();
3097
+ };
3098
+ }
3099
+
3100
+ // src/client/workspaces.ts
3101
+ var import_qrcode = __toESM(require_browser(), 1);
3102
+
3103
+ // src/client/icons.ts
3104
+ var deepSeekWorkspaceIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAACVBMVEUAAADy8vXx8fUsA3vyAAAAAXRSTlMAQObYZgAAAOxJREFUWMPtlsEOwyAMQxP+/6OnTZMGxHGcot3wDYgfhkJbs6urprzveGtu9d1NgEdto8w93GuA7zPS2RFg7ynsCOAokbtAmLr2YaeKgJ6fxpT8jCAC0qSqPyNoO5DXdvyouj4ClFAdYaDxK09uiBDCIYBf6CxLesnR0uF2pG+JmhCqrUb0AOvjjoQaYDTCEAAgMg5grhAeAQIB+/M15IcKlnUIp4CkTCd0AKb4zVsRSJVGYEVzT0agK107IMGMEurvromEpaX4wzk/IKw378kq4LafED6Oowxfk7AP2q8W16EdM3p29Eyvrv6vF0WIBfBziKyCAAAAAElFTkSuQmCC", gptWorkspaceIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAclBMVEX////v7+++wMf////s7O3k5OTExcrX2Ny6vMTv8PPW19yXmqRqboJmaHd3eoaqrLPs7fGMjpfb3eKlpq1eYXOxs7pWWWd+gY5HSVdRVGVub3k+QU74+Pg4OkcvMT1ISlUoKjUiIy4fICueoKkaGyUSFB21Bp+qAAAAAXRSTlMAQObYZgAABChJREFUWMPtl916qjoQhlsdEwIECEgMYCBxx/u/xT1DrFUL1LO1DtY8LSLJvPnmB4gfH//sr7TPDfvdebf/xXZbkE/4zZ0MVhGHd9zJDsv+7F3//Z69tT5wljAu3tXw+TIlzXKJlhflYmJ+5uF5WpWhb54X+C/zZCmT2wJA4dJZwus0UYjIGqWyMhVbEp4yKNRRqlv0opW5PJLJ4rFJXvP4JKDRMqturBZjkMVJFYjR6iHQDQDI4+k2k51wZbWrqwp4mR/1CVYATyko9TFGxBUqL5IvMbXSWt0T8bkGgFLqgqZBI/Uxbx5UAxLaNcCNLBpttM7wbCc1pmJOpWAsDtey68UaQMyrFgb9uxLPjqg3+nGluyKN0XUdWw0BJ0NvTFFqgzpr9J+Dh4w0Ga1qkqBNswagxdRgFPAbgHRQG5jumGWyMxrTIaRRa4AzFs0YrNMXgI4MJWnsKYFhGNMnIh/mBOPsV8CZBFjN9w8ArowxnZzDr5IcvxTaKpxJCVsoI3SWysz1UM4AqQdzlCgho1IKrK+x1mKFzisANtgEU8E7GwHDgOqxe4w9tnM166wbaA2xBMBLrTWcAGYGdCiYVUJUrMCF+7l6gklrW1RwPi8ByjuActANqhKzVWoYrFGcCFzbDgNaBrTWpncFQMcI2DfWoAiDqRCiHcYM/ZdCEKkZqfR8spj4F0CiJjv2gHL6URNoCQDaYacL6O1oFDO2eQDUFP7AKdCRdC4CRDZaNifbjA41l/uYb/SZMAFNTBGzY7sG4J2jTsJgToOzIzXF3HZqBpSOAGduXbkGEKV1OqVGqRJpRxtvwbSw5IqAiUJItwBCOT9R32FCGo3nCkAN3t0UTBRC6zDONcBeOee9pr4T+ASbnDOdc5OmtREwEEB5w8Wqgt4bOV5c7Lt9iiK8zdP/IsBbutUGX4gNwEVCqd3FUt/xYnRWt7BvPBYQjwjAGXa3ASguHVAZ/WXKlA3eZDX1wRegFsr7E2wAlB9xFbx/7MV70kFT8aqNgLL3F8nFBmA3hrn/IJHjKJOK2oj1WI4Z4FzwN/81AOhgYD6v2xbIvaZIurLC9AfvB1WLTYAoXejF1xeBL5cpBIyEbmxkZymIXwDQh1BAfOrhI1lfwtgz8tozF5T4ttf3+32AyxC6klwAgw/YVTHpoK82xYt3wLP/Bw4AAI4D7/01TLKXBj9NEz2wEuGiKpoy68S/FwCLMQAZ3gXhihaCa25vQo6RyToOz9PE6wYjJgGi1YnqZX8qMIK+TDlnargGzSv4NvFjlwXf/nfLLMrAB4O/Xl3BH0d+RIASFgDA8IYMIXgr2+cBsbDdPSwAAHjSZFmb3txETCKIxc0uWwI8rxsLJcTiVndNwyMgKljbbNN2/zcEAja2+4RgIDYN2Bu/WtAOaEodnu2dnzz/7I/Y/w/LaEcX/MdfAAAAAElFTkSuQmCC";
3105
+
3106
+ // src/client/workspaces.ts
3107
+ function createRemoteWorkspaceAction(React) {
3108
+ let RemoteProgressView = createRemoteProgressView(React);
3109
+ function RemoteWorkspaceAction(props) {
3110
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [cursorWorkspaces, setCursorWorkspaces] = React.useState([]), [antigravityWorkspaces, setAntigravityWorkspaces] = React.useState([]), [piWorkspaces, setPiWorkspaces] = React.useState([]), [opencodeWorkspaces, setOpencodeWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [cursorWorkspaceId, setCursorWorkspaceId] = React.useState(void 0), [antigravityWorkspaceId, setAntigravityWorkspaceId] = React.useState(void 0), [piWorkspaceId, setPiWorkspaceId] = React.useState(void 0), [opencodeWorkspaceId, setOpencodeWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), [showAllCursorWorkspaces, setShowAllCursorWorkspaces] = React.useState(!1), [showAllAntigravityWorkspaces, setShowAllAntigravityWorkspaces] = React.useState(!1), [showAllPiWorkspaces, setShowAllPiWorkspaces] = React.useState(!1), [showAllOpencodeWorkspaces, setShowAllOpencodeWorkspaces] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", cursorWorkspaceHeadingId = "dsh-remote-cursor-workspace-heading", cursorWorkspaceListId = "dsh-remote-cursor-workspace-list", antigravityWorkspaceHeadingId = "dsh-remote-antigravity-workspace-heading", piWorkspaceHeadingId = "dsh-remote-pi-workspace-heading", opencodeWorkspaceHeadingId = "dsh-remote-opencode-workspace-heading", antigravityWorkspaceListId = "dsh-remote-antigravity-workspace-list", piWorkspaceListId = "dsh-remote-pi-workspace-list", opencodeWorkspaceListId = "dsh-remote-opencode-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginServerUrl, setLoginServerUrl] = React.useState("https://dsh.r2049.cn"), [loginMethod, setLoginMethod] = React.useState("password"), loginMethodManuallySelected = React.useRef(!1), [oauthProviders, setOAuthProviders] = React.useState([]), [providersLoading, setProvidersLoading] = React.useState(!1), [providersFailed, setProvidersFailed] = React.useState(!1), [providerReload, setProviderReload] = React.useState(0), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), qrFlowRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
3111
+ React.useEffect(() => {
3112
+ open || (setDevicesOpen(!1), qrFlowRun.current += 1, setBusy(!1));
3113
+ }, [open]), React.useEffect(() => {
3114
+ if (!open) return;
3115
+ let closeOnEscape = (event) => {
3116
+ if (event.key === "Escape") {
3117
+ if (devicesOpen) {
3118
+ event.stopPropagation(), setDevicesOpen(!1);
3119
+ return;
3120
+ }
3121
+ setOpen(!1);
3127
3122
  }
3128
3123
  };
3129
- React.useEffect(() => {
3130
- if (!open || !needsAuthorization) return;
3131
- let active = !0;
3132
- return qrFlowRun.current += 1, setBusy(!1), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setOAuthProviders([]), setProvidersLoading(!0), setProvidersFailed(!1), props.control("client.account.providers").then((items) => {
3133
- if (!active) return;
3134
- let available = items.filter((item) => item.qrStartUrl != null);
3135
- setOAuthProviders(available), setLoginMethod((current) => {
3136
- if (loginMethodManuallySelected.current && (current === "password" || available.some((item) => `oauth:${item.id}` === current))) return current;
3137
- let preferred = available.find((item) => item.id === props.preferredQrProvider) ?? available[0];
3138
- return preferred === void 0 ? "password" : `oauth:${preferred.id}`;
3139
- });
3124
+ return window.addEventListener("keydown", closeOnEscape), () => window.removeEventListener("keydown", closeOnEscape);
3125
+ }, [open, devicesOpen]), React.useEffect(() => {
3126
+ if (!devicesOpen) return;
3127
+ let closeOnPointer = (event) => {
3128
+ let target = event.target;
3129
+ target instanceof Element && target.closest(".dshRemoteConnectedMenu") === null && setDevicesOpen(!1);
3130
+ };
3131
+ return window.addEventListener("mousedown", closeOnPointer), () => window.removeEventListener("mousedown", closeOnPointer);
3132
+ }, [devicesOpen]), React.useEffect(() => {
3133
+ (status?.host?.connectedClients?.length ?? 0) === 0 && setDevicesOpen(!1);
3134
+ }, [status?.host?.connectedClients?.length]), React.useEffect(() => {
3135
+ props.control("status").then(setStatus).catch(() => {
3136
+ });
3137
+ }, []), React.useEffect(() => {
3138
+ status?.serverUrl !== void 0 && loginServerUrl === "https://dsh.r2049.cn" && setLoginServerUrl(status.serverUrl);
3139
+ }, [status?.serverUrl]), React.useEffect(() => {
3140
+ let remoteActive = status?.mode === "remote";
3141
+ return document.documentElement.classList.toggle("dshRemoteTargetActive", remoteActive), () => {
3142
+ remoteActive && document.documentElement.classList.remove("dshRemoteTargetActive");
3143
+ };
3144
+ }, [status?.mode]);
3145
+ let startQrLogin = async (provider) => {
3146
+ let run = ++qrFlowRun.current;
3147
+ setBusy(!0), setError(void 0), setQrExpired(!1);
3148
+ try {
3149
+ let session = await props.control("client.account.qr.start", { provider }), image = await import_qrcode.default.toDataURL(session.scanUrl, {
3150
+ width: 184,
3151
+ margin: 1,
3152
+ errorCorrectionLevel: "L"
3153
+ });
3154
+ if (run !== qrFlowRun.current) return;
3155
+ setQrSession(session), setQrImage(image);
3156
+ } catch (reason) {
3157
+ run === qrFlowRun.current && setError(messageOf(reason));
3158
+ } finally {
3159
+ run === qrFlowRun.current && setBusy(!1);
3160
+ }
3161
+ };
3162
+ React.useEffect(() => {
3163
+ if (!open || !needsAuthorization) return;
3164
+ let active = !0;
3165
+ return qrFlowRun.current += 1, setBusy(!1), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setOAuthProviders([]), setProvidersLoading(!0), setProvidersFailed(!1), props.control("client.account.providers").then((items) => {
3166
+ if (!active) return;
3167
+ let available = items.filter((item) => item.qrStartUrl != null);
3168
+ setOAuthProviders(available), setLoginMethod((current) => {
3169
+ if (loginMethodManuallySelected.current && (current === "password" || available.some((item) => `oauth:${item.id}` === current))) return current;
3170
+ let preferred = available.find((item) => item.id === props.preferredQrProvider) ?? available[0];
3171
+ return preferred === void 0 ? "password" : `oauth:${preferred.id}`;
3172
+ });
3173
+ }).catch((reason) => {
3174
+ active && (setProvidersFailed(!0), setLoginMethod("password"), setError(messageOf(reason)));
3175
+ }).finally(() => {
3176
+ active && setProvidersLoading(!1);
3177
+ }), () => {
3178
+ active = !1;
3179
+ };
3180
+ }, [open, needsAuthorization, status?.serverUrl, props.preferredQrProvider, providerReload]), React.useEffect(() => {
3181
+ !open || !needsAuthorization || providersLoading || loginMethod === "password" || !oauthProviders.some((item) => `oauth:${item.id}` === loginMethod) || qrSession !== void 0 || qrExpired || startQrLogin(loginMethod.slice(6));
3182
+ }, [open, needsAuthorization, providersLoading, oauthProviders, loginMethod, qrSession, qrExpired]), React.useEffect(() => {
3183
+ if (!open || loginMethod === "password" || qrSession === void 0) return;
3184
+ let active = !0, polling = !1, settled = !1, run = qrFlowRun.current, timer, poll = () => {
3185
+ polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
3186
+ if (!(!active || settled || run !== qrFlowRun.current))
3187
+ if (result.status === "complete") {
3188
+ settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
3189
+ try {
3190
+ let [nextDevices, nextStatus] = await Promise.all([
3191
+ props.control("devices"),
3192
+ props.control("status")
3193
+ ]);
3194
+ active && run === qrFlowRun.current && (setDevices(nextDevices), setStatus(nextStatus));
3195
+ } catch (reason) {
3196
+ active && run === qrFlowRun.current && setError(messageOf(reason));
3197
+ } finally {
3198
+ run === qrFlowRun.current && (setQrSession(void 0), setQrImage(void 0), setBusy(!1));
3199
+ }
3200
+ } else result.status === "expired" && (settled = !0, timer !== void 0 && window.clearInterval(timer), setQrExpired(!0), setQrSession(void 0), setQrImage(void 0));
3140
3201
  }).catch((reason) => {
3141
- active && (setProvidersFailed(!0), setLoginMethod("password"), setError(messageOf(reason)));
3202
+ active && !settled && run === qrFlowRun.current && setError(messageOf(reason));
3142
3203
  }).finally(() => {
3143
- active && setProvidersLoading(!1);
3144
- }), () => {
3145
- active = !1;
3146
- };
3147
- }, [open, needsAuthorization, status?.serverUrl, props.preferredQrProvider, providerReload]), React.useEffect(() => {
3148
- !open || !needsAuthorization || providersLoading || loginMethod === "password" || !oauthProviders.some((item) => `oauth:${item.id}` === loginMethod) || qrSession !== void 0 || qrExpired || startQrLogin(loginMethod.slice(6));
3149
- }, [open, needsAuthorization, providersLoading, oauthProviders, loginMethod, qrSession, qrExpired]), React.useEffect(() => {
3150
- if (!open || loginMethod === "password" || qrSession === void 0) return;
3151
- let active = !0, polling = !1, settled = !1, run = qrFlowRun.current, timer, poll = () => {
3152
- polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
3153
- if (!(!active || settled || run !== qrFlowRun.current))
3154
- if (result.status === "complete") {
3155
- settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
3156
- try {
3157
- let [nextDevices, nextStatus] = await Promise.all([
3158
- props.control("devices"),
3159
- props.control("status")
3160
- ]);
3161
- active && run === qrFlowRun.current && (setDevices(nextDevices), setStatus(nextStatus));
3162
- } catch (reason) {
3163
- active && run === qrFlowRun.current && setError(messageOf(reason));
3164
- } finally {
3165
- run === qrFlowRun.current && (setQrSession(void 0), setQrImage(void 0), setBusy(!1));
3166
- }
3167
- } else result.status === "expired" && (settled = !0, timer !== void 0 && window.clearInterval(timer), setQrExpired(!0), setQrSession(void 0), setQrImage(void 0));
3168
- }).catch((reason) => {
3169
- active && !settled && run === qrFlowRun.current && setError(messageOf(reason));
3170
- }).finally(() => {
3171
- polling = !1;
3172
- }));
3173
- };
3174
- return poll(), timer = window.setInterval(poll, 1500), () => {
3175
- active = !1, timer !== void 0 && window.clearInterval(timer);
3176
- };
3177
- }, [open, loginMethod, qrSession]);
3178
- let selectLoginMethod = (method) => {
3179
- loginMethodManuallySelected.current = !0, method !== loginMethod && (qrFlowRun.current += 1, setLoginMethod(method), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setError(void 0));
3180
- }, orderedQrProviders = [...oauthProviders].sort((a, b) => +(b.id === props.preferredQrProvider) - +(a.id === props.preferredQrProvider)), selectedProvider = oauthProviders.find((item) => `oauth:${item.id}` === loginMethod), scanLabel = t("scanWithProvider", { provider: selectedProvider?.displayName ?? "" }), qrLoginTab = (provider) => React.createElement("button", {
3181
- key: provider.id,
3182
- type: "button",
3183
- role: "tab",
3184
- id: `dsh-remote-oauth:${provider.id}-tab`,
3185
- "aria-selected": loginMethod === `oauth:${provider.id}`,
3186
- "aria-controls": `dsh-remote-oauth:${provider.id}-panel`,
3187
- className: loginMethod === `oauth:${provider.id}` ? "isActive" : "",
3188
- disabled: busy,
3189
- onClick: () => selectLoginMethod(`oauth:${provider.id}`)
3190
- }, t("providerLogin", { provider: provider.displayName })), selectHost = async (host) => {
3191
- setBusy(!0), setError(void 0), setConnectingHost(host), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1);
3192
- try {
3193
- let result = await runConnectHostProgress(
3194
- status?.preferredTransports,
3195
- host.deviceId,
3196
- props.control,
3197
- { label: "remoteProgressLoadingWorkspaces", detail: "remoteProgressLoadingWorkspacesDetail" },
3198
- setProgress,
3199
- progressRun,
3200
- async () => {
3201
- let nextWorkspaces = await props.control("workspaces.list", {
3202
- targetDeviceId: host.deviceId
3203
- }), nextCodexWorkspaces = await props.control("codex.workspaces.list", {
3204
- targetDeviceId: host.deviceId
3205
- }).catch(() => []), nextCursorWorkspaces = await props.control("cursor.workspaces.list", {
3206
- targetDeviceId: host.deviceId
3207
- }).catch(() => []), nextAntigravityWorkspaces = await props.control("antigravity.workspaces.list", {
3208
- targetDeviceId: host.deviceId
3209
- }).catch(() => []), nextStatus = await props.control("status").catch(() => {
3210
- });
3211
- return nextStatus !== void 0 && setStatus(nextStatus), {
3212
- workspaces: nextWorkspaces,
3213
- codexWorkspaces: nextCodexWorkspaces,
3214
- cursorWorkspaces: nextCursorWorkspaces,
3215
- antigravityWorkspaces: nextAntigravityWorkspaces,
3216
- status: nextStatus
3217
- };
3218
- },
3219
- (result2) => connectedProgress(result2.status)
3220
- );
3221
- setWorkspaces(result.workspaces), setCodexWorkspaces(result.codexWorkspaces), setCursorWorkspaces(result.cursorWorkspaces), setAntigravityWorkspaces(result.antigravityWorkspaces), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3222
- } catch (reason) {
3223
- setError(messageOf(reason));
3224
- } finally {
3225
- setConnectingHost(void 0), setBusy(!1);
3226
- }
3227
- }, browseDirectory = async (nextPath) => {
3228
- if (selectedHost !== void 0) {
3229
- setBusy(!0), setError(void 0);
3230
- try {
3231
- let listing = await props.control("directory.list", {
3232
- targetDeviceId: selectedHost.deviceId,
3233
- ...nextPath === void 0 ? {} : { path: nextPath }
3204
+ polling = !1;
3205
+ }));
3206
+ };
3207
+ return poll(), timer = window.setInterval(poll, 1500), () => {
3208
+ active = !1, timer !== void 0 && window.clearInterval(timer);
3209
+ };
3210
+ }, [open, loginMethod, qrSession]);
3211
+ let selectLoginMethod = (method) => {
3212
+ loginMethodManuallySelected.current = !0, method !== loginMethod && (qrFlowRun.current += 1, setLoginMethod(method), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setError(void 0));
3213
+ }, orderedQrProviders = [...oauthProviders].sort((a, b) => +(b.id === props.preferredQrProvider) - +(a.id === props.preferredQrProvider)), selectedProvider = oauthProviders.find((item) => `oauth:${item.id}` === loginMethod), scanLabel = t("scanWithProvider", { provider: selectedProvider?.displayName ?? "" }), qrLoginTab = (provider) => React.createElement("button", {
3214
+ key: provider.id,
3215
+ type: "button",
3216
+ role: "tab",
3217
+ id: `dsh-remote-oauth:${provider.id}-tab`,
3218
+ "aria-selected": loginMethod === `oauth:${provider.id}`,
3219
+ "aria-controls": `dsh-remote-oauth:${provider.id}-panel`,
3220
+ className: loginMethod === `oauth:${provider.id}` ? "isActive" : "",
3221
+ disabled: busy,
3222
+ onClick: () => selectLoginMethod(`oauth:${provider.id}`)
3223
+ }, t("providerLogin", { provider: provider.displayName })), selectHost = async (host) => {
3224
+ setBusy(!0), setError(void 0), setConnectingHost(host), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1);
3225
+ try {
3226
+ let result = await runConnectHostProgress(
3227
+ status?.preferredTransports,
3228
+ host.deviceId,
3229
+ props.control,
3230
+ { label: "remoteProgressLoadingWorkspaces", detail: "remoteProgressLoadingWorkspacesDetail" },
3231
+ setProgress,
3232
+ progressRun,
3233
+ async () => {
3234
+ let nextWorkspaces = await props.control("workspaces.list", {
3235
+ targetDeviceId: host.deviceId
3236
+ }), nextCodexWorkspaces = await props.control("codex.workspaces.list", {
3237
+ targetDeviceId: host.deviceId
3238
+ }).catch(() => []), nextCursorWorkspaces = await props.control("cursor.workspaces.list", {
3239
+ targetDeviceId: host.deviceId
3240
+ }).catch(() => []), nextAntigravityWorkspaces = await props.control("antigravity.workspaces.list", {
3241
+ targetDeviceId: host.deviceId
3242
+ }).catch(() => []), nextPiWorkspaces = await props.control("pi.workspaces.list", {
3243
+ targetDeviceId: host.deviceId
3244
+ }).catch(() => []), nextOpencodeWorkspaces = await props.control("opencode.workspaces.list", {
3245
+ targetDeviceId: host.deviceId
3246
+ }).catch(() => []), nextStatus = await props.control("status").catch(() => {
3234
3247
  });
3235
- setDirectory(listing), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPath(listing.path);
3236
- } catch (reason) {
3237
- setError(messageOf(reason));
3238
- } finally {
3239
- setBusy(!1);
3240
- }
3241
- }
3242
- }, startAddingWorkspace = (backend) => {
3243
- setAddingWorkspace(!0), setWorkspaceBackend(backend), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setDirectory(void 0), setPath(""), browseDirectory();
3244
- }, cancelAddingWorkspace = () => {
3245
- setAddingWorkspace(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setDirectory(void 0), setPath("");
3246
- }, refreshRemote = async () => {
3247
- setBusy(!0), setNotice(void 0), setError(void 0);
3248
+ return nextStatus !== void 0 && setStatus(nextStatus), {
3249
+ workspaces: nextWorkspaces,
3250
+ codexWorkspaces: nextCodexWorkspaces,
3251
+ cursorWorkspaces: nextCursorWorkspaces,
3252
+ antigravityWorkspaces: nextAntigravityWorkspaces,
3253
+ piWorkspaces: nextPiWorkspaces,
3254
+ status: nextStatus
3255
+ };
3256
+ },
3257
+ (result2) => connectedProgress(result2.status)
3258
+ );
3259
+ setWorkspaces(result.workspaces), setCodexWorkspaces(result.codexWorkspaces), setCursorWorkspaces(result.cursorWorkspaces), setAntigravityWorkspaces(result.antigravityWorkspaces), setPiWorkspaces(result.piWorkspaces), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3260
+ } catch (reason) {
3261
+ setError(messageOf(reason));
3262
+ } finally {
3263
+ setConnectingHost(void 0), setBusy(!1);
3264
+ }
3265
+ }, browseDirectory = async (nextPath) => {
3266
+ if (selectedHost !== void 0) {
3267
+ setBusy(!0), setError(void 0);
3248
3268
  try {
3249
- let nextStatus = await props.control("status");
3250
- if (setStatus(nextStatus), !nextStatus.available) {
3251
- setDevices([]), setNeedsAuthorization(!1), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3252
- return;
3253
- }
3254
- try {
3255
- let nextDevices = await props.control("devices");
3256
- if (setDevices(nextDevices), setNeedsAuthorization(!1), selectedHost !== void 0) {
3257
- let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
3258
- nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : (setSelectedHost(nextSelectedHost), props.control("workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setWorkspaces(w)).catch(() => {
3259
- }), props.control("codex.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setCodexWorkspaces(w)).catch(() => {
3260
- }), props.control("cursor.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setCursorWorkspaces(w)).catch(() => {
3261
- }), props.control("antigravity.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setAntigravityWorkspaces(w)).catch(() => {
3262
- }));
3263
- }
3264
- } catch {
3265
- setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3266
- }
3269
+ let listing = await props.control("directory.list", {
3270
+ targetDeviceId: selectedHost.deviceId,
3271
+ ...nextPath === void 0 ? {} : { path: nextPath }
3272
+ });
3273
+ setDirectory(listing), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setPath(listing.path);
3267
3274
  } catch (reason) {
3268
3275
  setError(messageOf(reason));
3269
3276
  } finally {
3270
3277
  setBusy(!1);
3271
3278
  }
3272
- }, show = async () => {
3273
- setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setOpen(!0), await refreshRemote();
3274
- };
3275
- React.useEffect(() => {
3276
- if (!(!open || selectedHost !== void 0))
3277
- return props.statusFeed.subscribe(setStatus);
3278
- }, [open, selectedHost]);
3279
- let chooseAnotherHost = () => {
3280
- setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
3281
- }, signInClient = async () => {
3282
- if (!(email.trim() === "" || password === "" || loginServerUrl.trim() === "")) {
3283
- setBusy(!0), setError(void 0);
3284
- try {
3285
- await props.control("settings.configure", {
3286
- role: "client",
3287
- serverUrl: loginServerUrl.trim(),
3288
- email: email.trim(),
3289
- password
3290
- }), setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setPassword("");
3291
- } catch (reason) {
3292
- setError(messageOf(reason));
3293
- } finally {
3294
- setBusy(!1);
3295
- }
3279
+ }
3280
+ }, startAddingWorkspace = (backend) => {
3281
+ setAddingWorkspace(!0), setWorkspaceBackend(backend), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setDirectory(void 0), setPath(""), browseDirectory();
3282
+ }, cancelAddingWorkspace = () => {
3283
+ setAddingWorkspace(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setDirectory(void 0), setPath("");
3284
+ }, refreshRemote = async () => {
3285
+ setBusy(!0), setNotice(void 0), setError(void 0);
3286
+ try {
3287
+ let nextStatus = await props.control("status");
3288
+ if (setStatus(nextStatus), !nextStatus.available) {
3289
+ setDevices([]), setNeedsAuthorization(!1), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3290
+ return;
3296
3291
  }
3297
- }, openLocalWorkspaces = async () => {
3298
- setBusy(!0), setError(void 0);
3299
3292
  try {
3300
- await props.control("mode.set", { mode: "local" }), window.location.reload();
3301
- } catch (reason) {
3302
- setError(messageOf(reason)), setBusy(!1);
3293
+ let nextDevices = await props.control("devices");
3294
+ if (setDevices(nextDevices), setNeedsAuthorization(!1), selectedHost !== void 0) {
3295
+ let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
3296
+ nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : (setSelectedHost(nextSelectedHost), props.control("workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setWorkspaces(w)).catch(() => {
3297
+ }), props.control("codex.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setCodexWorkspaces(w)).catch(() => {
3298
+ }), props.control("cursor.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setCursorWorkspaces(w)).catch(() => {
3299
+ }), props.control("antigravity.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setAntigravityWorkspaces(w)).catch(() => {
3300
+ }), props.control("pi.workspaces.list", { targetDeviceId: nextSelectedHost.deviceId }).then((w) => setPiWorkspaces(w)).catch(() => {
3301
+ }));
3302
+ }
3303
+ } catch {
3304
+ setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
3303
3305
  }
3304
- }, setCurrentDeviceControl = async (enabled) => {
3306
+ } catch (reason) {
3307
+ setError(messageOf(reason));
3308
+ } finally {
3309
+ setBusy(!1);
3310
+ }
3311
+ }, show = async () => {
3312
+ setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setOpen(!0), await refreshRemote();
3313
+ };
3314
+ React.useEffect(() => {
3315
+ if (!(!open || selectedHost !== void 0))
3316
+ return props.statusFeed.subscribe(setStatus);
3317
+ }, [open, selectedHost]);
3318
+ let chooseAnotherHost = () => {
3319
+ setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
3320
+ }, signInClient = async () => {
3321
+ if (!(email.trim() === "" || password === "" || loginServerUrl.trim() === "")) {
3305
3322
  setBusy(!0), setError(void 0);
3306
3323
  try {
3307
- setStatus(await props.control("host.authorization.set", { enabled }));
3324
+ await props.control("settings.configure", {
3325
+ role: "client",
3326
+ serverUrl: loginServerUrl.trim(),
3327
+ email: email.trim(),
3328
+ password
3329
+ }), setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setPassword("");
3308
3330
  } catch (reason) {
3309
3331
  setError(messageOf(reason));
3310
3332
  } finally {
3311
3333
  setBusy(!1);
3312
3334
  }
3313
- }, logoutRemote = async () => {
3335
+ }
3336
+ }, openLocalWorkspaces = async () => {
3337
+ setBusy(!0), setError(void 0);
3338
+ try {
3339
+ await props.control("mode.set", { mode: "local" }), window.location.reload();
3340
+ } catch (reason) {
3341
+ setError(messageOf(reason)), setBusy(!1);
3342
+ }
3343
+ }, setCurrentDeviceControl = async (enabled) => {
3344
+ setBusy(!0), setError(void 0);
3345
+ try {
3346
+ setStatus(await props.control("host.authorization.set", { enabled }));
3347
+ } catch (reason) {
3348
+ setError(messageOf(reason));
3349
+ } finally {
3350
+ setBusy(!1);
3351
+ }
3352
+ }, logoutRemote = async () => {
3353
+ setBusy(!0), setError(void 0);
3354
+ try {
3355
+ await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setStatus(await props.control("status"));
3356
+ } catch (reason) {
3357
+ setError(messageOf(reason));
3358
+ } finally {
3359
+ setBusy(!1);
3360
+ }
3361
+ }, openWorkspace = async (selection) => {
3362
+ let targetBackend = selection?.backend ?? workspaceBackend, targetPath = (selection?.path ?? path).trim(), targetCodexWorkspaceId = selection?.backend === "codex" ? selection.workspaceId : selection === void 0 ? codexWorkspaceId : void 0, targetCursorWorkspaceId = selection?.backend === "cursor" ? selection.workspaceId : selection === void 0 ? cursorWorkspaceId : void 0, targetAntigravityWorkspaceId = selection?.backend === "antigravity" ? selection.workspaceId : selection === void 0 ? antigravityWorkspaceId : void 0, targetPiWorkspaceId = selection?.backend === "pi" ? selection.workspaceId : selection === void 0 ? piWorkspaceId : void 0, targetOpencodeWorkspaceId = selection?.backend === "opencode" ? selection.workspaceId : selection === void 0 ? opencodeWorkspaceId : void 0, createWorkspace = selection === void 0 && addingWorkspace;
3363
+ if (!(selectedHost === void 0 || targetPath === "" || !createWorkspace && targetBackend === "codex" && targetCodexWorkspaceId === void 0 || !createWorkspace && targetBackend === "cursor" && targetCursorWorkspaceId === void 0 && targetPath === "" || !createWorkspace && targetBackend === "antigravity" && targetAntigravityWorkspaceId === void 0 && targetPath === "")) {
3314
3364
  setBusy(!0), setError(void 0);
3315
3365
  try {
3316
- await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setStatus(await props.control("status"));
3366
+ let nextStatus = await (targetBackend === "codex" ? createWorkspace ? props.control("codex.workspace.create", {
3367
+ targetDeviceId: selectedHost.deviceId,
3368
+ path: targetPath
3369
+ }) : props.control("codex.workspace.open", {
3370
+ targetDeviceId: selectedHost.deviceId,
3371
+ workspaceId: targetCodexWorkspaceId
3372
+ }) : targetBackend === "cursor" ? createWorkspace || targetCursorWorkspaceId === void 0 ? props.control("cursor.workspace.create", {
3373
+ targetDeviceId: selectedHost.deviceId,
3374
+ path: targetPath
3375
+ }) : props.control("cursor.workspace.open", {
3376
+ targetDeviceId: selectedHost.deviceId,
3377
+ workspaceId: targetCursorWorkspaceId
3378
+ }) : targetBackend === "antigravity" ? createWorkspace || targetAntigravityWorkspaceId === void 0 ? props.control("antigravity.workspace.create", {
3379
+ targetDeviceId: selectedHost.deviceId,
3380
+ path: targetPath
3381
+ }) : props.control("antigravity.workspace.open", {
3382
+ targetDeviceId: selectedHost.deviceId,
3383
+ workspaceId: targetAntigravityWorkspaceId
3384
+ }) : targetBackend === "pi" ? createWorkspace || targetPiWorkspaceId === void 0 ? props.control("pi.workspace.create", {
3385
+ targetDeviceId: selectedHost.deviceId,
3386
+ path: targetPath
3387
+ }) : props.control("pi.workspace.open", {
3388
+ targetDeviceId: selectedHost.deviceId,
3389
+ workspaceId: targetPiWorkspaceId
3390
+ }) : targetBackend === "opencode" ? createWorkspace || targetOpencodeWorkspaceId === void 0 ? props.control("opencode.workspace.create", {
3391
+ targetDeviceId: selectedHost.deviceId,
3392
+ path: targetPath
3393
+ }) : props.control("opencode.workspace.open", {
3394
+ targetDeviceId: selectedHost.deviceId,
3395
+ workspaceId: targetOpencodeWorkspaceId
3396
+ }) : props.control("workspace.open", {
3397
+ targetDeviceId: selectedHost.deviceId,
3398
+ path: targetPath
3399
+ }));
3400
+ setStatus(nextStatus), nextStatus.workspaceSelection !== void 0 && window.sessionStorage.setItem(pendingWorkspaceSelectionKey, JSON.stringify(nextStatus.workspaceSelection)), window.location.reload();
3317
3401
  } catch (reason) {
3318
- setError(messageOf(reason));
3319
- } finally {
3320
- setBusy(!1);
3402
+ setError(messageOf(reason)), setBusy(!1);
3321
3403
  }
3322
- }, openWorkspace = async (selection) => {
3323
- let targetBackend = selection?.backend ?? workspaceBackend, targetPath = (selection?.path ?? path).trim(), targetCodexWorkspaceId = selection?.backend === "codex" ? selection.workspaceId : selection === void 0 ? codexWorkspaceId : void 0, targetCursorWorkspaceId = selection?.backend === "cursor" ? selection.workspaceId : selection === void 0 ? cursorWorkspaceId : void 0, targetAntigravityWorkspaceId = selection?.backend === "antigravity" ? selection.workspaceId : selection === void 0 ? antigravityWorkspaceId : void 0, createWorkspace = selection === void 0 && addingWorkspace;
3324
- if (!(selectedHost === void 0 || targetPath === "" || !createWorkspace && targetBackend === "codex" && targetCodexWorkspaceId === void 0 || !createWorkspace && targetBackend === "cursor" && targetCursorWorkspaceId === void 0 && targetPath === "" || !createWorkspace && targetBackend === "antigravity" && targetAntigravityWorkspaceId === void 0 && targetPath === "")) {
3325
- setBusy(!0), setError(void 0);
3326
- try {
3327
- let nextStatus = await (targetBackend === "codex" ? createWorkspace ? props.control("codex.workspace.create", {
3328
- targetDeviceId: selectedHost.deviceId,
3329
- path: targetPath
3330
- }) : props.control("codex.workspace.open", {
3331
- targetDeviceId: selectedHost.deviceId,
3332
- workspaceId: targetCodexWorkspaceId
3333
- }) : targetBackend === "cursor" ? createWorkspace || targetCursorWorkspaceId === void 0 ? props.control("cursor.workspace.create", {
3334
- targetDeviceId: selectedHost.deviceId,
3335
- path: targetPath
3336
- }) : props.control("cursor.workspace.open", {
3337
- targetDeviceId: selectedHost.deviceId,
3338
- workspaceId: targetCursorWorkspaceId
3339
- }) : targetBackend === "antigravity" ? createWorkspace || targetAntigravityWorkspaceId === void 0 ? props.control("antigravity.workspace.create", {
3340
- targetDeviceId: selectedHost.deviceId,
3341
- path: targetPath
3342
- }) : props.control("antigravity.workspace.open", {
3343
- targetDeviceId: selectedHost.deviceId,
3344
- workspaceId: targetAntigravityWorkspaceId
3345
- }) : props.control("workspace.open", {
3346
- targetDeviceId: selectedHost.deviceId,
3347
- path: targetPath
3348
- }));
3349
- setStatus(nextStatus), nextStatus.workspaceSelection !== void 0 && window.sessionStorage.setItem(pendingWorkspaceSelectionKey, JSON.stringify(nextStatus.workspaceSelection)), window.location.reload();
3350
- } catch (reason) {
3351
- setError(messageOf(reason)), setBusy(!1);
3352
- }
3404
+ }
3405
+ }, remoteLabel = status?.mode === "remote" ? t("activeRemote", { name: status.target?.name ?? t("host") }) : t("remoteEntry"), remoteActionLabel = status?.mode === "remote" ? `${remoteLabel} \xB7 ${t("exitRemote")}` : remoteLabel, visibleWorkspaces = showAllWorkspaces ? workspaces : workspaces.slice(0, 3), visibleCodexWorkspaces = showAllCodexWorkspaces ? codexWorkspaces : codexWorkspaces.slice(0, 3), visibleCursorWorkspaces = showAllCursorWorkspaces ? cursorWorkspaces : cursorWorkspaces.slice(0, 3), visibleAntigravityWorkspaces = showAllAntigravityWorkspaces ? antigravityWorkspaces : antigravityWorkspaces.slice(0, 3), visiblePiWorkspaces = showAllPiWorkspaces ? piWorkspaces : piWorkspaces.slice(0, 3), visibleOpencodeWorkspaces = showAllOpencodeWorkspaces ? opencodeWorkspaces : opencodeWorkspaces.slice(0, 3), codexAvailable = status?.remoteFeatures?.codex === !0, cursorAvailable = status?.remoteFeatures?.cursor === !0, antigravityAvailable = status?.remoteFeatures?.antigravity === !0, piAvailable = status?.remoteFeatures?.pi === !0, opencodeAvailable = status?.remoteFeatures?.opencode === !0, selectedHostDetails = selectedHost === void 0 ? void 0 : [
3406
+ formatPlatform(selectedHost.platform),
3407
+ selectedHost.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: selectedHost.harnessVersion }),
3408
+ selectedHost.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: selectedHost.clientVersion })
3409
+ ].filter(Boolean).join(" \xB7 "), connectedClients = status?.host?.connectedClients ?? [], connectedCount = connectedClients.length, connectedCountLabel = t("connectedClientCount", { count: connectedCount }), connectedMenu = !needsAuthorization && status?.hostAuthorizationAvailable === !0 ? React.createElement(
3410
+ "div",
3411
+ {
3412
+ className: `dshRemoteConnectedMenu${devicesOpen ? " isOpen" : ""}`
3413
+ },
3414
+ React.createElement("a", {
3415
+ href: connectedCount > 0 ? "#connected-devices" : void 0,
3416
+ className: `dshRemoteConnectedCount${connectedCount > 0 ? " isOnline isInteractive" : ""}`,
3417
+ "aria-expanded": connectedCount > 0 ? devicesOpen : void 0,
3418
+ "aria-haspopup": connectedCount > 0 ? "dialog" : void 0,
3419
+ title: connectedCountLabel,
3420
+ "aria-label": connectedCountLabel,
3421
+ onClick: (event) => {
3422
+ event.preventDefault(), connectedCount !== 0 && setDevicesOpen((current) => !current);
3353
3423
  }
3354
- }, remoteLabel = status?.mode === "remote" ? t("activeRemote", { name: status.target?.name ?? t("host") }) : t("remoteEntry"), remoteActionLabel = status?.mode === "remote" ? `${remoteLabel} \xB7 ${t("exitRemote")}` : remoteLabel, visibleWorkspaces = showAllWorkspaces ? workspaces : workspaces.slice(0, 3), visibleCodexWorkspaces = showAllCodexWorkspaces ? codexWorkspaces : codexWorkspaces.slice(0, 3), visibleCursorWorkspaces = showAllCursorWorkspaces ? cursorWorkspaces : cursorWorkspaces.slice(0, 3), visibleAntigravityWorkspaces = showAllAntigravityWorkspaces ? antigravityWorkspaces : antigravityWorkspaces.slice(0, 3), codexAvailable = status?.remoteFeatures?.codex === !0, cursorAvailable = status?.remoteFeatures?.cursor === !0, antigravityAvailable = status?.remoteFeatures?.antigravity === !0, selectedHostDetails = selectedHost === void 0 ? void 0 : [
3355
- formatPlatform(selectedHost.platform),
3356
- selectedHost.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: selectedHost.harnessVersion }),
3357
- selectedHost.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: selectedHost.clientVersion })
3358
- ].filter(Boolean).join(" \xB7 "), connectedClients = status?.host?.connectedClients ?? [], connectedCount = connectedClients.length, connectedCountLabel = t("connectedClientCount", { count: connectedCount }), connectedMenu = !needsAuthorization && status?.hostAuthorizationAvailable === !0 ? React.createElement(
3424
+ }, connectedCountLabel),
3425
+ devicesOpen && connectedCount > 0 ? React.createElement(
3359
3426
  "div",
3360
3427
  {
3361
- className: `dshRemoteConnectedMenu${devicesOpen ? " isOpen" : ""}`
3428
+ className: "dshRemoteConnectedPanel",
3429
+ id: "connected-devices",
3430
+ role: "dialog",
3431
+ "aria-label": t("currentConnectedDevices")
3362
3432
  },
3363
- React.createElement("a", {
3364
- href: connectedCount > 0 ? "#connected-devices" : void 0,
3365
- className: `dshRemoteConnectedCount${connectedCount > 0 ? " isOnline isInteractive" : ""}`,
3366
- "aria-expanded": connectedCount > 0 ? devicesOpen : void 0,
3367
- "aria-haspopup": connectedCount > 0 ? "dialog" : void 0,
3368
- title: connectedCountLabel,
3369
- "aria-label": connectedCountLabel,
3370
- onClick: (event) => {
3371
- event.preventDefault(), connectedCount !== 0 && setDevicesOpen((current) => !current);
3372
- }
3373
- }, connectedCountLabel),
3374
- devicesOpen && connectedCount > 0 ? React.createElement(
3375
- "div",
3376
- {
3377
- className: "dshRemoteConnectedPanel",
3378
- id: "connected-devices",
3379
- role: "dialog",
3380
- "aria-label": t("currentConnectedDevices")
3381
- },
3382
- React.createElement("strong", { className: "dshRemoteConnectedPanelTitle" }, t("currentConnectedDevices")),
3383
- React.createElement(
3384
- "div",
3385
- { className: "dshRemoteClientList", "aria-label": t("currentConnectedDevices") },
3386
- ...connectedClients.map((client) => React.createElement(
3387
- "div",
3388
- {
3389
- key: client.deviceId,
3390
- className: "dshRemoteClientRow"
3391
- },
3392
- React.createElement(
3393
- "span",
3394
- null,
3395
- React.createElement("strong", null, client.name.trim() === "" ? t("unknownDevice") : client.name),
3396
- React.createElement("small", null, [
3397
- client.platform === void 0 ? void 0 : formatPlatform(client.platform),
3398
- connectedClientModeLabel(client.mode, t)
3399
- ].filter(Boolean).join(" \xB7 "))
3400
- ),
3401
- React.createElement("small", { className: "dshRemoteClientOnline" }, t("connected"))
3402
- ))
3403
- )
3404
- ) : null
3405
- ) : null, listedHosts = connectingHost === void 0 ? devices : [connectingHost];
3406
- return React.createElement(
3407
- React.Fragment,
3408
- null,
3433
+ React.createElement("strong", { className: "dshRemoteConnectedPanelTitle" }, t("currentConnectedDevices")),
3409
3434
  React.createElement(
3410
3435
  "div",
3411
- { className: `dshRemoteSidebarEntry${status?.mode === "remote" ? " isActive" : ""}${props.wide ? " isWide" : " isRail"}` },
3412
- React.createElement(status?.mode === "remote" && props.wide ? "div" : "button", {
3413
- ...status?.mode === "remote" && props.wide ? {} : {
3414
- type: "button",
3415
- disabled: status?.mode === "remote" && busy,
3416
- onClick: () => void (status?.mode === "remote" ? openLocalWorkspaces() : show())
3417
- },
3418
- className: "dshRemoteModeButton",
3419
- title: props.wide ? remoteLabel : remoteActionLabel,
3420
- "aria-label": props.wide ? remoteLabel : remoteActionLabel
3421
- }, React.createElement(
3422
- "svg",
3436
+ { className: "dshRemoteClientList", "aria-label": t("currentConnectedDevices") },
3437
+ ...connectedClients.map((client) => React.createElement(
3438
+ "div",
3423
3439
  {
3424
- className: "dshRemoteComputerIcon",
3425
- viewBox: "0 0 24 24",
3426
- fill: "none",
3427
- stroke: "currentColor",
3428
- strokeWidth: 1.7,
3429
- strokeLinecap: "round",
3430
- strokeLinejoin: "round",
3431
- "aria-hidden": !0
3440
+ key: client.deviceId,
3441
+ className: "dshRemoteClientRow"
3432
3442
  },
3433
- React.createElement("rect", { x: 3, y: 4, width: 18, height: 13, rx: 2 }),
3434
- React.createElement("path", { d: "M8 21h8M12 17v4" })
3435
- ), props.wide ? React.createElement("span", { className: "dshRemoteSidebarLabel" }, remoteLabel) : null),
3436
- status?.mode === "remote" && props.wide ? React.createElement("button", {
3443
+ React.createElement(
3444
+ "span",
3445
+ null,
3446
+ React.createElement("strong", null, client.name.trim() === "" ? t("unknownDevice") : client.name),
3447
+ React.createElement("small", null, [
3448
+ client.platform === void 0 ? void 0 : formatPlatform(client.platform),
3449
+ connectedClientModeLabel(client.mode, t)
3450
+ ].filter(Boolean).join(" \xB7 "))
3451
+ ),
3452
+ React.createElement("small", { className: "dshRemoteClientOnline" }, t("connected"))
3453
+ ))
3454
+ )
3455
+ ) : null
3456
+ ) : null, listedHosts = connectingHost === void 0 ? devices : [connectingHost];
3457
+ return React.createElement(
3458
+ React.Fragment,
3459
+ null,
3460
+ React.createElement(
3461
+ "div",
3462
+ { className: `dshRemoteSidebarEntry${status?.mode === "remote" ? " isActive" : ""}${props.wide ? " isWide" : " isRail"}` },
3463
+ React.createElement(status?.mode === "remote" && props.wide ? "div" : "button", {
3464
+ ...status?.mode === "remote" && props.wide ? {} : {
3437
3465
  type: "button",
3438
- className: "dshRemoteExitLink",
3439
- disabled: busy,
3440
- onClick: () => void openLocalWorkspaces()
3441
- }, t("exitRemote")) : null
3442
- ),
3443
- open ? React.createElement("div", {
3444
- className: "dshRemoteBackdrop",
3445
- role: "presentation",
3446
- onMouseDown: (event) => {
3447
- event.target === event.currentTarget && setOpen(!1);
3448
- }
3466
+ disabled: status?.mode === "remote" && busy,
3467
+ onClick: () => void (status?.mode === "remote" ? openLocalWorkspaces() : show())
3468
+ },
3469
+ className: "dshRemoteModeButton",
3470
+ title: props.wide ? remoteLabel : remoteActionLabel,
3471
+ "aria-label": props.wide ? remoteLabel : remoteActionLabel
3449
3472
  }, React.createElement(
3450
- "section",
3473
+ "svg",
3451
3474
  {
3452
- className: `dshRemotePage${selectedHost === void 0 ? "" : " hasSelectedHost"}`,
3453
- role: "dialog",
3454
- "aria-modal": !0,
3455
- "aria-label": selectedHost?.name ?? t("remoteTitle")
3475
+ className: "dshRemoteComputerIcon",
3476
+ viewBox: "0 0 24 24",
3477
+ fill: "none",
3478
+ stroke: "currentColor",
3479
+ strokeWidth: 1.7,
3480
+ strokeLinecap: "round",
3481
+ strokeLinejoin: "round",
3482
+ "aria-hidden": !0
3456
3483
  },
3484
+ React.createElement("rect", { x: 3, y: 4, width: 18, height: 13, rx: 2 }),
3485
+ React.createElement("path", { d: "M8 21h8M12 17v4" })
3486
+ ), props.wide ? React.createElement("span", { className: "dshRemoteSidebarLabel" }, remoteLabel) : null),
3487
+ status?.mode === "remote" && props.wide ? React.createElement("button", {
3488
+ type: "button",
3489
+ className: "dshRemoteExitLink",
3490
+ disabled: busy,
3491
+ onClick: () => void openLocalWorkspaces()
3492
+ }, t("exitRemote")) : null
3493
+ ),
3494
+ open ? React.createElement("div", {
3495
+ className: "dshRemoteBackdrop",
3496
+ role: "presentation",
3497
+ onMouseDown: (event) => {
3498
+ event.target === event.currentTarget && setOpen(!1);
3499
+ }
3500
+ }, React.createElement(
3501
+ "section",
3502
+ {
3503
+ className: `dshRemotePage${selectedHost === void 0 ? "" : " hasSelectedHost"}`,
3504
+ role: "dialog",
3505
+ "aria-modal": !0,
3506
+ "aria-label": selectedHost?.name ?? t("remoteTitle")
3507
+ },
3508
+ React.createElement(
3509
+ "header",
3510
+ { className: "dshRemotePageHeader" },
3457
3511
  React.createElement(
3458
- "header",
3459
- { className: "dshRemotePageHeader" },
3512
+ "div",
3513
+ { className: "dshRemotePageIntro" },
3460
3514
  React.createElement(
3461
3515
  "div",
3462
- { className: "dshRemotePageIntro" },
3463
- React.createElement(
3464
- "div",
3465
- { className: "dshRemotePageTitleRow" },
3466
- React.createElement("strong", null, selectedHost?.name ?? t("remoteTitle")),
3467
- selectedHost === void 0 ? React.createElement("a", {
3468
- className: "dshRemoteStarLink",
3469
- href: "https://github.com/liguobao/ds-harness-remote",
3470
- target: "_blank",
3471
- rel: "noreferrer"
3472
- }, t("starProject")) : null
3473
- ),
3474
- React.createElement("p", null, selectedHostDetails ?? t("remoteDescription"))
3516
+ { className: "dshRemotePageTitleRow" },
3517
+ React.createElement("strong", null, selectedHost?.name ?? t("remoteTitle")),
3518
+ selectedHost === void 0 ? React.createElement("a", {
3519
+ className: "dshRemoteStarLink",
3520
+ href: "https://github.com/liguobao/ds-harness-remote",
3521
+ target: "_blank",
3522
+ rel: "noreferrer"
3523
+ }, t("starProject")) : null
3475
3524
  ),
3476
- React.createElement(
3477
- "div",
3478
- { className: "dshRemotePageActions" },
3479
- selectedHost === void 0 ? null : React.createElement("button", {
3480
- type: "button",
3481
- className: "dshRemotePageBack",
3482
- disabled: busy,
3483
- title: t("backToHosts"),
3484
- onClick: chooseAnotherHost
3485
- }, t("backToHosts")),
3486
- React.createElement("button", {
3487
- type: "button",
3488
- className: "dshRemotePageRefresh",
3489
- disabled: busy,
3490
- title: t("refreshRemote"),
3491
- "aria-label": t("refreshRemote"),
3492
- onClick: () => void refreshRemote()
3493
- }, t("refreshRemoteShort")),
3494
- React.createElement("button", { type: "button", className: "dshRemotePageClose", onClick: () => setOpen(!1), "aria-label": t("close") }, "\xD7")
3495
- )
3525
+ React.createElement("p", null, selectedHostDetails ?? t("remoteDescription"))
3496
3526
  ),
3497
3527
  React.createElement(
3498
- "main",
3499
- { className: "dshRemotePageBody" },
3500
- status?.mode === "remote" ? React.createElement("button", {
3528
+ "div",
3529
+ { className: "dshRemotePageActions" },
3530
+ selectedHost === void 0 ? null : React.createElement("button", {
3501
3531
  type: "button",
3502
- className: "dshRemoteLocalLink",
3532
+ className: "dshRemotePageBack",
3503
3533
  disabled: busy,
3504
- onClick: () => void openLocalWorkspaces()
3505
- }, t("openLocalWorkspaces")) : null,
3506
- React.createElement(
3534
+ title: t("backToHosts"),
3535
+ onClick: chooseAnotherHost
3536
+ }, t("backToHosts")),
3537
+ React.createElement("button", {
3538
+ type: "button",
3539
+ className: "dshRemotePageRefresh",
3540
+ disabled: busy,
3541
+ title: t("refreshRemote"),
3542
+ "aria-label": t("refreshRemote"),
3543
+ onClick: () => void refreshRemote()
3544
+ }, t("refreshRemoteShort")),
3545
+ React.createElement("button", { type: "button", className: "dshRemotePageClose", onClick: () => setOpen(!1), "aria-label": t("close") }, "\xD7")
3546
+ )
3547
+ ),
3548
+ React.createElement(
3549
+ "main",
3550
+ { className: "dshRemotePageBody" },
3551
+ status?.mode === "remote" ? React.createElement("button", {
3552
+ type: "button",
3553
+ className: "dshRemoteLocalLink",
3554
+ disabled: busy,
3555
+ onClick: () => void openLocalWorkspaces()
3556
+ }, t("openLocalWorkspaces")) : null,
3557
+ React.createElement(
3558
+ React.Fragment,
3559
+ null,
3560
+ needsAuthorization ? React.createElement(
3561
+ "section",
3562
+ { className: "dshRemoteEnable" },
3563
+ React.createElement(
3564
+ "div",
3565
+ { className: "dshRemoteLoginHeading" },
3566
+ React.createElement("strong", { className: "dshRemoteLoginTitle" }, t("signInClient")),
3567
+ React.createElement("span", null, t("signInClientDescription"))
3568
+ ),
3569
+ React.createElement(
3570
+ "div",
3571
+ { className: "dshRemoteLoginTabs", role: "tablist" },
3572
+ ...orderedQrProviders.map(qrLoginTab),
3573
+ React.createElement("button", {
3574
+ type: "button",
3575
+ role: "tab",
3576
+ id: "dsh-remote-password-tab",
3577
+ "aria-selected": loginMethod === "password",
3578
+ "aria-controls": "dsh-remote-password-panel",
3579
+ className: loginMethod === "password" ? "isActive" : "",
3580
+ disabled: busy,
3581
+ onClick: () => selectLoginMethod("password")
3582
+ }, t("accountPasswordLogin"))
3583
+ ),
3584
+ providersLoading ? React.createElement("p", { role: "status" }, t("loadingLoginProviders")) : null,
3585
+ providersFailed ? React.createElement("button", {
3586
+ type: "button",
3587
+ onClick: () => {
3588
+ setError(void 0), setProviderReload((value) => value + 1);
3589
+ }
3590
+ }, t("retryLoginProviders")) : null,
3591
+ !providersLoading && !providersFailed && oauthProviders.length === 0 ? React.createElement("p", { role: "status" }, t("noLoginProviders")) : null,
3592
+ loginMethod !== "password" && selectedProvider !== void 0 ? React.createElement(
3593
+ "div",
3594
+ {
3595
+ className: "dshRemoteQrLogin",
3596
+ role: "tabpanel",
3597
+ id: `dsh-remote-${loginMethod}-panel`,
3598
+ "aria-labelledby": `dsh-remote-${loginMethod}-tab`
3599
+ },
3600
+ qrImage === void 0 ? React.createElement(
3601
+ "div",
3602
+ { className: "dshRemoteQrPlaceholder", "aria-busy": busy },
3603
+ qrExpired ? React.createElement("p", null, t("qrLoginExpired")) : React.createElement("span", null, t("checkingConnection"))
3604
+ ) : qrSession !== void 0 ? React.createElement(
3605
+ "a",
3606
+ {
3607
+ className: "dshRemoteQrOpen",
3608
+ href: qrSession.scanUrl,
3609
+ target: "_blank",
3610
+ rel: "noopener noreferrer",
3611
+ "aria-label": t("openInBrowser")
3612
+ },
3613
+ React.createElement("img", {
3614
+ src: qrImage,
3615
+ width: 184,
3616
+ height: 184,
3617
+ alt: scanLabel
3618
+ }),
3619
+ React.createElement("span", null, t("openInBrowser"), " \u2197")
3620
+ ) : null,
3621
+ React.createElement("strong", null, scanLabel),
3622
+ React.createElement("p", null, t("scanLoginHint")),
3623
+ status?.serverUrl === void 0 ? null : React.createElement(
3624
+ "p",
3625
+ { className: "dshRemoteServiceAddress" },
3626
+ t("currentServiceAddress"),
3627
+ " ",
3628
+ React.createElement("a", {
3629
+ href: status.serverUrl,
3630
+ target: "_blank",
3631
+ rel: "noreferrer"
3632
+ }, status.serverUrl)
3633
+ ),
3634
+ qrExpired ? React.createElement("button", {
3635
+ type: "button",
3636
+ disabled: busy,
3637
+ onClick: () => setQrExpired(!1)
3638
+ }, t("refreshQrCode")) : null
3639
+ ) : React.createElement(
3640
+ "div",
3641
+ {
3642
+ className: "dshRemoteClientLogin",
3643
+ role: "tabpanel",
3644
+ id: "dsh-remote-password-panel",
3645
+ "aria-labelledby": "dsh-remote-password-tab"
3646
+ },
3647
+ React.createElement("input", {
3648
+ type: "url",
3649
+ value: loginServerUrl,
3650
+ disabled: busy,
3651
+ autoComplete: "url",
3652
+ placeholder: t("serverUrl"),
3653
+ "aria-label": t("serverUrl"),
3654
+ onChange: (event) => setLoginServerUrl(event.target.value)
3655
+ }),
3656
+ React.createElement("input", {
3657
+ type: "email",
3658
+ value: email,
3659
+ disabled: busy,
3660
+ autoComplete: "username",
3661
+ placeholder: t("account"),
3662
+ "aria-label": t("account"),
3663
+ onChange: (event) => setEmail(event.target.value)
3664
+ }),
3665
+ React.createElement("input", {
3666
+ type: "password",
3667
+ value: password,
3668
+ disabled: busy,
3669
+ autoComplete: "current-password",
3670
+ placeholder: t("password"),
3671
+ "aria-label": t("password"),
3672
+ onChange: (event) => setPassword(event.target.value)
3673
+ }),
3674
+ React.createElement("button", { type: "button", disabled: busy || loginServerUrl.trim() === "" || email.trim() === "" || password === "", onClick: () => void signInClient() }, t(busy ? "signingIn" : "startSignIn"))
3675
+ )
3676
+ ) : null,
3677
+ needsAuthorization ? null : React.createElement(
3507
3678
  React.Fragment,
3508
3679
  null,
3509
- needsAuthorization ? React.createElement(
3680
+ selectedHost === void 0 ? React.createElement(
3510
3681
  "section",
3511
- { className: "dshRemoteEnable" },
3682
+ { className: "dshRemoteHosts", "aria-label": t("chooseHost") },
3512
3683
  React.createElement(
3513
3684
  "div",
3514
- { className: "dshRemoteLoginHeading" },
3515
- React.createElement("strong", { className: "dshRemoteLoginTitle" }, t("signInClient")),
3516
- React.createElement("span", null, t("signInClientDescription"))
3517
- ),
3518
- React.createElement(
3519
- "div",
3520
- { className: "dshRemoteLoginTabs", role: "tablist" },
3521
- ...orderedQrProviders.map(qrLoginTab),
3522
- React.createElement("button", {
3523
- type: "button",
3524
- role: "tab",
3525
- id: "dsh-remote-password-tab",
3526
- "aria-selected": loginMethod === "password",
3527
- "aria-controls": "dsh-remote-password-panel",
3528
- className: loginMethod === "password" ? "isActive" : "",
3529
- disabled: busy,
3530
- onClick: () => selectLoginMethod("password")
3531
- }, t("accountPasswordLogin"))
3685
+ { className: "dshRemoteSectionHeading" },
3686
+ React.createElement(
3687
+ "div",
3688
+ { className: "dshRemoteSectionTitle" },
3689
+ React.createElement("strong", null, t("chooseHost")),
3690
+ status?.hostAuthorizationAvailable ? React.createElement(
3691
+ "div",
3692
+ { className: "dshRemoteHostControlToggle" },
3693
+ React.createElement("span", null, t("allowControlDevice")),
3694
+ React.createElement("input", {
3695
+ type: "checkbox",
3696
+ role: "switch",
3697
+ disabled: busy,
3698
+ "aria-label": t("allowControlDevice"),
3699
+ checked: status.host?.authorized === !0,
3700
+ onChange: (event) => void setCurrentDeviceControl(event.target.checked)
3701
+ })
3702
+ ) : null,
3703
+ connectedMenu
3704
+ )
3532
3705
  ),
3533
- providersLoading ? React.createElement("p", { role: "status" }, t("loadingLoginProviders")) : null,
3534
- providersFailed ? React.createElement("button", {
3535
- type: "button",
3536
- onClick: () => {
3537
- setError(void 0), setProviderReload((value) => value + 1);
3538
- }
3539
- }, t("retryLoginProviders")) : null,
3540
- !providersLoading && !providersFailed && oauthProviders.length === 0 ? React.createElement("p", { role: "status" }, t("noLoginProviders")) : null,
3541
- loginMethod !== "password" && selectedProvider !== void 0 ? React.createElement(
3542
- "div",
3706
+ React.createElement("div", {
3707
+ className: `dshRemoteHostList${connectingHost === void 0 ? "" : " isCollapsed"}`,
3708
+ "aria-busy": connectingHost === void 0 ? void 0 : !0
3709
+ }, listedHosts.length === 0 ? React.createElement("p", null, t(busy ? "checkingConnection" : "noRemoteHosts")) : listedHosts.map((device) => React.createElement(
3710
+ "button",
3543
3711
  {
3544
- className: "dshRemoteQrLogin",
3545
- role: "tabpanel",
3546
- id: `dsh-remote-${loginMethod}-panel`,
3547
- "aria-labelledby": `dsh-remote-${loginMethod}-tab`
3712
+ type: "button",
3713
+ key: device.deviceId,
3714
+ disabled: busy || !device.online,
3715
+ "aria-current": connectingHost?.deviceId === device.deviceId ? "true" : void 0,
3716
+ onClick: () => void selectHost(device)
3548
3717
  },
3549
- qrImage === void 0 ? React.createElement(
3550
- "div",
3551
- { className: "dshRemoteQrPlaceholder", "aria-busy": busy },
3552
- qrExpired ? React.createElement("p", null, t("qrLoginExpired")) : React.createElement("span", null, t("checkingConnection"))
3553
- ) : qrSession !== void 0 ? React.createElement(
3554
- "a",
3555
- {
3556
- className: "dshRemoteQrOpen",
3557
- href: qrSession.scanUrl,
3558
- target: "_blank",
3559
- rel: "noopener noreferrer",
3560
- "aria-label": t("openInBrowser")
3561
- },
3562
- React.createElement("img", {
3563
- src: qrImage,
3564
- width: 184,
3565
- height: 184,
3566
- alt: scanLabel
3567
- }),
3568
- React.createElement("span", null, t("openInBrowser"), " \u2197")
3569
- ) : null,
3570
- React.createElement("strong", null, scanLabel),
3571
- React.createElement("p", null, t("scanLoginHint")),
3572
- status?.serverUrl === void 0 ? null : React.createElement(
3573
- "p",
3574
- { className: "dshRemoteServiceAddress" },
3575
- t("currentServiceAddress"),
3576
- " ",
3577
- React.createElement("a", {
3578
- href: status.serverUrl,
3579
- target: "_blank",
3580
- rel: "noreferrer"
3581
- }, status.serverUrl)
3718
+ React.createElement(
3719
+ "span",
3720
+ null,
3721
+ React.createElement("strong", null, device.name),
3722
+ React.createElement("small", null, [
3723
+ formatPlatform(device.platform),
3724
+ device.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: device.harnessVersion }),
3725
+ device.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: device.clientVersion })
3726
+ ].filter(Boolean).join(" \xB7 "))
3582
3727
  ),
3583
- qrExpired ? React.createElement("button", {
3728
+ React.createElement("small", null, t(device.online ? "online" : "offline"))
3729
+ )))
3730
+ ) : null,
3731
+ React.createElement(RemoteProgressView, { progress, t }),
3732
+ selectedHost === void 0 ? connectingHost === void 0 ? React.createElement(
3733
+ React.Fragment,
3734
+ null,
3735
+ React.createElement("p", { className: "dshRemoteHint" }, t("selectHostHint")),
3736
+ React.createElement(
3737
+ "footer",
3738
+ { className: "dshRemoteAccountFooter" },
3739
+ React.createElement("span", null, status?.host?.account ?? t("account")),
3740
+ React.createElement("button", {
3584
3741
  type: "button",
3742
+ className: "dshRemoteAccountExit",
3585
3743
  disabled: busy,
3586
- onClick: () => setQrExpired(!1)
3587
- }, t("refreshQrCode")) : null
3588
- ) : React.createElement(
3744
+ onClick: () => void logoutRemote()
3745
+ }, t("exitRemoteAccount"))
3746
+ )
3747
+ ) : null : React.createElement(
3748
+ "section",
3749
+ { className: "dshRemoteBrowser", "aria-label": t("chooseDirectory") },
3750
+ React.createElement(
3589
3751
  "div",
3590
- {
3591
- className: "dshRemoteClientLogin",
3592
- role: "tabpanel",
3593
- id: "dsh-remote-password-panel",
3594
- "aria-labelledby": "dsh-remote-password-tab"
3595
- },
3596
- React.createElement("input", {
3597
- type: "url",
3598
- value: loginServerUrl,
3599
- disabled: busy,
3600
- autoComplete: "url",
3601
- placeholder: t("serverUrl"),
3602
- "aria-label": t("serverUrl"),
3603
- onChange: (event) => setLoginServerUrl(event.target.value)
3604
- }),
3605
- React.createElement("input", {
3606
- type: "email",
3607
- value: email,
3752
+ { className: "dshRemoteSectionHeading dshRemoteWorkspaceHeading" },
3753
+ React.createElement("strong", null, t(addingWorkspace ? workspaceBackend === "codex" ? "addCodexWorkspace" : workspaceBackend === "cursor" ? "addCursorWorkspace" : workspaceBackend === "antigravity" ? "addAntigravityWorkspace" : workspaceBackend === "pi" ? "addPiWorkspace" : workspaceBackend === "opencode" ? "addOpencodeWorkspace" : "addRemoteWorkspace" : "existingWorkspaces")),
3754
+ addingWorkspace ? React.createElement("button", {
3755
+ type: "button",
3756
+ className: "dshRemoteCancelWorkspace",
3608
3757
  disabled: busy,
3609
- autoComplete: "username",
3610
- placeholder: t("account"),
3611
- "aria-label": t("account"),
3612
- onChange: (event) => setEmail(event.target.value)
3613
- }),
3614
- React.createElement("input", {
3615
- type: "password",
3616
- value: password,
3758
+ onClick: cancelAddingWorkspace
3759
+ }, t("cancelAddWorkspace")) : React.createElement("button", {
3760
+ type: "button",
3761
+ className: "dshRemoteAddWorkspace",
3617
3762
  disabled: busy,
3618
- autoComplete: "current-password",
3619
- placeholder: t("password"),
3620
- "aria-label": t("password"),
3621
- onChange: (event) => setPassword(event.target.value)
3622
- }),
3623
- React.createElement("button", { type: "button", disabled: busy || loginServerUrl.trim() === "" || email.trim() === "" || password === "", onClick: () => void signInClient() }, t(busy ? "signingIn" : "startSignIn"))
3624
- )
3625
- ) : null,
3626
- needsAuthorization ? null : React.createElement(
3627
- React.Fragment,
3628
- null,
3629
- selectedHost === void 0 ? React.createElement(
3630
- "section",
3631
- { className: "dshRemoteHosts", "aria-label": t("chooseHost") },
3632
- React.createElement(
3633
- "div",
3634
- { className: "dshRemoteSectionHeading" },
3635
- React.createElement(
3636
- "div",
3637
- { className: "dshRemoteSectionTitle" },
3638
- React.createElement("strong", null, t("chooseHost")),
3639
- status?.hostAuthorizationAvailable ? React.createElement(
3640
- "div",
3641
- { className: "dshRemoteHostControlToggle" },
3642
- React.createElement("span", null, t("allowControlDevice")),
3643
- React.createElement("input", {
3644
- type: "checkbox",
3645
- role: "switch",
3646
- disabled: busy,
3647
- "aria-label": t("allowControlDevice"),
3648
- checked: status.host?.authorized === !0,
3649
- onChange: (event) => void setCurrentDeviceControl(event.target.checked)
3650
- })
3651
- ) : null,
3652
- connectedMenu
3653
- )
3654
- ),
3655
- React.createElement("div", {
3656
- className: `dshRemoteHostList${connectingHost === void 0 ? "" : " isCollapsed"}`,
3657
- "aria-busy": connectingHost === void 0 ? void 0 : !0
3658
- }, listedHosts.length === 0 ? React.createElement("p", null, t(busy ? "checkingConnection" : "noRemoteHosts")) : listedHosts.map((device) => React.createElement(
3659
- "button",
3660
- {
3661
- type: "button",
3662
- key: device.deviceId,
3663
- disabled: busy || !device.online,
3664
- "aria-current": connectingHost?.deviceId === device.deviceId ? "true" : void 0,
3665
- onClick: () => void selectHost(device)
3666
- },
3763
+ title: t("addRemoteWorkspace"),
3764
+ "aria-label": t("addRemoteWorkspace"),
3765
+ onClick: () => startAddingWorkspace("harness")
3766
+ }, React.createElement("svg", {
3767
+ className: "dshRemoteAddWorkspaceIcon",
3768
+ viewBox: "0 0 16 16",
3769
+ "aria-hidden": !0,
3770
+ focusable: !1
3771
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" })))
3772
+ ),
3773
+ addingWorkspace ? React.createElement(
3774
+ "div",
3775
+ { className: "dshRemoteFolderBrowser" },
3776
+ directory === void 0 ? React.createElement("p", null, t("loadingDirectory")) : React.createElement(
3777
+ React.Fragment,
3778
+ null,
3667
3779
  React.createElement(
3668
- "span",
3669
- null,
3670
- React.createElement("strong", null, device.name),
3671
- React.createElement("small", null, [
3672
- formatPlatform(device.platform),
3673
- device.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: device.harnessVersion }),
3674
- device.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: device.clientVersion })
3675
- ].filter(Boolean).join(" \xB7 "))
3780
+ "nav",
3781
+ { className: "dshRemoteCrumbs", "aria-label": t("currentDirectory") },
3782
+ directory.crumbs.map((crumb) => React.createElement("button", {
3783
+ type: "button",
3784
+ key: crumb.path,
3785
+ disabled: busy || crumb.path === directory.path,
3786
+ onClick: () => void browseDirectory(crumb.path)
3787
+ }, crumb.path === directory.home ? "\u2302" : crumb.name))
3676
3788
  ),
3677
- React.createElement("small", null, t(device.online ? "online" : "offline"))
3678
- )))
3679
- ) : null,
3680
- React.createElement(RemoteProgressView, { progress, t }),
3681
- selectedHost === void 0 ? connectingHost === void 0 ? React.createElement(
3682
- React.Fragment,
3683
- null,
3684
- React.createElement("p", { className: "dshRemoteHint" }, t("selectHostHint")),
3685
- React.createElement(
3686
- "footer",
3687
- { className: "dshRemoteAccountFooter" },
3688
- React.createElement("span", null, status?.host?.account ?? t("account")),
3689
- React.createElement("button", {
3789
+ React.createElement("div", { className: "dshRemoteFolderList" }, directory.entries.filter((entry) => !entry.hidden).length === 0 ? React.createElement("p", null, t("emptyDirectory")) : directory.entries.filter((entry) => !entry.hidden).map((entry) => React.createElement("button", {
3690
3790
  type: "button",
3691
- className: "dshRemoteAccountExit",
3791
+ key: entry.path,
3692
3792
  disabled: busy,
3693
- onClick: () => void logoutRemote()
3694
- }, t("exitRemoteAccount"))
3793
+ onClick: () => void browseDirectory(entry.path)
3794
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u25B1"), React.createElement("span", null, entry.name)))),
3795
+ directory.truncated ? React.createElement("small", null, t("directoryTruncated")) : null
3695
3796
  )
3696
- ) : null : React.createElement(
3697
- "section",
3698
- { className: "dshRemoteBrowser", "aria-label": t("chooseDirectory") },
3797
+ ) : React.createElement(
3798
+ React.Fragment,
3799
+ null,
3699
3800
  React.createElement(
3700
3801
  "div",
3701
- { className: "dshRemoteSectionHeading dshRemoteWorkspaceHeading" },
3702
- React.createElement("strong", null, t(addingWorkspace ? workspaceBackend === "codex" ? "addCodexWorkspace" : workspaceBackend === "cursor" ? "addCursorWorkspace" : workspaceBackend === "antigravity" ? "addAntigravityWorkspace" : "addRemoteWorkspace" : "existingWorkspaces")),
3703
- addingWorkspace ? React.createElement("button", {
3704
- type: "button",
3705
- className: "dshRemoteCancelWorkspace",
3706
- disabled: busy,
3707
- onClick: cancelAddingWorkspace
3708
- }, t("cancelAddWorkspace")) : React.createElement("button", {
3709
- type: "button",
3710
- className: "dshRemoteAddWorkspace",
3711
- disabled: busy,
3712
- title: t("addRemoteWorkspace"),
3713
- "aria-label": t("addRemoteWorkspace"),
3714
- onClick: () => startAddingWorkspace("harness")
3715
- }, React.createElement("svg", {
3716
- className: "dshRemoteAddWorkspaceIcon",
3717
- viewBox: "0 0 16 16",
3718
- "aria-hidden": !0,
3719
- focusable: !1
3720
- }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" })))
3721
- ),
3722
- addingWorkspace ? React.createElement(
3723
- "div",
3724
- { className: "dshRemoteFolderBrowser" },
3725
- directory === void 0 ? React.createElement("p", null, t("loadingDirectory")) : React.createElement(
3726
- React.Fragment,
3727
- null,
3728
- React.createElement(
3729
- "nav",
3730
- { className: "dshRemoteCrumbs", "aria-label": t("currentDirectory") },
3731
- directory.crumbs.map((crumb) => React.createElement("button", {
3732
- type: "button",
3733
- key: crumb.path,
3734
- disabled: busy || crumb.path === directory.path,
3735
- onClick: () => void browseDirectory(crumb.path)
3736
- }, crumb.path === directory.home ? "\u2302" : crumb.name))
3737
- ),
3738
- React.createElement("div", { className: "dshRemoteFolderList" }, directory.entries.filter((entry) => !entry.hidden).length === 0 ? React.createElement("p", null, t("emptyDirectory")) : directory.entries.filter((entry) => !entry.hidden).map((entry) => React.createElement("button", {
3739
- type: "button",
3740
- key: entry.path,
3741
- disabled: busy,
3742
- onClick: () => void browseDirectory(entry.path)
3743
- }, React.createElement("span", { "aria-hidden": !0 }, "\u25B1"), React.createElement("span", null, entry.name)))),
3744
- directory.truncated ? React.createElement("small", null, t("directoryTruncated")) : null
3745
- )
3746
- ) : React.createElement(
3747
- React.Fragment,
3748
- null,
3802
+ { className: "dshRemoteWorkspaceLists" },
3749
3803
  React.createElement(
3750
3804
  "div",
3751
- { className: "dshRemoteWorkspaceLists" },
3752
- React.createElement(
3753
- "div",
3754
- { id: workspaceListId, className: "dshRemoteDirectoryList" },
3755
- workspaces.length === 0 ? React.createElement("p", null, t("noRemoteWorkspaces")) : visibleWorkspaces.map((workspace) => React.createElement(
3756
- "button",
3757
- {
3758
- type: "button",
3759
- key: workspace.workspaceId,
3760
- disabled: busy,
3761
- className: workspaceBackend === "harness" && path === workspace.path ? "isSelected" : "",
3762
- "aria-pressed": workspaceBackend === "harness" && path === workspace.path,
3763
- onClick: () => {
3764
- setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
3765
- },
3766
- onDoubleClick: () => void openWorkspace({ backend: "harness", path: workspace.path })
3767
- },
3768
- React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3769
- React.createElement("span", null, workspace.title),
3770
- React.createElement("small", null, workspace.path)
3771
- )),
3772
- workspaces.length <= 3 || showAllWorkspaces ? null : React.createElement("button", {
3773
- type: "button",
3774
- className: "dshRemoteWorkspaceMore",
3775
- disabled: busy,
3776
- "aria-controls": workspaceListId,
3777
- "aria-label": t("showAllWorkspaces"),
3778
- onClick: () => setShowAllWorkspaces(!0)
3779
- }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3780
- )
3781
- ),
3782
- codexAvailable ? React.createElement(
3783
- "section",
3784
- { className: "dshRemoteCodexWorkspaceGroup" },
3785
- React.createElement(
3786
- "div",
3787
- {
3788
- id: codexWorkspaceHeadingId,
3789
- className: "dshRemoteWorkspaceSourceHeading"
3790
- },
3791
- React.createElement(
3792
- "span",
3793
- { className: "dshRemoteWorkspaceSourceText" },
3794
- React.createElement("strong", null, t("codexVirtualWorkspace"))
3795
- ),
3796
- codexAvailable ? React.createElement("button", {
3797
- type: "button",
3798
- className: "dshRemoteAddWorkspace",
3799
- disabled: busy,
3800
- title: t("addCodexWorkspace"),
3801
- "aria-label": t("addCodexWorkspace"),
3802
- onClick: () => startAddingWorkspace("codex")
3803
- }, React.createElement("svg", {
3804
- className: "dshRemoteAddWorkspaceIcon",
3805
- viewBox: "0 0 16 16",
3806
- "aria-hidden": !0,
3807
- focusable: !1
3808
- }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
3809
- ),
3810
- React.createElement("div", {
3811
- id: codexWorkspaceListId,
3812
- className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3813
- "aria-labelledby": codexWorkspaceHeadingId
3814
- }, visibleCodexWorkspaces.length === 0 ? React.createElement("p", null, t("noCodexWorkspaces")) : visibleCodexWorkspaces.map((workspace) => React.createElement(
3805
+ { id: workspaceListId, className: "dshRemoteDirectoryList" },
3806
+ workspaces.length === 0 ? React.createElement("p", null, t("noRemoteWorkspaces")) : visibleWorkspaces.map((workspace) => React.createElement(
3815
3807
  "button",
3816
3808
  {
3817
3809
  type: "button",
3818
3810
  key: workspace.workspaceId,
3819
3811
  disabled: busy,
3820
- className: workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3821
- "aria-pressed": workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId,
3812
+ className: workspaceBackend === "harness" && path === workspace.path ? "isSelected" : "",
3813
+ "aria-pressed": workspaceBackend === "harness" && path === workspace.path,
3822
3814
  onClick: () => {
3823
- setWorkspaceBackend("codex"), setCodexWorkspaceId(workspace.workspaceId), setCursorWorkspaceId(void 0), setPath(workspace.path);
3815
+ setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
3824
3816
  },
3825
- onDoubleClick: () => void openWorkspace({
3826
- backend: "codex",
3827
- path: workspace.path,
3828
- workspaceId: workspace.workspaceId
3829
- })
3817
+ onDoubleClick: () => void openWorkspace({ backend: "harness", path: workspace.path })
3830
3818
  },
3831
- React.createElement("img", { className: "dshRemoteWorkspaceIcon isGpt", src: gptWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3819
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3832
3820
  React.createElement("span", null, workspace.title),
3833
- React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3834
- ))),
3835
- codexWorkspaces.length <= 3 || showAllCodexWorkspaces ? null : React.createElement("button", {
3821
+ React.createElement("small", null, workspace.path)
3822
+ )),
3823
+ workspaces.length <= 3 || showAllWorkspaces ? null : React.createElement("button", {
3836
3824
  type: "button",
3837
3825
  className: "dshRemoteWorkspaceMore",
3838
3826
  disabled: busy,
3839
- "aria-controls": codexWorkspaceListId,
3840
- "aria-label": t("showAllCodexWorkspaces"),
3841
- onClick: () => setShowAllCodexWorkspaces(!0)
3827
+ "aria-controls": workspaceListId,
3828
+ "aria-label": t("showAllWorkspaces"),
3829
+ onClick: () => setShowAllWorkspaces(!0)
3842
3830
  }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3843
- ) : null,
3844
- cursorAvailable ? React.createElement(
3845
- "section",
3846
- { className: "dshRemoteCodexWorkspaceGroup" },
3831
+ )
3832
+ ),
3833
+ codexAvailable ? React.createElement(
3834
+ "section",
3835
+ { className: "dshRemoteCodexWorkspaceGroup" },
3836
+ React.createElement(
3837
+ "div",
3838
+ {
3839
+ id: codexWorkspaceHeadingId,
3840
+ className: "dshRemoteWorkspaceSourceHeading"
3841
+ },
3847
3842
  React.createElement(
3848
- "div",
3849
- {
3850
- id: cursorWorkspaceHeadingId,
3851
- className: "dshRemoteWorkspaceSourceHeading"
3852
- },
3853
- React.createElement(
3854
- "span",
3855
- { className: "dshRemoteWorkspaceSourceText" },
3856
- React.createElement("strong", null, t("cursorVirtualWorkspace"))
3857
- ),
3858
- cursorAvailable ? React.createElement("button", {
3859
- type: "button",
3860
- className: "dshRemoteAddWorkspace",
3861
- disabled: busy,
3862
- title: t("addCursorWorkspace"),
3863
- "aria-label": t("addCursorWorkspace"),
3864
- onClick: () => startAddingWorkspace("cursor")
3865
- }, React.createElement("svg", {
3866
- className: "dshRemoteAddWorkspaceIcon",
3867
- viewBox: "0 0 16 16",
3868
- "aria-hidden": !0,
3869
- focusable: !1
3870
- }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
3843
+ "span",
3844
+ { className: "dshRemoteWorkspaceSourceText" },
3845
+ React.createElement("strong", null, t("codexVirtualWorkspace"))
3871
3846
  ),
3872
- React.createElement("div", {
3873
- id: cursorWorkspaceListId,
3874
- className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3875
- "aria-labelledby": cursorWorkspaceHeadingId
3876
- }, visibleCursorWorkspaces.length === 0 ? React.createElement("p", null, t("noCursorWorkspaces")) : visibleCursorWorkspaces.map((workspace) => React.createElement(
3877
- "button",
3878
- {
3879
- type: "button",
3880
- key: workspace.workspaceId,
3881
- disabled: busy,
3882
- className: workspaceBackend === "cursor" && cursorWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3883
- "aria-pressed": workspaceBackend === "cursor" && cursorWorkspaceId === workspace.workspaceId,
3884
- onClick: () => {
3885
- setWorkspaceBackend("cursor"), setCursorWorkspaceId(workspace.workspaceId), setCodexWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPath(workspace.path);
3886
- },
3887
- onDoubleClick: () => void openWorkspace({
3888
- backend: "cursor",
3889
- path: workspace.path,
3890
- workspaceId: workspace.workspaceId
3891
- })
3847
+ codexAvailable ? React.createElement("button", {
3848
+ type: "button",
3849
+ className: "dshRemoteAddWorkspace",
3850
+ disabled: busy,
3851
+ title: t("addCodexWorkspace"),
3852
+ "aria-label": t("addCodexWorkspace"),
3853
+ onClick: () => startAddingWorkspace("codex")
3854
+ }, React.createElement("svg", {
3855
+ className: "dshRemoteAddWorkspaceIcon",
3856
+ viewBox: "0 0 16 16",
3857
+ "aria-hidden": !0,
3858
+ focusable: !1
3859
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
3860
+ ),
3861
+ React.createElement("div", {
3862
+ id: codexWorkspaceListId,
3863
+ className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3864
+ "aria-labelledby": codexWorkspaceHeadingId
3865
+ }, visibleCodexWorkspaces.length === 0 ? React.createElement("p", null, t("noCodexWorkspaces")) : visibleCodexWorkspaces.map((workspace) => React.createElement(
3866
+ "button",
3867
+ {
3868
+ type: "button",
3869
+ key: workspace.workspaceId,
3870
+ disabled: busy,
3871
+ className: workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3872
+ "aria-pressed": workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId,
3873
+ onClick: () => {
3874
+ setWorkspaceBackend("codex"), setCodexWorkspaceId(workspace.workspaceId), setCursorWorkspaceId(void 0), setPath(workspace.path);
3892
3875
  },
3893
- React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3894
- React.createElement("span", null, workspace.title),
3895
- React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3896
- ))),
3897
- cursorWorkspaces.length <= 3 || showAllCursorWorkspaces ? null : React.createElement("button", {
3876
+ onDoubleClick: () => void openWorkspace({
3877
+ backend: "codex",
3878
+ path: workspace.path,
3879
+ workspaceId: workspace.workspaceId
3880
+ })
3881
+ },
3882
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon isGpt", src: gptWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3883
+ React.createElement("span", null, workspace.title),
3884
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3885
+ ))),
3886
+ codexWorkspaces.length <= 3 || showAllCodexWorkspaces ? null : React.createElement("button", {
3887
+ type: "button",
3888
+ className: "dshRemoteWorkspaceMore",
3889
+ disabled: busy,
3890
+ "aria-controls": codexWorkspaceListId,
3891
+ "aria-label": t("showAllCodexWorkspaces"),
3892
+ onClick: () => setShowAllCodexWorkspaces(!0)
3893
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3894
+ ) : null,
3895
+ cursorAvailable ? React.createElement(
3896
+ "section",
3897
+ { className: "dshRemoteCodexWorkspaceGroup" },
3898
+ React.createElement(
3899
+ "div",
3900
+ {
3901
+ id: cursorWorkspaceHeadingId,
3902
+ className: "dshRemoteWorkspaceSourceHeading"
3903
+ },
3904
+ React.createElement(
3905
+ "span",
3906
+ { className: "dshRemoteWorkspaceSourceText" },
3907
+ React.createElement("strong", null, t("cursorVirtualWorkspace"))
3908
+ ),
3909
+ cursorAvailable ? React.createElement("button", {
3898
3910
  type: "button",
3899
- className: "dshRemoteWorkspaceMore",
3911
+ className: "dshRemoteAddWorkspace",
3900
3912
  disabled: busy,
3901
- "aria-controls": cursorWorkspaceListId,
3902
- "aria-label": t("showAllCursorWorkspaces"),
3903
- onClick: () => setShowAllCursorWorkspaces(!0)
3904
- }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3905
- ) : null,
3906
- antigravityAvailable ? React.createElement(
3907
- "section",
3908
- { className: "dshRemoteCodexWorkspaceGroup" },
3913
+ title: t("addCursorWorkspace"),
3914
+ "aria-label": t("addCursorWorkspace"),
3915
+ onClick: () => startAddingWorkspace("cursor")
3916
+ }, React.createElement("svg", {
3917
+ className: "dshRemoteAddWorkspaceIcon",
3918
+ viewBox: "0 0 16 16",
3919
+ "aria-hidden": !0,
3920
+ focusable: !1
3921
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
3922
+ ),
3923
+ React.createElement("div", {
3924
+ id: cursorWorkspaceListId,
3925
+ className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3926
+ "aria-labelledby": cursorWorkspaceHeadingId
3927
+ }, visibleCursorWorkspaces.length === 0 ? React.createElement("p", null, t("noCursorWorkspaces")) : visibleCursorWorkspaces.map((workspace) => React.createElement(
3928
+ "button",
3929
+ {
3930
+ type: "button",
3931
+ key: workspace.workspaceId,
3932
+ disabled: busy,
3933
+ className: workspaceBackend === "cursor" && cursorWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3934
+ "aria-pressed": workspaceBackend === "cursor" && cursorWorkspaceId === workspace.workspaceId,
3935
+ onClick: () => {
3936
+ setWorkspaceBackend("cursor"), setCursorWorkspaceId(workspace.workspaceId), setCodexWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setPath(workspace.path);
3937
+ },
3938
+ onDoubleClick: () => void openWorkspace({
3939
+ backend: "cursor",
3940
+ path: workspace.path,
3941
+ workspaceId: workspace.workspaceId
3942
+ })
3943
+ },
3944
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3945
+ React.createElement("span", null, workspace.title),
3946
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3947
+ ))),
3948
+ cursorWorkspaces.length <= 3 || showAllCursorWorkspaces ? null : React.createElement("button", {
3949
+ type: "button",
3950
+ className: "dshRemoteWorkspaceMore",
3951
+ disabled: busy,
3952
+ "aria-controls": cursorWorkspaceListId,
3953
+ "aria-label": t("showAllCursorWorkspaces"),
3954
+ onClick: () => setShowAllCursorWorkspaces(!0)
3955
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3956
+ ) : null,
3957
+ antigravityAvailable ? React.createElement(
3958
+ "section",
3959
+ { className: "dshRemoteCodexWorkspaceGroup" },
3960
+ React.createElement(
3961
+ "div",
3962
+ {
3963
+ id: antigravityWorkspaceHeadingId,
3964
+ className: "dshRemoteWorkspaceSourceHeading"
3965
+ },
3909
3966
  React.createElement(
3910
- "div",
3911
- {
3912
- id: antigravityWorkspaceHeadingId,
3913
- className: "dshRemoteWorkspaceSourceHeading"
3967
+ "span",
3968
+ { className: "dshRemoteWorkspaceSourceText" },
3969
+ React.createElement("strong", null, t("antigravityVirtualWorkspace"))
3970
+ ),
3971
+ antigravityAvailable ? React.createElement("button", {
3972
+ type: "button",
3973
+ className: "dshRemoteAddWorkspace",
3974
+ disabled: busy,
3975
+ title: t("addAntigravityWorkspace"),
3976
+ "aria-label": t("addAntigravityWorkspace"),
3977
+ onClick: () => startAddingWorkspace("antigravity")
3978
+ }, React.createElement("svg", {
3979
+ className: "dshRemoteAddWorkspaceIcon",
3980
+ viewBox: "0 0 16 16",
3981
+ "aria-hidden": !0,
3982
+ focusable: !1
3983
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
3984
+ ),
3985
+ React.createElement("div", {
3986
+ id: antigravityWorkspaceListId,
3987
+ className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3988
+ "aria-labelledby": antigravityWorkspaceHeadingId
3989
+ }, visibleAntigravityWorkspaces.length === 0 ? React.createElement("p", null, t("noAntigravityWorkspaces")) : visibleAntigravityWorkspaces.map((workspace) => React.createElement(
3990
+ "button",
3991
+ {
3992
+ type: "button",
3993
+ key: workspace.workspaceId,
3994
+ disabled: busy,
3995
+ className: workspaceBackend === "antigravity" && antigravityWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3996
+ "aria-pressed": workspaceBackend === "antigravity" && antigravityWorkspaceId === workspace.workspaceId,
3997
+ onClick: () => {
3998
+ setWorkspaceBackend("antigravity"), setAntigravityWorkspaceId(workspace.workspaceId), setPiWorkspaceId(void 0), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
3914
3999
  },
3915
- React.createElement(
3916
- "span",
3917
- { className: "dshRemoteWorkspaceSourceText" },
3918
- React.createElement("strong", null, t("antigravityVirtualWorkspace"))
3919
- ),
3920
- antigravityAvailable ? React.createElement("button", {
3921
- type: "button",
3922
- className: "dshRemoteAddWorkspace",
3923
- disabled: busy,
3924
- title: t("addAntigravityWorkspace"),
3925
- "aria-label": t("addAntigravityWorkspace"),
3926
- onClick: () => startAddingWorkspace("antigravity")
3927
- }, React.createElement("svg", {
3928
- className: "dshRemoteAddWorkspaceIcon",
3929
- viewBox: "0 0 16 16",
3930
- "aria-hidden": !0,
3931
- focusable: !1
3932
- }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
4000
+ onDoubleClick: () => void openWorkspace({
4001
+ backend: "antigravity",
4002
+ path: workspace.path,
4003
+ workspaceId: workspace.workspaceId
4004
+ })
4005
+ },
4006
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
4007
+ React.createElement("span", null, workspace.title),
4008
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
4009
+ ))),
4010
+ antigravityWorkspaces.length <= 3 || showAllAntigravityWorkspaces ? null : React.createElement("button", {
4011
+ type: "button",
4012
+ className: "dshRemoteWorkspaceMore",
4013
+ disabled: busy,
4014
+ "aria-controls": antigravityWorkspaceListId,
4015
+ "aria-label": t("showAllAntigravityWorkspaces"),
4016
+ onClick: () => setShowAllAntigravityWorkspaces(!0)
4017
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
4018
+ ) : null,
4019
+ piAvailable ? React.createElement(
4020
+ "section",
4021
+ { className: "dshRemoteCodexWorkspaceGroup" },
4022
+ React.createElement(
4023
+ "div",
4024
+ {
4025
+ id: piWorkspaceHeadingId,
4026
+ className: "dshRemoteWorkspaceSourceHeading"
4027
+ },
4028
+ React.createElement(
4029
+ "span",
4030
+ { className: "dshRemoteWorkspaceSourceText" },
4031
+ React.createElement("strong", null, t("piVirtualWorkspace"))
3933
4032
  ),
3934
- React.createElement("div", {
3935
- id: antigravityWorkspaceListId,
3936
- className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
3937
- "aria-labelledby": antigravityWorkspaceHeadingId
3938
- }, visibleAntigravityWorkspaces.length === 0 ? React.createElement("p", null, t("noAntigravityWorkspaces")) : visibleAntigravityWorkspaces.map((workspace) => React.createElement(
3939
- "button",
3940
- {
3941
- type: "button",
3942
- key: workspace.workspaceId,
3943
- disabled: busy,
3944
- className: workspaceBackend === "antigravity" && antigravityWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3945
- "aria-pressed": workspaceBackend === "antigravity" && antigravityWorkspaceId === workspace.workspaceId,
3946
- onClick: () => {
3947
- setWorkspaceBackend("antigravity"), setAntigravityWorkspaceId(workspace.workspaceId), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
3948
- },
3949
- onDoubleClick: () => void openWorkspace({
3950
- backend: "antigravity",
3951
- path: workspace.path,
3952
- workspaceId: workspace.workspaceId
3953
- })
4033
+ piAvailable ? React.createElement("button", {
4034
+ type: "button",
4035
+ className: "dshRemoteAddWorkspace",
4036
+ disabled: busy,
4037
+ title: t("addPiWorkspace"),
4038
+ "aria-label": t("addPiWorkspace"),
4039
+ onClick: () => startAddingWorkspace("pi")
4040
+ }, React.createElement("svg", {
4041
+ className: "dshRemoteAddWorkspaceIcon",
4042
+ viewBox: "0 0 16 16",
4043
+ "aria-hidden": !0,
4044
+ focusable: !1
4045
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" }))) : null
4046
+ ),
4047
+ React.createElement("div", {
4048
+ id: piWorkspaceListId,
4049
+ className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
4050
+ "aria-labelledby": piWorkspaceHeadingId
4051
+ }, visiblePiWorkspaces.length === 0 ? React.createElement("p", null, t("noPiWorkspaces")) : visiblePiWorkspaces.map((workspace) => React.createElement(
4052
+ "button",
4053
+ {
4054
+ type: "button",
4055
+ key: workspace.workspaceId,
4056
+ disabled: busy,
4057
+ className: workspaceBackend === "pi" && piWorkspaceId === workspace.workspaceId ? "isSelected" : "",
4058
+ "aria-pressed": workspaceBackend === "pi" && piWorkspaceId === workspace.workspaceId,
4059
+ onClick: () => {
4060
+ setWorkspaceBackend("pi"), setPiWorkspaceId(workspace.workspaceId), setAntigravityWorkspaceId(void 0), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
3954
4061
  },
3955
- React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
3956
- React.createElement("span", null, workspace.title),
3957
- React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3958
- ))),
3959
- antigravityWorkspaces.length <= 3 || showAllAntigravityWorkspaces ? null : React.createElement("button", {
4062
+ onDoubleClick: () => void openWorkspace({
4063
+ backend: "pi",
4064
+ path: workspace.path,
4065
+ workspaceId: workspace.workspaceId
4066
+ })
4067
+ },
4068
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
4069
+ React.createElement("span", null, workspace.title),
4070
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
4071
+ ))),
4072
+ piWorkspaces.length <= 3 || showAllPiWorkspaces ? null : React.createElement("button", {
4073
+ type: "button",
4074
+ className: "dshRemoteWorkspaceMore",
4075
+ disabled: busy,
4076
+ "aria-controls": piWorkspaceListId,
4077
+ "aria-label": t("showAllPiWorkspaces"),
4078
+ onClick: () => setShowAllPiWorkspaces(!0)
4079
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
4080
+ ) : null,
4081
+ opencodeAvailable ? React.createElement(
4082
+ "section",
4083
+ { className: "dshRemoteCodexWorkspaceGroup" },
4084
+ React.createElement(
4085
+ "div",
4086
+ {
4087
+ id: opencodeWorkspaceHeadingId,
4088
+ className: "dshRemoteWorkspaceSourceHeading"
4089
+ },
4090
+ React.createElement("span", { className: "dshRemoteWorkspaceSourceText" }, React.createElement("strong", null, t("opencodeVirtualWorkspace"))),
4091
+ React.createElement("button", {
3960
4092
  type: "button",
3961
- className: "dshRemoteWorkspaceMore",
4093
+ className: "dshRemoteAddWorkspace",
3962
4094
  disabled: busy,
3963
- "aria-controls": antigravityWorkspaceListId,
3964
- "aria-label": t("showAllAntigravityWorkspaces"),
3965
- onClick: () => setShowAllAntigravityWorkspaces(!0)
3966
- }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
3967
- ) : null
3968
- ),
3969
- React.createElement(
3970
- "footer",
3971
- { className: "dshRemoteOpenBar" },
3972
- React.createElement("div", null, React.createElement("span", null, t("currentDirectory")), React.createElement("strong", null, path || "\u2014")),
3973
- React.createElement("button", {
4095
+ title: t("addOpencodeWorkspace"),
4096
+ "aria-label": t("addOpencodeWorkspace"),
4097
+ onClick: () => startAddingWorkspace("opencode")
4098
+ }, React.createElement("svg", {
4099
+ className: "dshRemoteAddWorkspaceIcon",
4100
+ viewBox: "0 0 16 16",
4101
+ "aria-hidden": !0,
4102
+ focusable: !1
4103
+ }, React.createElement("path", { d: "M8 3v10M3 8h10", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round" })))
4104
+ ),
4105
+ React.createElement("div", {
4106
+ id: opencodeWorkspaceListId,
4107
+ className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList",
4108
+ "aria-labelledby": opencodeWorkspaceHeadingId
4109
+ }, visibleOpencodeWorkspaces.length === 0 ? React.createElement("p", null, t("noOpencodeWorkspaces")) : visibleOpencodeWorkspaces.map((workspace) => React.createElement(
4110
+ "button",
4111
+ {
4112
+ type: "button",
4113
+ key: workspace.workspaceId,
4114
+ disabled: busy,
4115
+ className: workspaceBackend === "opencode" && opencodeWorkspaceId === workspace.workspaceId ? "isSelected" : "",
4116
+ "aria-pressed": workspaceBackend === "opencode" && opencodeWorkspaceId === workspace.workspaceId,
4117
+ onClick: () => {
4118
+ setWorkspaceBackend("opencode"), setOpencodeWorkspaceId(workspace.workspaceId), setPiWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setPath(workspace.path);
4119
+ },
4120
+ onDoubleClick: () => void openWorkspace({
4121
+ backend: "opencode",
4122
+ path: workspace.path,
4123
+ workspaceId: workspace.workspaceId
4124
+ })
4125
+ },
4126
+ React.createElement("img", { className: "dshRemoteWorkspaceIcon", src: deepSeekWorkspaceIcon, alt: "", "aria-hidden": !0 }),
4127
+ React.createElement("span", null, workspace.title),
4128
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
4129
+ ))),
4130
+ opencodeWorkspaces.length <= 3 || showAllOpencodeWorkspaces ? null : React.createElement("button", {
3974
4131
  type: "button",
3975
- disabled: busy || path.trim() === "" || !addingWorkspace && workspaceBackend === "codex" && codexWorkspaceId === void 0 || !addingWorkspace && workspaceBackend === "cursor" && cursorWorkspaceId === void 0 && path === "" || !addingWorkspace && workspaceBackend === "antigravity" && antigravityWorkspaceId === void 0 && path === "",
3976
- onClick: () => void openWorkspace()
3977
- }, t(busy ? "openingWorkspace" : addingWorkspace ? "confirmAddWorkspace" : "openWorkspace"))
3978
- )
4132
+ className: "dshRemoteWorkspaceMore",
4133
+ disabled: busy,
4134
+ "aria-controls": opencodeWorkspaceListId,
4135
+ "aria-label": t("showAllOpencodeWorkspaces"),
4136
+ onClick: () => setShowAllOpencodeWorkspaces(!0)
4137
+ }, React.createElement("span", { "aria-hidden": !0 }, "\u2026"))
4138
+ ) : null
4139
+ ),
4140
+ React.createElement(
4141
+ "footer",
4142
+ { className: "dshRemoteOpenBar" },
4143
+ React.createElement("div", null, React.createElement("span", null, t("currentDirectory")), React.createElement("strong", null, path || "\u2014")),
4144
+ React.createElement("button", {
4145
+ type: "button",
4146
+ disabled: busy || path.trim() === "" || !addingWorkspace && workspaceBackend === "codex" && codexWorkspaceId === void 0 || !addingWorkspace && workspaceBackend === "cursor" && cursorWorkspaceId === void 0 && path === "" || !addingWorkspace && workspaceBackend === "antigravity" && antigravityWorkspaceId === void 0 && path === "" || !addingWorkspace && workspaceBackend === "pi" && piWorkspaceId === void 0 && path === "" || !addingWorkspace && workspaceBackend === "opencode" && opencodeWorkspaceId === void 0 && path === "",
4147
+ onClick: () => void openWorkspace()
4148
+ }, t(busy ? "openingWorkspace" : addingWorkspace ? "confirmAddWorkspace" : "openWorkspace"))
3979
4149
  )
3980
4150
  )
3981
- ),
3982
- notice === void 0 ? null : React.createElement("p", { className: "dshRemoteNotice", role: "status" }, notice),
3983
- error === void 0 ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
3984
- )
3985
- )) : null
3986
- );
4151
+ )
4152
+ ),
4153
+ notice === void 0 ? null : React.createElement("p", { className: "dshRemoteNotice", role: "status" }, notice),
4154
+ error === void 0 ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
4155
+ )
4156
+ )) : null
4157
+ );
4158
+ }
4159
+ return RemoteWorkspaceAction;
4160
+ }
4161
+
4162
+ // src/control-route.ts
4163
+ var CONTROL_RPC_PREFIX = "/ds-harness-remote", STATUS_STREAM_ENDPOINT = "status.events", STATUS_STREAM_PATH = `${CONTROL_RPC_PREFIX}/${STATUS_STREAM_ENDPOINT}`;
4164
+
4165
+ // src/plugin-route-client.ts
4166
+ var PluginRouteFailure = class extends Error {
4167
+ constructor(code, message) {
4168
+ super(message);
4169
+ this.code = code;
4170
+ }
4171
+ };
4172
+ function createPluginRouteFetch(original, baseUrl, options = {}) {
4173
+ let routeUrl = new URL("api/bot", baseUrl), nextRpcId = 0, control = async (method, payload, signal) => {
4174
+ let rpcId = `plugin-route-${++nextRpcId}`, response = await original(new URL(`${CONTROL_RPC_PREFIX.slice(1)}/${method}`, baseUrl), {
4175
+ method: "POST",
4176
+ credentials: "same-origin",
4177
+ headers: { "content-type": "application/json" },
4178
+ body: JSON.stringify({ type: "client-request", rpcId, method, payload }),
4179
+ signal
4180
+ });
4181
+ if (!response.ok) throw new PluginRouteFailure("remote-plugin/control-unavailable", `The local Remote control request failed (HTTP ${response.status}). Reload the Remote plugin.`);
4182
+ let envelope = await response.json();
4183
+ if (!isRecord(envelope) || envelope.type !== "server-response" || envelope.rpcId !== rpcId || !isRecord(envelope.result))
4184
+ throw new PluginRouteFailure("remote-plugin/control-invalid", "The local Remote control response is invalid. Reload the Remote plugin.");
4185
+ if (envelope.result.ok !== !0) {
4186
+ let error = isRecord(envelope.result.error) ? envelope.result.error : void 0, code = (isRecord(error?.details) ? error.details : void 0)?.remoteCode ?? error?.code;
4187
+ throw code === "FEATURE_NOT_SUPPORTED" || code === "METHOD_NOT_FOUND" ? new PluginRouteFailure("remote-plugin/host-unsupported", "The selected Host does not support plugin route forwarding. Update and reload Remote on the Host, then reconnect.") : code === "REMOTE_NOT_CONNECTED" || code === "TRANSPORT_CLOSED" ? new PluginRouteFailure("remote-plugin/disconnected", "The Remote Host is disconnected. Reconnect to load DS Bot.") : code === "INVALID_MESSAGE" ? new PluginRouteFailure("remote-plugin/operation-not-allowed", "This DS Bot operation is not allowed over Remote. Use the Host locally.") : new PluginRouteFailure("remote-plugin/control-rejected", "The Remote plugin route request was rejected by the control channel.");
4188
+ }
4189
+ return envelope.result.value;
4190
+ };
4191
+ return async (input, init) => {
4192
+ let requestUrl = new URL(input instanceof Request ? input.url : String(input), baseUrl);
4193
+ if ((init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase() !== "POST" || requestUrl.href !== routeUrl.href) return original(input, init);
4194
+ let lifetime = (init?.signal !== void 0 ? init.signal ?? void 0 : input instanceof Request ? input.signal : void 0) ?? AbortSignal.timeout(45e3);
4195
+ try {
4196
+ lifetime.throwIfAborted();
4197
+ let status = await control("status", {}, AbortSignal.any([lifetime, AbortSignal.timeout(1e4)]));
4198
+ if (lifetime.throwIfAborted(), !isRecord(status)) throw new PluginRouteFailure("remote-plugin/authority-unavailable", "The Remote plugin route authority is unavailable.");
4199
+ if (status.mode === "local") return original(input, init);
4200
+ if (status.mode !== "remote") throw new PluginRouteFailure("remote-plugin/authority-unavailable", "The Remote plugin route authority is unavailable.");
4201
+ if (status.connected !== !0) throw new PluginRouteFailure("remote-plugin/disconnected", "The Remote Host is disconnected. Reconnect to load DS Bot.");
4202
+ if (!isRecord(status.remoteFeatures) || status.remoteFeatures.pluginRoute !== !0) throw new PluginRouteFailure("remote-plugin/host-unsupported", "The selected Host does not support plugin route forwarding. Update and reload Remote on the Host, then reconnect.");
4203
+ if (status.backend !== void 0 && status.backend !== "harness") throw new PluginRouteFailure("remote-plugin/backend-unsupported", "DS Bot requires the Remote Harness catalog. Select a Harness workspace on this Host.");
4204
+ let body = await (input instanceof Request ? new Request(input, init) : new Request(requestUrl, init)).clone().json();
4205
+ if (!isRecord(body)) throw new Error("The plugin route body must be a JSON object.");
4206
+ let result = await control("plugin.route", { route: "api/bot", body }, lifetime);
4207
+ if (!isRecord(result) || !Number.isInteger(result.status) || result.status < 200 || result.status > 599)
4208
+ throw new Error("The plugin route response is invalid.");
4209
+ let statusCode = result.status;
4210
+ if (statusCode === 404) throw new PluginRouteFailure("remote-plugin/bot-not-loaded", "The Host has no DS Bot route. Enable ds-bot in the same DSH instance/profile as the connected Host.");
4211
+ if (statusCode === 503) throw new PluginRouteFailure("remote-plugin/host-carrier-unavailable", "The Host plugin route carrier is unavailable. Update and reload Remote on the Host.");
4212
+ if (statusCode >= 200 && statusCode < 300 && options.beforeResponse !== void 0)
4213
+ try {
4214
+ await waitWithSignal(options.beforeResponse(status, body, result.json, lifetime), lifetime);
4215
+ } catch {
4216
+ throw lifetime.throwIfAborted(), new PluginRouteFailure("remote-plugin/catalog-unavailable", "The Remote Harness Session catalog is not ready. Reconnect before loading DS Bot.");
4217
+ }
4218
+ return lifetime.throwIfAborted(), new Response([204, 205, 304].includes(statusCode) ? null : JSON.stringify(result.json ?? null), {
4219
+ status: statusCode,
4220
+ headers: { "content-type": "application/json" }
4221
+ });
4222
+ } catch (error) {
4223
+ return lifetime.throwIfAborted(), new Response(JSON.stringify({
4224
+ ok: !1,
4225
+ error: {
4226
+ code: error instanceof PluginRouteFailure ? error.code : "remote-plugin/unavailable",
4227
+ message: error instanceof PluginRouteFailure ? error.message : "The Remote plugin route is unavailable.",
4228
+ details: {}
4229
+ }
4230
+ }), { status: 200, headers: { "content-type": "application/json" } });
4231
+ }
4232
+ };
4233
+ }
4234
+ function createPluginRouteCatalogGuard(readSessions) {
4235
+ return async (_status, body, json, signal) => {
4236
+ if (!isRecord(json) || json.ok !== !0 || !isRecord(json.value)) return;
4237
+ let required = botSessionIds(body.endpoint, json.value);
4238
+ if (required.size === 0) return;
4239
+ let sessions = await readSessions(), containsSessions = () => {
4240
+ let snapshot = sessions.list.getSnapshot(), known = new Set(snapshot.ids);
4241
+ return snapshot.phase === "ready" && [...required].every((id) => known.has(id));
4242
+ };
4243
+ for (let attempt = 0; attempt < 2; attempt++) {
4244
+ if (signal.throwIfAborted(), containsSessions()) return;
4245
+ if (sessions.refresh === void 0) break;
4246
+ await sessions.refresh();
4247
+ }
4248
+ if (signal.throwIfAborted(), !containsSessions()) throw new Error("The Remote Session catalog does not contain the published Sessions.");
4249
+ };
4250
+ }
4251
+ function botSessionIds(endpoint, value) {
4252
+ let ids = /* @__PURE__ */ new Set(), add = (id) => {
4253
+ if (id != null) {
4254
+ if (typeof id != "string" || id.length === 0) throw new Error("Invalid Bot Session identity.");
4255
+ ids.add(id);
4256
+ }
4257
+ }, addArray = (input) => {
4258
+ if (input !== void 0) {
4259
+ if (!Array.isArray(input)) throw new Error("Invalid Bot Session identities.");
4260
+ input.forEach(add);
4261
+ }
4262
+ }, bot = (input) => {
4263
+ if (!isRecord(input)) throw new Error("Invalid Bot catalog entry.");
4264
+ add(input.id), add(input.sessionId), addArray(input.parts), Array.isArray(input.segments) && input.segments.forEach((segment) => {
4265
+ if (!isRecord(segment)) throw new Error("Invalid Bot Session segment.");
4266
+ add(segment.sessionId);
4267
+ });
4268
+ }, room = (input) => {
4269
+ if (!isRecord(input)) throw new Error("Invalid Bot room entry.");
4270
+ add(input.id), addArray(input.parts), isRecord(input.sessions) && Object.values(input.sessions).forEach(add);
4271
+ }, agent = (input) => {
4272
+ if (!isRecord(input)) throw new Error("Invalid Bot agent entry.");
4273
+ addArray(input.sessions);
4274
+ }, roster = () => {
4275
+ for (let [key, visit] of [["bots", bot], ["rooms", room], ["agents", agent]])
4276
+ if (value[key] !== void 0) {
4277
+ if (!Array.isArray(value[key])) throw new Error("Invalid Bot roster.");
4278
+ value[key].forEach(visit);
4279
+ }
4280
+ };
4281
+ switch (endpoint) {
4282
+ case "state":
4283
+ case "delete-bot":
4284
+ case "delete-room":
4285
+ case "set-main":
4286
+ case "remove-agent":
4287
+ roster();
4288
+ break;
4289
+ case "create-bot":
4290
+ case "duplicate-bot":
4291
+ case "update-bot":
4292
+ bot(value);
4293
+ break;
4294
+ case "create-room":
4295
+ room(value);
4296
+ break;
4297
+ case "update-room":
4298
+ room(value.room);
4299
+ break;
4300
+ case "add-agent":
4301
+ agent(value);
4302
+ break;
4303
+ case "agent-session":
4304
+ case "agent-adopt":
4305
+ add(value.sessionId);
4306
+ break;
4307
+ case "set-flags":
4308
+ Array.isArray(value.sessions) ? agent(value) : Array.isArray(value.members) ? room(value) : bot(value);
4309
+ break;
4310
+ }
4311
+ return ids;
4312
+ }
4313
+ function waitWithSignal(pending, signal) {
4314
+ return new Promise((resolve, reject) => {
4315
+ let onAbort = () => reject(signal.reason);
4316
+ signal.addEventListener("abort", onAbort, { once: !0 }), signal.aborted && onAbort(), pending.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
4317
+ });
4318
+ }
4319
+ function isRecord(value) {
4320
+ return typeof value == "object" && value !== null && !Array.isArray(value);
4321
+ }
4322
+
4323
+ // src/remote-file-content-provider.ts
4324
+ function shouldUseRemoteFileViewer(status) {
4325
+ return status.mode === "remote" && status.remoteFeatures?.fileViewer === !0;
4326
+ }
4327
+ var REMOTE_FILE_SAVE_AS_MAX_BYTES = 100 * 1024 * 1024, REMOTE_FILE_FAST_SAVE_AS_MAX_BYTES = 1024 * 1024 * 1024;
4328
+ function shouldAllowRemoteFileSaveAs(status) {
4329
+ return shouldUseRemoteFileViewer(status) && (status.transport === "LAN" || status.transport === "P2P" || status.transport === "TURN");
4330
+ }
4331
+ function remoteFileSaveAsMaxBytes(status) {
4332
+ return status.transport === "LAN" || status.transport === "P2P" ? REMOTE_FILE_FAST_SAVE_AS_MAX_BYTES : REMOTE_FILE_SAVE_AS_MAX_BYTES;
4333
+ }
4334
+ function createRemoteFileContentProvider(call, options = {}) {
4335
+ return {
4336
+ id: "dsh-remote-files",
4337
+ priority: 1e4,
4338
+ supports: () => !0,
4339
+ saveAsAllowed: () => ({
4340
+ allowed: currentSaveAsAllowed(options.saveAsAllowed),
4341
+ maxBytes: currentSaveAsMaxBytes(options.saveAsMaxBytes)
4342
+ }),
4343
+ async stat(locator, signal) {
4344
+ let value = await call("fileviewer.stat", { path: locator }, signal);
4345
+ if (value.exists)
4346
+ return {
4347
+ name: value.name,
4348
+ size: value.isDirectory ? 0 : value.size,
4349
+ mime: value.mime,
4350
+ mtimeMs: value.mtimeMs,
4351
+ isDirectory: value.isDirectory
4352
+ };
4353
+ },
4354
+ async read(locator, request) {
4355
+ if (!Number.isInteger(request.offset) || request.offset < 0) throw new Error("A non-negative integer offset is required.");
4356
+ if (!Number.isInteger(request.length) || request.length <= 0) throw new Error("A positive integer length is required.");
4357
+ let chunks = [], received = 0;
4358
+ for (; received < request.length; ) {
4359
+ request.signal.throwIfAborted();
4360
+ let length = Math.min(524288, request.length - received), offset = request.offset + received, range = await call("fileviewer.readRange", { path: locator, offset, length }, request.signal);
4361
+ if (range.offset !== offset) throw new Error("The Remote Host returned a mismatched file range.");
4362
+ let bytes = decodeBase64(range.data);
4363
+ if (bytes.byteLength > length) throw new Error("The Remote Host returned more file bytes than requested.");
4364
+ if (chunks.push(bytes), received += bytes.byteLength, range.eof || bytes.byteLength === 0) break;
4365
+ }
4366
+ let merged = new Uint8Array(received), cursor = 0;
4367
+ for (let chunk of chunks)
4368
+ merged.set(chunk, cursor), cursor += chunk.byteLength;
4369
+ return merged;
4370
+ },
4371
+ async list(locator, signal) {
4372
+ return (await call("fileviewer.list", { path: locator }, signal)).entries.map((entry) => ({
4373
+ locator: entry.path,
4374
+ name: entry.name,
4375
+ size: entry.isDirectory ? 0 : entry.size ?? 0,
4376
+ mtimeMs: entry.mtimeMs,
4377
+ isDirectory: entry.isDirectory
4378
+ }));
4379
+ }
4380
+ };
4381
+ }
4382
+ function currentSaveAsAllowed(value) {
4383
+ return typeof value == "function" ? value() : value === !0;
4384
+ }
4385
+ function currentSaveAsMaxBytes(value) {
4386
+ return typeof value == "function" ? value() : value ?? REMOTE_FILE_SAVE_AS_MAX_BYTES;
4387
+ }
4388
+ function decodeBase64(value) {
4389
+ let binary = atob(value), bytes = new Uint8Array(binary.length);
4390
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
4391
+ return bytes;
4392
+ }
4393
+
4394
+ // src/status-stream.ts
4395
+ function parseStatus(data) {
4396
+ if (typeof data == "string")
4397
+ try {
4398
+ let parsed = JSON.parse(data);
4399
+ return parsed === null || typeof parsed != "object" ? void 0 : parsed;
4400
+ } catch {
4401
+ return;
4402
+ }
4403
+ }
4404
+ function createStatusFeed(options) {
4405
+ let listeners = /* @__PURE__ */ new Set(), pollIntervalMs = options.pollIntervalMs ?? 1500, openTimeoutMs = options.openTimeoutMs ?? 4e3, createSource = options.createSource ?? ((url) => new EventSource(url)), status, source, openTimer, pollTimer, publish = (next) => {
4406
+ status = next;
4407
+ for (let listener of [...listeners]) listener(next);
4408
+ }, teardown = () => {
4409
+ openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0), pollTimer !== void 0 && (clearInterval(pollTimer), pollTimer = void 0), source?.close(), source = void 0;
4410
+ }, poll = () => {
4411
+ options.readStatus().then((next) => {
4412
+ pollTimer !== void 0 && publish(next);
4413
+ }).catch(() => {
4414
+ });
4415
+ }, fallbackToPolling = (reason) => {
4416
+ pollTimer !== void 0 || listeners.size === 0 || (openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0), source?.close(), source = void 0, options.onFallback?.(reason), poll(), pollTimer = setInterval(poll, pollIntervalMs));
4417
+ }, openStream = () => {
4418
+ let opened;
4419
+ try {
4420
+ opened = createSource(options.url);
4421
+ } catch {
4422
+ fallbackToPolling("unsupported");
4423
+ return;
4424
+ }
4425
+ source = opened;
4426
+ let received = !1;
4427
+ openTimer = setTimeout(() => {
4428
+ received || fallbackToPolling("silent");
4429
+ }, openTimeoutMs), opened.onmessage = (event) => {
4430
+ received = !0, openTimer !== void 0 && (clearTimeout(openTimer), openTimer = void 0);
4431
+ let next = parseStatus(event.data);
4432
+ next !== void 0 && publish(next);
4433
+ }, opened.onerror = () => {
4434
+ opened.readyState === 2 && fallbackToPolling("unavailable");
4435
+ };
4436
+ };
4437
+ return {
4438
+ getSnapshot: () => status,
4439
+ subscribe: (listener) => (listeners.add(listener), status !== void 0 && listener(status), listeners.size === 1 && openStream(), () => {
4440
+ listeners.delete(listener), listeners.size === 0 && teardown();
4441
+ }),
4442
+ close: () => {
4443
+ listeners.clear(), teardown();
3987
4444
  }
4445
+ };
4446
+ }
4447
+
4448
+ // src/client.ts
4449
+ var clientModuleId = "ds-harness-remote", controlRouteBackoffStepsMs = [1e3, 2e3, 5e3, 1e4, 3e4], ControlRouteUnavailableError = class extends Error {
4450
+ constructor(message) {
4451
+ super(message), this.name = "ControlRouteUnavailableError";
4452
+ }
4453
+ }, originalPluginFetch = window.fetch, readyPluginSessions, pluginSessions = new Promise((resolve) => {
4454
+ readyPluginSessions = resolve;
4455
+ }), pluginRouteFetch = typeof originalPluginFetch == "function" && typeof document < "u" ? createPluginRouteFetch(originalPluginFetch.bind(window), document.baseURI, {
4456
+ beforeResponse: createPluginRouteCatalogGuard(() => pluginSessions)
4457
+ }) : void 0;
4458
+ pluginRouteFetch !== void 0 && (window.fetch = pluginRouteFetch);
4459
+ function controlRouteUnavailableStatus() {
4460
+ return {
4461
+ mode: "local",
4462
+ available: !1,
4463
+ controlUnavailable: !0,
4464
+ connected: !1,
4465
+ transport: "Disconnected",
4466
+ remoteFeatures: { commandList: !1, fileViewer: !1, terminal: !1, codex: !1, pluginRoute: !1, cursor: !1, antigravity: !1, pi: !1, opencode: !1 },
4467
+ hostAuthorizationAvailable: !1
4468
+ };
4469
+ }
4470
+ window.__ModuleLoader__.load({
4471
+ id: clientModuleId,
4472
+ factory: (require2) => {
4473
+ let module = { exports: {} }, React = require2("react"), RemotePluginOptions = createRemotePluginOptions(React), RemoteWorkspaceAction = createRemoteWorkspaceAction(React), RemoteProgressView = createRemoteProgressView(React), RemoteSessionHeaderAction = createRemoteSessionHeaderAction(React), inject = [
4474
+ "connection",
4475
+ "slots",
4476
+ "locale",
4477
+ "workspaces",
4478
+ "sessions"
4479
+ ];
3988
4480
  function RemoteModeAction(props) {
3989
4481
  let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [hostRegistrationCode, setHostRegistrationCode] = React.useState(""), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [busy, setBusy] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), [error, setError] = React.useState(void 0), [supported, setSupported] = React.useState(!0), refresh = async () => {
3990
4482
  let [nextStatus, nextDevices] = await Promise.all([
@@ -4133,278 +4625,6 @@ Minimum version required to store current data is: ` + bestVersion + `.
4133
4625
  ) : null
4134
4626
  ) : null;
4135
4627
  }
4136
- function RemoteSessionHeaderAction(props) {
4137
- let { t } = props, status = React.useSyncExternalStore(
4138
- props.statusFeed.subscribe,
4139
- props.statusFeed.getSnapshot,
4140
- props.statusFeed.getSnapshot
4141
- ), [busy, setBusy] = React.useState(!1), [routeOpen, setRouteOpen] = React.useState(!1);
4142
- if (React.useEffect(() => {
4143
- if (status?.mode === "remote")
4144
- return hideLocalSessionActions();
4145
- }, [status?.mode]), React.useEffect(() => (document.documentElement.classList.toggle(
4146
- "dshRemoteCodexTargetActive",
4147
- status?.mode === "remote" && status.backend === "codex"
4148
- ), document.documentElement.classList.toggle(
4149
- "dshRemoteCursorTargetActive",
4150
- status?.mode === "remote" && status.backend === "cursor"
4151
- ), document.documentElement.classList.toggle(
4152
- "dshRemoteAntigravityTargetActive",
4153
- status?.mode === "remote" && status.backend === "antigravity"
4154
- ), () => {
4155
- document.documentElement.classList.remove("dshRemoteCodexTargetActive"), document.documentElement.classList.remove("dshRemoteCursorTargetActive"), document.documentElement.classList.remove("dshRemoteAntigravityTargetActive");
4156
- }), [status?.mode, status?.backend]), React.useEffect(() => {
4157
- if (!routeOpen) return;
4158
- let closeOnEscape = (event) => {
4159
- event.key === "Escape" && setRouteOpen(!1);
4160
- };
4161
- return document.addEventListener("keydown", closeOnEscape), () => document.removeEventListener("keydown", closeOnEscape);
4162
- }, [routeOpen]), status?.mode !== "remote") return null;
4163
- let exit = async () => {
4164
- setBusy(!0);
4165
- try {
4166
- await props.control("mode.set", { mode: "local" }), window.location.reload();
4167
- } finally {
4168
- setBusy(!1);
4169
- }
4170
- }, transport = status.network?.webRtc?.mode ?? status.transport ?? "Disconnected", networkLabel = t(transport === "P2P" ? "remoteNetworkP2p" : transport === "TURN" ? "remoteNetworkTurn" : transport === "Relay" ? "remoteNetworkRelay" : transport === "LAN" ? "remoteNetworkLan" : "remoteNetworkOffline"), networkOnline = status.connected === !0 && transport !== "Disconnected", routeVia = t(transport === "P2P" ? "connectionRouteP2p" : transport === "TURN" ? "connectionRouteTurn" : transport === "Relay" ? "connectionRouteRelay" : "connectionRouteLan"), routeViaDetail = t(transport === "P2P" ? "connectionRouteP2pDetail" : transport === "TURN" ? "connectionRouteTurnDetail" : transport === "Relay" ? "connectionRouteRelayDetail" : "connectionRouteLanDetail"), network = status.network, webRtc = network?.webRtc, controlStateLabel = network?.controlChannelState === "connecting" ? t("controlStateConnecting") : network?.controlChannelState === "open" ? t("controlStateOpen") : network?.controlChannelState === "closing" ? t("controlStateClosing") : t("controlStateClosed"), detailValue = (value) => value === void 0 || value === "" ? t("notProvided") : String(value), candidateLabel = (value) => value === "host" ? t("candidateHost") : value === "srflx" ? t("candidateSrflx") : value === "prflx" ? t("candidatePrflx") : value === "relay" ? t("candidateRelay") : detailValue(value), fact = (label, value, mono = !1) => React.createElement(
4171
- "div",
4172
- null,
4173
- React.createElement("dt", null, label),
4174
- React.createElement("dd", { className: mono ? "isMono" : void 0, title: mono ? value : void 0 }, value)
4175
- );
4176
- return React.createElement(
4177
- "div",
4178
- { className: "dshRemoteSessionHeader", role: "status" },
4179
- React.createElement("svg", {
4180
- viewBox: "0 0 24 24",
4181
- fill: "none",
4182
- stroke: "currentColor",
4183
- strokeWidth: 1.7,
4184
- strokeLinecap: "round",
4185
- strokeLinejoin: "round",
4186
- "aria-hidden": !0
4187
- }, React.createElement("rect", { x: 3, y: 4, width: 18, height: 13, rx: 2 }), React.createElement("path", { d: "M8 21h8M12 17v4" })),
4188
- React.createElement("span", { className: "dshRemoteSessionTarget" }, t("remoteModeLabel", { name: status.target?.name ?? t("host") })),
4189
- React.createElement("button", {
4190
- type: "button",
4191
- className: `dshRemoteNetwork${networkOnline ? " isOnline" : " isOffline"}`,
4192
- title: networkLabel,
4193
- disabled: !networkOnline,
4194
- "aria-haspopup": "dialog",
4195
- "aria-expanded": routeOpen,
4196
- onClick: () => setRouteOpen((value) => !value)
4197
- }, React.createElement("i", { "aria-hidden": !0 }), networkLabel),
4198
- networkOnline ? React.createElement("span", { className: "dshRemoteEncrypted" }, t("remoteLinkEncrypted")) : null,
4199
- React.createElement("button", { type: "button", className: "dshRemoteHeaderExitLink", disabled: busy, onClick: () => void exit() }, t("exitRemote")),
4200
- routeOpen ? React.createElement("div", {
4201
- className: "dshRemoteRouteBackdrop",
4202
- role: "presentation",
4203
- onMouseDown: (event) => {
4204
- event.target === event.currentTarget && setRouteOpen(!1);
4205
- }
4206
- }, React.createElement(
4207
- "section",
4208
- {
4209
- className: "dshRemoteRoutePanel",
4210
- role: "dialog",
4211
- "aria-label": t("connectionRouteTitle")
4212
- },
4213
- React.createElement(
4214
- "header",
4215
- null,
4216
- React.createElement("strong", null, t("connectionRouteTitle")),
4217
- React.createElement("button", { type: "button", "aria-label": t("close"), onClick: () => setRouteOpen(!1) }, "\xD7")
4218
- ),
4219
- React.createElement(
4220
- "ol",
4221
- null,
4222
- React.createElement(
4223
- "li",
4224
- null,
4225
- React.createElement("small", null, t("connectionRouteFrom")),
4226
- React.createElement("strong", null, network?.local.name ?? t("connectionRouteCurrentDevice")),
4227
- network === void 0 ? null : React.createElement("span", null, `${network.local.platform} \xB7 ${shortDeviceId(network.local.deviceId)}`)
4228
- ),
4229
- React.createElement(
4230
- "li",
4231
- null,
4232
- React.createElement("small", null, t("connectionRouteVia")),
4233
- React.createElement("strong", null, routeVia),
4234
- React.createElement("span", null, routeViaDetail)
4235
- ),
4236
- React.createElement(
4237
- "li",
4238
- null,
4239
- React.createElement("small", null, t("connectionRouteTo")),
4240
- React.createElement("strong", null, network?.remote.name ?? status.target?.name ?? t("host")),
4241
- React.createElement("span", null, network === void 0 ? t("connectionRouteHost") : `${network.remote.platform} \xB7 ${shortDeviceId(network.remote.deviceId)}`)
4242
- )
4243
- ),
4244
- network === void 0 ? null : React.createElement(
4245
- "section",
4246
- { className: "dshRemoteRouteSection" },
4247
- React.createElement("h3", null, t("connectionDetailsConnection")),
4248
- React.createElement(
4249
- "dl",
4250
- null,
4251
- fact(t("connectionId"), detailValue(network.connectionId), !0),
4252
- fact(t("connectedAt"), network.connectedAt === void 0 ? t("notProvided") : formatLocalTime(network.connectedAt)),
4253
- fact(t("preferredTransports"), network.preferredTransports.map((value) => transportLabel(value, t)).join(" \u2192 ")),
4254
- fact(t("controlChannel"), `WebSocket \xB7 ${controlStateLabel}`),
4255
- fact(t("controlAddress"), network.controlChannelUrl, !0)
4256
- )
4257
- ),
4258
- webRtc === void 0 ? null : React.createElement(
4259
- "section",
4260
- { className: "dshRemoteRouteSection" },
4261
- React.createElement("h3", null, t("connectionDetailsWebRtc")),
4262
- React.createElement(
4263
- "dl",
4264
- null,
4265
- fact(t("peerState"), `${webRtc.connectionState} \xB7 ICE ${webRtc.iceConnectionState}`),
4266
- fact(t("dataChannel"), detailValue(webRtc.dataChannelState)),
4267
- fact(t("localCandidate"), candidateLabel(webRtc.localCandidateType)),
4268
- fact(t("remoteCandidate"), candidateLabel(webRtc.remoteCandidateType)),
4269
- fact(t("localAddress"), detailValue(webRtc.localAddress), !0),
4270
- fact(t("remoteAddress"), detailValue(webRtc.remoteAddress), !0),
4271
- fact(t("networkProtocol"), detailValue(webRtc.protocol?.toUpperCase())),
4272
- fact(t("relayProtocol"), detailValue(webRtc.relayProtocol?.toUpperCase())),
4273
- fact(t("roundTripTime"), webRtc.currentRoundTripTimeMs === void 0 ? t("notProvided") : `${webRtc.currentRoundTripTimeMs.toLocaleString()} ms`),
4274
- fact(t("availableBitrate"), webRtc.availableOutgoingBitrate === void 0 ? t("notProvided") : formatBitrate(webRtc.availableOutgoingBitrate)),
4275
- fact(t("bytesSent"), webRtc.bytesSent === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesSent)),
4276
- fact(t("bytesReceived"), webRtc.bytesReceived === void 0 ? t("notProvided") : formatByteSize(webRtc.bytesReceived))
4277
- )
4278
- ),
4279
- React.createElement("p", null, t("connectionRouteEncrypted"))
4280
- )) : null
4281
- );
4282
- }
4283
- function hideLocalSessionActions() {
4284
- let selector = 'button,a,[role="button"]', hiddenAttribute = "data-dsh-remote-hidden-action", localAction = /(?:open|打开).{0,12}vs\s*code|vs\s*code.{0,12}(?:open|打开)|session\s*logs?|download.{0,12}session\s*logs?|会话日志|下载.{0,8}日志/i, inspect = (root) => {
4285
- let candidates = root instanceof Element && root.matches(selector) ? [root, ...Array.from(root.querySelectorAll(selector))] : Array.from(root.querySelectorAll(selector));
4286
- for (let candidate of candidates) {
4287
- if (candidate.closest(".dshRemoteSessionHeader") !== null) continue;
4288
- let label = [
4289
- candidate.getAttribute("aria-label"),
4290
- candidate.getAttribute("title"),
4291
- candidate.getAttribute("data-tooltip"),
4292
- candidate.textContent
4293
- ].filter(Boolean).join(" ");
4294
- localAction.test(label) && candidate.setAttribute(hiddenAttribute, "");
4295
- }
4296
- };
4297
- inspect(document.body);
4298
- let observer = new MutationObserver((records) => {
4299
- for (let record of records) {
4300
- record.type === "attributes" && inspect(record.target);
4301
- for (let node of Array.from(record.addedNodes))
4302
- node instanceof Element && inspect(node);
4303
- }
4304
- });
4305
- return observer.observe(document.body, {
4306
- subtree: !0,
4307
- childList: !0,
4308
- attributes: !0,
4309
- attributeFilter: ["aria-label", "title", "data-tooltip"]
4310
- }), () => {
4311
- observer.disconnect(), document.querySelectorAll(`[${hiddenAttribute}]`).forEach((element) => element.removeAttribute(hiddenAttribute));
4312
- };
4313
- }
4314
- function installStyle() {
4315
- let style = document.createElement("style");
4316
- return style.dataset.plugin = clientModuleId, style.dataset.pluginCss = "dsh-remote", style.textContent = [
4317
- 'html.dshRemoteTargetActive button[aria-label="\u6DFB\u52A0\u5DE5\u4F5C\u533A"],html.dshRemoteTargetActive button[aria-label="Add workspace"]{display:none!important}',
4318
- 'html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="\u6307\u4EE4"],html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="Commands"]{display:none!important}',
4319
- "[data-dsh-remote-hidden-action]{display:none!important}",
4320
- // The 0.1.6 right sidebar occupies the same shell header area as the
4321
- // remote status strip. Hide the strip while that sidebar is expanded;
4322
- // the sidebar itself remains the active context for terminal/files.
4323
- ":has([data-sidebar-right-open]) .dshRemoteSessionHeader{display:none!important}",
4324
- // TerminalRecovery renders a retry action in the conversation header.
4325
- // A failed remote terminal is reported when its tab is opened/closed;
4326
- // keeping this background recovery action out of the top-left header
4327
- // avoids overlapping the session controls.
4328
- '[title^="\u6062\u590D\u7EC8\u7AEF\u5931\u8D25"],[title^="Terminal recovery failed"]{display:none!important}',
4329
- ".dshRemoteTerminalUnavailable{box-sizing:border-box;margin:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font-size:13px;line-height:1.5}",
4330
- ".dshRemoteModeButton{min-height:36px;border:0;background:transparent;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;padding:0 10px;border-radius:8px}.dshRemoteModeButton:is(button){cursor:pointer}",
4331
- ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
4332
- // Keep additive footer actions in reading order above the Settings seat.
4333
- '[class*="_footArea"]:has(.dshRemoteSidebarEntry){flex-direction:column!important;align-items:stretch;gap:0}[class*="_footerActions"]:has(.dshRemoteSidebarEntry){display:flex!important;flex-direction:column;align-items:stretch}[class*="_footerActions"]:has(.dshRemoteSidebarEntry.isRail){align-items:center}',
4334
- '[class*="_footerActions"]:has(.dshRemoteSidebarEntry.isWide) .bt-return{justify-content:flex-start}',
4335
- // Bot mode seats its account beside Connect plugins. Keep that row intact
4336
- // and let Remote span a separate row underneath it.
4337
- '[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide){display:grid!important;grid-template-columns:36px minmax(0,1fr);align-items:center;gap:8px 9px}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_footerActions"]{display:contents!important}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_footerActions"]>div:not(.dshRemoteSidebarEntry){display:contents!important}',
4338
- '[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide) .bt-connect-wrap{grid-column:2;grid-row:1}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide)>[class*="_settingsArea"]{grid-column:1;grid-row:1;width:36px!important}[class*="_footArea"]:has(.bt-connect-wrap):has(.dshRemoteSidebarEntry.isWide) .dshRemoteSidebarEntry.isWide{display:block!important;grid-column:1/-1;grid-row:2;margin:0}',
4339
- '[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide){grid-template-columns:36px minmax(0,1fr) 36px}[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide) .bt-foot-account{grid-column:1;grid-row:1}[class*="_footArea"]:has(.bt-connect-wrap):has(.bt-foot-account):has(.dshRemoteSidebarEntry.isWide)>[class*="_settingsArea"]{grid-column:3}',
4340
- ".dshRemoteSidebarEntry{box-sizing:border-box;flex:none;width:36px;min-width:36px;display:block}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:36px;height:36px;min-height:36px;justify-content:center;gap:0;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isWide{width:100%;min-width:0;height:36px;margin:4px 0}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{width:100%;min-width:0;justify-content:flex-start;gap:8px;padding:0 14px;border-radius:8px;font:inherit;font-size:14px;line-height:20px;text-align:start}.dshRemoteSidebarLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteSidebarEntry.isRail{height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{margin:8px 0 10px}.dshRemoteSidebarEntry.isActive .dshRemoteComputerIcon{color:var(--dsw-alias-brand-primary)}.dshRemoteSidebarEntry .dshRemoteModeButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteSidebarEntry .dshRemoteModeButton:disabled{opacity:.45;cursor:default}",
4341
- ".dshRemoteComputerIcon{box-sizing:border-box;width:18px;height:18px;flex:0 0 18px;color:var(--dsw-alias-label-secondary)}",
4342
- ".dshRemoteSidebarEntry.isWide{position:relative}.dshRemoteSidebarEntry.isWide.isActive .dshRemoteModeButton{padding-inline-end:64px}.dshRemoteExitLink{position:absolute;inset-block-start:0;inset-inline-end:8px;min-width:44px;height:36px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);padding:0 6px;font:inherit;font-size:12px;line-height:20px;white-space:nowrap;cursor:pointer}.dshRemoteExitLink:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default}",
4343
- '.dshRemoteSessionHeader{position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteSessionTarget{min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteHeaderExitLink{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:3px 2px;font:inherit;text-decoration:none;cursor:pointer}.dshRemoteHeaderExitLink:hover{text-decoration:underline;color:var(--dsw-alias-label-primary)}.dshRemoteHeaderExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}.dshRemoteNetwork:focus-visible,.dshRemoteHeaderExitLink:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
4344
- ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:auto;right:104px;transform:none;max-width:calc(100vw - 124px)}}",
4345
- ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
4346
- ".dshRemotePage{width:min(720px,100%);max-height:min(760px,calc(100vh - 40px));display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;overflow:hidden;animation:dshRemotePageIn .18s cubic-bezier(.25,1,.5,1)}",
4347
- ".dshRemotePageHeader{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:14px 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemotePageIntro{min-width:0;flex:1}.dshRemotePageHeader strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:18px;line-height:1.4}.dshRemotePageHeader p{min-width:0;max-width:70ch;margin:3px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.dshRemotePageActions{flex:0 0 auto;display:flex;align-items:center;gap:4px}.dshRemotePageActions>button{height:40px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:inherit;line-height:1;cursor:pointer}.dshRemotePageActions>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemotePageActions>button:disabled{opacity:.45;cursor:default}.dshRemotePageBack,.dshRemotePageRefresh{min-width:48px;padding:0 10px;font:inherit;font-size:13px}.dshRemotePageBack{color:var(--dsw-alias-label-secondary)!important}.dshRemotePageClose{width:40px;padding:0;font-size:24px}",
4348
- ".dshRemotePageBody{padding:24px;overflow:auto;display:flex;flex-direction:column;gap:24px}.dshRemotePageBody button{font:inherit;color:inherit}",
4349
- ".dshRemotePageTitleRow{display:flex;align-items:center;gap:10px;min-width:0}.dshRemotePageTitleRow>strong{min-width:0;flex:0 1 auto}.dshRemoteStarLink{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400;text-decoration:none}.dshRemoteStarLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-offset:3px}.dshRemoteStarLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;border-radius:3px}",
4350
- ".dshRemoteSectionHeading{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:10px}.dshRemoteSectionTitle{min-width:0;display:flex;align-items:center;gap:10px}.dshRemoteSectionTitle>strong{font-size:14px}.dshRemoteSectionActions{display:flex;align-items:center;gap:14px}.dshRemoteSectionActions>button{border:0;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;padding:5px 0;font-size:12px}.dshRemoteSectionActions>button:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}",
4351
- ".dshRemoteSectionTitle{flex:1}.dshRemoteSectionTitle>.dshRemoteConnectedMenu{margin-left:auto}",
4352
- '.dshRemoteAcpSetting{display:block!important;width:100%;padding:0}.dshRemoteAcpSetting>summary{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;cursor:pointer;list-style:none}.dshRemoteAcpSetting>summary::-webkit-details-marker{display:none}.dshRemoteAcpSetting>summary::after{content:"\u2304";color:var(--dsw-alias-label-secondary);transition:transform .18s ease-out}.dshRemoteAcpSetting[open]>summary::after{transform:rotate(180deg)}.dshRemoteAcpSummaryText{min-width:0}.dshRemoteAcpSummaryText strong{display:block}.dshRemoteAcpSummaryText p{margin:4px 0 0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.4}.dshRemoteAcpCheckLink{grid-column:2;grid-row:1;color:var(--dsw-alias-brand-primary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpCheckLink:hover{color:var(--dsw-alias-label-primary)}.dshRemoteAcpCheckResult{grid-column:3;grid-row:1;font-size:11px;line-height:1.4;white-space:nowrap}.dshRemoteAcpCheckResult.isPassed{color:var(--dsw-alias-state-success-primary)}.dshRemoteAcpCheckResult.isFailed{color:var(--dsw-alias-state-danger-primary)}.dshRemoteAcpList{display:flex;flex-direction:column;gap:0;margin-top:12px;padding-top:0;border-top:0}.dshRemoteAcpList>.dshRemoteAuthorizationSetting{display:grid;width:100%;grid-template-columns:minmax(0,1fr) auto auto auto auto;align-items:center;column-gap:18px;line-height:1.4}.dshRemoteAcpList>.dshRemoteAuthorizationSetting>span:first-child{min-width:0;line-height:1.4}.dshRemoteAcpList>.dshRemoteAuthorizationSetting>input{grid-column:4;grid-row:1}',
4353
- ".dshRemoteAcpAddLink{align-self:flex-start;margin-top:12px;color:var(--dsw-alias-brand-primary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpAddForm{display:grid;grid-template-columns:minmax(100px,.8fr) minmax(140px,1fr) minmax(100px,1fr) auto;gap:8px;margin-top:12px}.dshRemoteAcpAddForm input{min-width:0;height:34px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:inherit;padding:0 10px}.dshRemoteAcpAddForm button{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);padding:0 12px;cursor:pointer;font:inherit;font-size:12px}.dshRemoteAcpAddForm button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteAcpRemoveLink{grid-column:3;grid-row:1;color:var(--dsw-alias-label-secondary);font-size:12px;text-decoration:underline;text-underline-offset:3px}.dshRemoteAcpRemoveLink:hover{color:var(--dsw-alias-state-danger-primary)}",
4354
- ".dshRemoteAcpCheckResult.isPassed,.dshRemoteAcpCheckResult.isFailed{color:var(--dsw-alias-label-secondary)}",
4355
- ".dshRemoteAcpList>.dshRemoteAuthorizationSetting{grid-template-columns:minmax(0,1fr) 190px 40px 56px;column-gap:18px}.dshRemoteAcpCheckCell{grid-column:2;display:flex;align-items:center;gap:10px;min-width:0}.dshRemoteAcpCheckLink,.dshRemoteAcpRemoveLink{justify-self:start}.dshRemoteAcpCheckResult{position:static}",
4356
- ".dshRemoteAcpCheckLink.isPassed{color:var(--dsw-alias-state-success-primary)}.dshRemoteAcpCheckLink.isFailed{color:var(--dsw-alias-state-danger-primary)}.dshRemoteAcpCheckLink.isChecking{color:var(--dsw-alias-label-secondary)}",
4357
- ".dshRemoteCancelWorkspace{min-height:36px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:6px 0;cursor:pointer}.dshRemoteCancelWorkspace:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteCancelWorkspace:disabled{opacity:.5;cursor:default}",
4358
- '.dshRemoteHostList{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2);max-height:296px;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable}.dshRemoteHostList.isCollapsed{max-height:none;overflow-y:visible}.dshRemoteHostList>button{min-height:58px;flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:16px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:10px 4px;cursor:pointer}.dshRemoteHostList>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button:disabled{opacity:.5;cursor:default}.dshRemoteHostList>button[aria-current="true"]{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button>span{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostList>button strong{font-size:14px;font-weight:500}.dshRemoteHostList small{color:var(--dsw-alias-label-secondary);font-size:12px}',
4359
- '.dshRemoteConnectedMenu{position:relative;flex:0 0 auto;margin-right:4px}.dshRemoteConnectedCount{appearance:none;display:inline-flex;align-items:center;justify-content:center;height:22px;border:0;border-radius:999px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);box-shadow:0 1px 2px rgba(0,0,0,.18),0 0 0 1px rgba(255,255,255,.04) inset;padding:0 10px;font:inherit;font-size:11px;font-weight:500;line-height:17px;white-space:nowrap;cursor:default}.dshRemoteConnectedCount.isOnline{color:var(--dsw-alias-state-success-primary)}.dshRemoteConnectedCount.isInteractive{cursor:pointer}.dshRemoteConnectedCount.isInteractive:hover{filter:brightness(1.08)}.dshRemoteConnectedCount:disabled{opacity:1;cursor:default}.dshRemoteConnectedCount:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteConnectedPanel{position:absolute;top:calc(100% + 8px);right:0;z-index:4;width:min(320px,calc(100vw - 48px));max-height:min(280px,40vh);overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2);box-shadow:0 10px 28px rgba(0,0,0,.28);padding:10px 12px}.dshRemoteConnectedPanelTitle{display:block;margin:0 0 6px;color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600}.dshRemoteClientList{display:flex;flex-direction:column}.dshRemoteClientRow{min-height:44px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteClientRow:last-child{border-bottom:0}.dshRemoteClientRow>span{min-width:0;display:flex;flex-direction:column;gap:2px}.dshRemoteClientRow strong{font-size:13px;font-weight:500}.dshRemoteClientRow small{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteClientOnline{display:inline-flex;align-items:center;gap:6px;color:var(--dsw-alias-state-success-primary)!important}.dshRemoteClientOnline::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}',
4360
- ".dshRemoteConnectedCount{height:auto;border-radius:0;background:transparent;box-shadow:none;padding:0 4px;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 45%,transparent);text-underline-offset:3px}.dshRemoteConnectedCount.isInteractive:hover{filter:none;text-decoration-color:currentColor}.dshRemoteConnectedCount:focus-visible{outline-offset:3px;border-radius:3px}",
4361
- '.dshRemoteProgress{display:flex;flex-direction:column;gap:8px;margin:12px 0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}.dshRemoteProgressHeader{display:flex;align-items:center;justify-content:space-between;gap:12px}.dshRemoteProgressHeader strong{font-size:13px;font-weight:600}.dshRemoteProgressHeader span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteProgressBar{height:6px;overflow:hidden;border-radius:999px;background:var(--dsw-alias-bg-layer-3)}.dshRemoteProgressBar>span{display:block;width:100%;height:100%;border-radius:inherit;background:var(--dsw-alias-brand-primary);transform-origin:left center;transition:transform .22s ease-out}[dir="rtl"] .dshRemoteProgressBar>span{transform-origin:right center}.dshRemoteProgress p{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45}.dshRemoteProgressRoute{font-weight:500}.dshRemoteProgressRoute .isActive{color:var(--dsw-alias-state-success-primary);font-weight:700}.dshRemoteProgressRouteArrow{color:var(--dsw-alias-label-tertiary)}@media(prefers-reduced-motion:reduce){.dshRemoteProgressBar>span{transition:none}}',
4362
- '.dshRemoteBrowser{display:flex;flex-direction:column}.dshRemoteCrumbs{display:flex;align-items:center;gap:4px;overflow:auto;padding:2px 0 10px}.dshRemoteCrumbs>button{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 7px;border-radius:6px;cursor:pointer}.dshRemoteCrumbs>button:not(:last-child)::after{content:" /";color:var(--dsw-alias-label-tertiary)}.dshRemoteCrumbs>button:disabled{color:var(--dsw-alias-label-primary);font-weight:600}',
4363
- ".dshRemoteWorkspaceLists{overflow:visible}",
4364
- ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child,.dshRemoteDirectoryList>button>.dshRemoteWorkspaceIcon{grid-row:1/3}.dshRemoteWorkspaceIcon{box-sizing:border-box;width:22px;height:22px;align-self:center;object-fit:contain}.dshRemoteWorkspaceIcon.isGpt{border-radius:6px}.dshRemoteDirectoryList>button>span:not(:first-child),.dshRemoteDirectoryList>button>small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary)}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
4365
- ".dshRemoteAddWorkspace{box-sizing:border-box;width:40px;height:40px;display:inline-grid;place-items:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;cursor:pointer}.dshRemoteAddWorkspace:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteAddWorkspace:disabled{opacity:.5;cursor:default}.dshRemoteAddWorkspaceIcon{width:20px;height:20px}.dshRemoteCodexWorkspaceGroup{margin-top:16px}.dshRemoteWorkspaceSourceHeading{min-height:44px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 4px 7px}.dshRemoteWorkspaceSourceText{min-width:0;display:flex;flex-direction:column;gap:2px}.dshRemoteWorkspaceSourceText>strong{font-size:13px}.dshRemoteWorkspaceSourceText>small{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteCodexWorkspaceList{min-height:0}.dshRemoteDirectoryList>.dshRemoteWorkspaceMore,.dshRemoteCodexWorkspaceGroup>.dshRemoteWorkspaceMore{box-sizing:border-box;width:100%;min-height:48px;display:flex;align-items:center;justify-content:center;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);padding:8px 4px;text-align:center;font-size:16px;cursor:pointer}.dshRemoteWorkspaceMore>span{display:block;line-height:1;transform:translateY(-2px)}.dshRemoteWorkspaceMore:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:transparent}.dshRemoteWorkspaceMore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.dshRemoteWorkspaceMore:disabled{opacity:.5;cursor:default}",
4366
- ".dshRemotePreviewAction,.dshRemotePreviewForm{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}.dshRemotePreviewForm input{width:90px;color:inherit;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);padding:6px}.dshRemotePreviewForm [role=alert]{max-width:360px;white-space:normal}.dshRemoteDevelopmentSettings{width:100%;margin:16px 0}.dshRemoteDevelopmentSettings .dshRemotePathField{display:flex;flex-direction:column;gap:6px;margin:8px 0}.dshRemoteDevelopmentSettings .dshRemotePathField>label{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteDevelopmentSettings .dshRemotePortsRow{display:flex;gap:8px;align-items:stretch;width:100%}.dshRemoteDevelopmentSettings .dshRemotePortsRow>input{box-sizing:border-box;width:100%;flex:1;min-width:0;height:34px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}.dshRemoteDevelopmentSettings button{min-height:34px;color:inherit;background:var(--dsw-alias-bg-layer-1);border:.5px solid var(--dsw-alias-border-l2);border-radius:8px;padding:5px 14px;white-space:nowrap;font-size:13px;line-height:1.5}.dshRemoteAcpAddForm>label{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteAcpAddForm>label>input{box-sizing:border-box;width:100%;height:34px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);padding:0 12px;font:inherit;font-size:13px;line-height:1.5}",
4367
- ".dshRemoteFolderBrowser{margin-top:14px}.dshRemoteFolderBrowser>p,.dshRemoteFolderList>p{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}.dshRemoteFolderList{max-height:260px;overflow:auto;border-block:1px solid var(--dsw-alias-border-l2)}.dshRemoteFolderList>button{width:100%;min-height:42px;display:flex;align-items:center;gap:9px;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:7px 6px;text-align:left;cursor:pointer}.dshRemoteFolderList>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteFolderBrowser>small{display:block;margin-top:8px;color:var(--dsw-alias-state-warn-label)}",
4368
- ".dshRemotePathField{display:flex;flex-direction:column;gap:6px;margin-top:20px}.dshRemotePathField>span{font-size:13px;font-weight:600}.dshRemotePathField>input{min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit}.dshRemotePathField>small{color:var(--dsw-alias-label-secondary)}",
4369
- ".dshRemoteOpenBar{position:sticky;bottom:-96px;display:flex;align-items:center;justify-content:space-between;gap:20px;margin-top:20px;padding:14px 0;background:var(--dsw-alias-bg-layer-1);border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteOpenBar>div{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteOpenBar span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteOpenBar strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.dshRemoteOpenBar>button,.dshRemoteEnable>button{min-height:40px;flex:0 0 auto;border:0;border-radius:8px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);padding:8px 16px;cursor:pointer}.dshRemoteOpenBar>button:disabled,.dshRemoteEnable>button:disabled{opacity:.5;cursor:default}",
4370
- ".dshRemoteEnable{box-sizing:border-box;width:min(440px,100%);max-width:100%;min-height:388px;margin:0 auto;display:flex;flex-direction:column;align-items:stretch;gap:10px}.dshRemoteEnable p{margin:0;color:var(--dsw-alias-label-secondary);line-height:1.5}",
4371
- '.dshRemoteLoginTabs{width:min(440px,100%);display:flex;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteLoginTabs>button{position:relative;min-height:38px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:6px 14px;font:inherit;font-size:13px;cursor:pointer}.dshRemoteLoginTabs>button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.dshRemoteLoginTabs>button.isActive{color:var(--dsw-alias-label-primary);font-weight:600}.dshRemoteLoginTabs>button.isActive::after{content:"";position:absolute;right:12px;bottom:-1px;left:12px;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-brand-primary)}.dshRemoteLoginTabs>button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px;border-radius:6px}',
4372
- ".dshRemoteClientLogin{width:min(440px,100%);display:flex;flex-direction:column;gap:8px}.dshRemoteClientLogin input{min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit}.dshRemoteClientLogin button{align-self:flex-start;min-height:40px;border:0;border-radius:8px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);padding:8px 16px;cursor:pointer}",
4373
- ".dshRemoteQrLogin{width:min(440px,100%);display:flex;flex-direction:column;align-items:center;gap:8px;padding:6px 0 2px;text-align:center}.dshRemoteQrLogin img,.dshRemoteQrPlaceholder{box-sizing:border-box;width:200px;height:200px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:#fff;padding:8px}.dshRemoteQrOpen{display:flex;flex-direction:column;align-items:center;gap:5px;color:var(--dsw-alias-label-secondary);font-size:12px;text-decoration:none}.dshRemoteQrOpen:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteQrOpen:hover img{border-color:var(--dsw-alias-label-dimmed)}.dshRemoteQrOpen:focus-visible{border-radius:12px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.dshRemoteQrPlaceholder{display:flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-secondary)}.dshRemoteQrLogin>strong{font-size:14px}.dshRemoteQrLogin>p{max-width:48ch;margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.dshRemoteQrLogin>.dshRemoteServiceAddress{margin-top:2px;color:var(--dsw-alias-label-tertiary)}.dshRemoteServiceAddress>a{color:var(--dsw-alias-label-secondary);text-decoration:none}.dshRemoteServiceAddress>a:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteQrLogin>button,.dshRemoteClientLogin>.dshRemoteLoginSwitch{min-height:32px;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:4px 8px;font:inherit;font-size:12px;cursor:pointer}.dshRemoteQrLogin>button:hover,.dshRemoteClientLogin>.dshRemoteLoginSwitch:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteClientLogin>.dshRemoteLoginSwitch{align-self:flex-start;background:transparent;color:var(--dsw-alias-label-secondary);padding-left:0}",
4374
- ".dshRemoteLoginHeading{box-sizing:border-box;width:100%;display:flex;align-items:baseline;gap:10px;overflow:hidden;white-space:nowrap}.dshRemoteLoginTitle{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteLoginHeading>span{flex:0 0 auto;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:400}.dshRemoteLoginTabs{box-sizing:border-box;width:100%;flex-wrap:wrap}.dshRemoteLoginTabs>button{min-width:120px;flex:1 0 auto;display:flex;align-items:center;justify-content:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.dshRemoteLoginTabs>button.isActive::after{right:0;left:0;border-radius:0}.dshRemoteClientLogin,.dshRemoteQrLogin{box-sizing:border-box;width:100%;height:300px;min-height:300px}.dshRemoteClientLogin{align-items:stretch;padding-top:16px}.dshRemoteClientLogin>button{align-self:stretch;width:100%}.dshRemoteQrLogin{padding-top:12px}",
4375
- '.dshRemoteHostControlToggle{display:flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;white-space:nowrap;cursor:default}.dshRemoteHostControlToggle>input{appearance:none;box-sizing:border-box;position:relative;width:32px;height:18px;flex:0 0 auto;margin:0;border:1px solid var(--dsw-alias-label-secondary);border-radius:999px;background:var(--dsw-alias-bg-layer-3);cursor:pointer;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2);transition:background .16s ease-out,border-color .16s ease-out,box-shadow .16s ease-out}.dshRemoteHostControlToggle>input::after{content:"";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-label-secondary);transition:transform .16s ease-out,background .16s ease-out}.dshRemoteHostControlToggle>input:checked{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-primary);box-shadow:none}.dshRemoteHostControlToggle>input:checked::after{transform:translateX(14px);background:var(--dsw-alias-bg-layer-1)}.dshRemoteHostControlToggle>input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteHostControlToggle>input:disabled{opacity:.5;cursor:default}@media(prefers-reduced-motion:reduce){.dshRemoteHostControlToggle>input,.dshRemoteHostControlToggle>input::after{transition:none}}',
4376
- ".dshRemoteAccountFooter{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:14px;color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteAccountExit{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;padding:5px 0;font-size:12px;line-height:1.5;white-space:nowrap}.dshRemoteAccountExit:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteAccountExit:disabled{opacity:.5;cursor:default;text-decoration:none}",
4377
- ".dshRemoteLocalLink{align-self:flex-start;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:4px 0;cursor:pointer}.dshRemoteLocalLink:hover{color:var(--dsw-alias-label-primary)}",
4378
- "@keyframes dshRemotePageIn{from{opacity:0;transform:translateY(6px) scale(.99)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.dshRemotePage{animation:none}}@media(max-width:620px){.dshRemoteBackdrop{padding:12px}.dshRemotePage{max-height:calc(100vh - 24px)}.dshRemotePageHeader{gap:8px;padding:12px 16px}.dshRemotePage.hasSelectedHost .dshRemotePageBack{max-width:112px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteSectionHeading{align-items:flex-start;flex-direction:column;gap:8px}.dshRemoteWorkspaceHeading{align-items:center;flex-direction:row}.dshRemoteSectionActions{width:100%;justify-content:space-between}.dshRemotePageBody{padding:20px 16px}.dshRemoteOpenBar{align-items:flex-end}.dshRemoteOpenBar>button{min-height:48px}}",
4379
- ".dshRemoteBackdrop{position:fixed;inset:0;z-index:1000;background:var(--dsw-alias-bg-mask-3);display:grid;place-items:center;padding:20px}",
4380
- ".dshRemoteDialog{width:min(460px,100%);max-height:80vh;overflow:auto;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:18px;display:grid;gap:12px;box-shadow:var(--dsw-shadow-lv2)}",
4381
- ".dshRemoteDialog button,.dshRemoteDialog input{font:inherit;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:9px 10px;background:transparent;color:inherit}",
4382
- ".dshRemoteDialog button:not(:disabled){cursor:pointer}.dshRemoteDialog button:disabled{opacity:.5}",
4383
- ".dshRemoteHeader{display:flex;align-items:center;justify-content:space-between}.dshRemoteHeader button{border:0;font-size:22px;padding:0 6px}",
4384
- ".dshRemoteDevices{display:grid;gap:8px}.dshRemoteDevices p{margin:4px 0;color:var(--dsw-alias-label-secondary)}",
4385
- ".dshRemoteError{margin:0;color:var(--dsw-alias-state-error-primary)}",
4386
- ".dshRemoteHostAccount{display:grid;gap:8px;border-top:1px solid var(--dsw-alias-border-l3);padding-top:12px}.dshRemoteHostAccount p{margin:0;color:var(--dsw-alias-label-secondary);font-size:13px}",
4387
- ".dshRemoteLogin{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dshRemoteLogin button{grid-column:1/-1}",
4388
- // The plugin manager already supplies DSH's detail page chrome and
4389
- // spacing for `view: page`. Keep the legacy card only for older hosts;
4390
- // current DSH must not get a second, old-style card inside that page.
4391
- ".dshRemotePluginCard{list-style:none;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:var(--dsw-radius-xl,16px);transition:border-color .16s,background .16s}",
4392
- ".dshRemotePluginModern{box-sizing:border-box;width:100%;max-width:none;box-shadow:none;border:0;background:transparent;border-radius:0}.dshRemotePluginModern>.dshRemotePluginCardHeader{display:none}.dshRemotePluginModern>.dshRemotePluginCardBody{border-top:0;margin:0;padding:0}",
4393
- ".dshRemotePluginCard:hover{border-color:var(--dsw-alias-label-dimmed)}.dshRemotePluginCard.isOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}",
4394
- ".dshRemotePluginCard.dshRemotePluginModern:hover,.dshRemotePluginCard.dshRemotePluginModern.isOpen{border-color:transparent;background:transparent}",
4395
- ".dshRemotePluginCardHeader{display:flex;align-items:center}.dshRemotePluginCardToggle{appearance:none;width:100%;min-width:0;font:inherit;color:inherit;text-align:left;cursor:pointer;background:transparent;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 16px}.dshRemotePluginCardToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}",
4396
- ".dshRemotePluginCardHeading{display:flex;flex-direction:column;gap:4px;min-width:0;flex:1}.dshRemotePluginCardHeading>strong{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.dshRemotePluginCardHeading>span{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.dshRemotePluginCardStatus{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.dshRemotePluginCardStatus.isOnline{color:var(--dsw-alias-state-success-primary)}.dshRemotePluginCardStatus.isReconnecting{color:var(--dsw-alias-state-warn-label)}.dshRemotePluginCardStatus.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemotePluginCardChevron{color:var(--dsw-alias-label-tertiary);font-size:18px;line-height:14px;transition:transform .16s}.dshRemotePluginCard.isOpen .dshRemotePluginCardChevron{transform:rotate(180deg)}",
4397
- ".dshRemotePluginCardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.dshRemoteSettings{display:flex;flex-direction:column;max-width:none}.dshRemoteSettingsTop{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:0 0 12px}.dshRemoteSettingsState{margin:0;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}",
4398
- ".dshRemotePluginModern .dshRemoteField input{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md,8px);height:40px}.dshRemotePluginModern .dshRemoteSettingsFooter button{border-radius:var(--dsw-radius-md,8px);min-height:32px}",
4399
- ".dshRemoteHostIdentity{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:12px 0;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemoteHostIdentity>div{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostIdentity span{color:var(--dsw-alias-label-tertiary);font-size:12px}.dshRemoteHostIdentity strong,.dshRemoteHostIdentity code{min-width:0;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500}.dshRemoteHostIdentity code{font-family:var(--dsw-font-mono,ui-monospace,SFMono-Regular,Menlo,monospace);font-weight:400}",
4400
- ".dshRemoteField{display:flex;flex-direction:column;gap:6px;padding:12px 0}.dshRemoteField+.dshRemoteField{border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteField label{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.dshRemoteField input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.dshRemoteField input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.dshRemoteField input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.dshRemoteField p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}",
4401
- '.dshRemoteAuthorizationSetting{border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;gap:20px;padding:12px 0}.dshRemoteAuthorizationSetting>div{min-width:0}.dshRemoteAuthorizationSetting strong{font-size:13px;font-weight:500}.dshRemoteAuthorizationSetting p{margin:3px 0 0;color:var(--dsw-alias-label-tertiary);font-size:12px}.dshRemoteAuthorizationSetting>input{appearance:none;position:relative;width:38px;height:22px;flex:0 0 auto;margin:0;border:1px solid var(--dsw-alias-label-secondary);border-radius:999px;background:var(--dsw-alias-bg-layer-3);cursor:pointer;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2);transition:background .16s ease-out,border-color .16s ease-out,box-shadow .16s ease-out}.dshRemoteAuthorizationSetting>input::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-secondary);transition:transform .16s ease-out,background .16s ease-out}.dshRemoteAuthorizationSetting>input:checked{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-primary);box-shadow:none}.dshRemoteAuthorizationSetting>input:checked::after{transform:translateX(16px);background:var(--dsw-alias-bg-layer-1)}.dshRemoteAuthorizationSetting>input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteAuthorizationSetting>input:disabled{opacity:.5;cursor:default}@media(prefers-reduced-motion:reduce){.dshRemoteAuthorizationSetting>input,.dshRemoteAuthorizationSetting>input::after{transition:none}}',
4402
- ".dshRemoteAssociation{min-width:0;flex:1;display:flex;flex-direction:column;gap:4px}.dshRemoteAssociation>span{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.dshRemoteAssociation strong{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:1.5}.dshRemoteAssociation p{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}",
4403
- ".dshRemoteConnection{border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 0}.dshRemoteConnectionSummary{min-width:0;display:flex;flex-direction:column;gap:4px}.dshRemoteConnectionSummary>span{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.dshRemoteConnectionSummary strong{display:flex;align-items:center;gap:7px;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:1.5}.dshRemoteConnectionSummary p,.dshRemoteConnectionIssue{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.dshRemoteConnectionDot{width:8px;height:8px;flex:0 0 auto;border-radius:999px;background:var(--dsw-alias-label-tertiary)}.dshRemoteConnectionDot.isOnline{background:var(--dsw-alias-state-success-primary)}.dshRemoteConnectionDot.isReconnecting{background:var(--dsw-alias-state-warn-primary)}.dshRemoteConnectionDot.isOffline{background:var(--dsw-alias-state-error-primary)}.dshRemoteConnectionIssue{color:var(--dsw-alias-state-error-primary);padding:0 0 12px}.dshRemoteReconnect{appearance:none;flex:0 0 auto;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);min-height:34px;padding:5px 14px;font-size:13px;line-height:1.5}.dshRemoteReconnect:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteReconnect:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.dshRemoteReconnect:disabled{opacity:.4;cursor:default}",
4404
- ".dshRemoteSettingsFooter{border-top:1px solid var(--dsw-alias-border-l2);display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px}.dshRemoteSettingsFooter .dshRemoteError,.dshRemoteNotice{min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.dshRemoteNotice{color:var(--dsw-alias-label-tertiary)}.dshRemoteDiscard,.dshRemoteSave{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.dshRemoteDiscard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteDiscard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.dshRemoteSave{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.dshRemoteDiscard:disabled,.dshRemoteSave:disabled{opacity:.4;cursor:default}.dshRemoteDiscard:focus-visible,.dshRemoteSave:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}",
4405
- "@media(max-width:620px){.dshRemotePluginCardStatus{display:none}.dshRemoteSettingsTop{gap:10px}.dshRemoteConnection{align-items:flex-start}.dshRemoteReconnect{min-height:40px}.dshRemotePortsRow{flex-direction:column}.dshRemoteAcpAddForm{grid-template-columns:1fr}.dshRemoteAcpAddForm button{min-height:40px}}"
4406
- ].join(""), document.head.append(style), () => style.remove();
4407
- }
4408
4628
  function apply(ctx) {
4409
4629
  if (window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__) return;
4410
4630
  window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__ = !0, readyPluginSessions(ctx.sessions), ctx.effect(() => () => {
@@ -4438,7 +4658,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
4438
4658
  if (disposed || opening || selection === void 0) return;
4439
4659
  let pending = selection, workspaceSnapshot = ctx.workspaces.list.getSnapshot();
4440
4660
  if (!workspacesReady(workspaceSnapshot) || !workspaceSnapshot.items.some((workspace) => workspace.workspaceId === pending.workspaceId)) return;
4441
- let sessionSnapshot = ctx.sessions.list.getSnapshot(), isVirtualBackend = pending.backend === "codex" || pending.backend === "cursor" || pending.backend === "antigravity";
4661
+ let sessionSnapshot = ctx.sessions.list.getSnapshot(), isVirtualBackend = pending.backend === "codex" || pending.backend === "cursor" || pending.backend === "antigravity" || pending.backend === "pi" || pending.backend === "opencode";
4442
4662
  if (isVirtualBackend && pending.sessionId !== void 0 && sessionSnapshot.phase !== "ready") return;
4443
4663
  opening = !0, unsubscribeWorkspaces?.(), unsubscribeSessions?.(), unsubscribeWorkspaces = void 0, unsubscribeSessions = void 0;
4444
4664
  let navigation = ctx.get("uiWorkspace"), connectWorkspace = (workspaceId) => navigation !== void 0 ? navigation.connectWorkspace(workspaceId) : ctx.workspaces.connectWorkspace(workspaceId);
@@ -4480,7 +4700,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
4480
4700
  unsubscribe(), unregister?.();
4481
4701
  };
4482
4702
  }, "ds-harness-remote: remote file viewer provider");
4483
- }), ctx.effect(() => ctx.locale.register(localeNamespace, { zh, en }), "ds-harness-remote: dictionaries"), ctx.effect(installStyle, "ds-harness-remote: client styles"), ctx.effect(() => installTerminalAvailabilityNotice(statusFeed, t), "ds-harness-remote: terminal availability notice"), ctx.slots.inject("shell.overlay", () => ctx.slots.register({
4703
+ }), ctx.effect(() => ctx.locale.register(localeNamespace, { zh, en }), "ds-harness-remote: dictionaries"), ctx.effect(() => installStyle(clientModuleId), "ds-harness-remote: client styles"), ctx.effect(() => installTerminalAvailabilityNotice(statusFeed, t), "ds-harness-remote: terminal availability notice"), ctx.slots.inject("shell.overlay", () => ctx.slots.register({
4484
4704
  name: "shell.overlay",
4485
4705
  id: "ds-harness-remote-global-context",
4486
4706
  order: 20,
@@ -4511,31 +4731,6 @@ Minimum version required to store current data is: ` + bestVersion + `.
4511
4731
  function isMissingControlRoute(reason) {
4512
4732
  return reason instanceof Error && reason.message.startsWith(`transport failure for ${CONTROL_RPC_PREFIX}/`) && (reason.message.endsWith(": HTTP 404") || reason.message.endsWith(": HTTP 405"));
4513
4733
  }
4514
- function installTerminalAvailabilityNotice(feed, t) {
4515
- let latest, notice, update = () => {
4516
- let terminal = document.querySelector("[data-sidebar-terminal]"), unavailable = latest?.mode === "remote" && latest.remoteFeatures?.terminal !== !0;
4517
- if (!terminal || !unavailable) {
4518
- notice?.remove(), notice = void 0;
4519
- return;
4520
- }
4521
- notice !== void 0 && notice.isConnected || (notice = document.createElement("div"), notice.className = "dshRemoteTerminalUnavailable", notice.setAttribute("role", "alert"), notice.textContent = t("terminalRemoteUnavailable"), terminal.prepend(notice));
4522
- }, unsubscribe = feed.subscribe((status) => {
4523
- latest = status, update();
4524
- }), observer = new MutationObserver(update);
4525
- return observer.observe(document.body, { childList: !0, subtree: !0 }), update(), () => {
4526
- unsubscribe(), observer.disconnect(), notice?.remove();
4527
- };
4528
- }
4529
- function messageOf(reason) {
4530
- return reason instanceof Error ? reason.message : String(reason);
4531
- }
4532
- function formatPlatform(value) {
4533
- let normalized = value.toLowerCase();
4534
- return normalized === "darwin" || normalized === "macos" ? "macOS" : normalized === "win32" || normalized === "windows" ? "Windows" : normalized === "linux" ? "Linux" : normalized === "android" ? "Android" : value;
4535
- }
4536
- function connectedClientModeLabel(mode, t) {
4537
- return t(mode === "LAN" ? "remoteNetworkLan" : mode === "P2P" ? "remoteNetworkP2p" : mode === "TURN" ? "remoteNetworkTurn" : mode === "Relay" ? "remoteNetworkRelay" : "connected");
4538
- }
4539
4734
  return module.exports.apply = apply, module.exports.inject = inject, module.exports;
4540
4735
  }
4541
4736
  });