ds-harness-remote 0.5.5 → 0.5.8

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 (92) hide show
  1. package/dist/acp/adapters/antigravity/transcript-loader.d.ts.map +1 -1
  2. package/dist/acp/adapters/antigravity/transcript-loader.js +4 -1
  3. package/dist/acp/adapters/antigravity/transcript-loader.js.map +1 -1
  4. package/dist/acp/gateway.d.ts +2 -0
  5. package/dist/acp/gateway.d.ts.map +1 -1
  6. package/dist/acp/gateway.js +46 -37
  7. package/dist/acp/gateway.js.map +1 -1
  8. package/dist/acp/workspace-tools.js +1 -1
  9. package/dist/acp/workspace-tools.js.map +1 -1
  10. package/dist/cli.d.ts +2 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +16 -14
  13. package/dist/cli.js.map +1 -1
  14. package/dist/client-locale.d.ts +5 -0
  15. package/dist/client-locale.d.ts.map +1 -1
  16. package/dist/client-locale.js +10 -0
  17. package/dist/client-locale.js.map +1 -1
  18. package/dist/client-runtime.d.ts +2 -0
  19. package/dist/client-runtime.d.ts.map +1 -1
  20. package/dist/client-runtime.js +26 -2
  21. package/dist/client-runtime.js.map +1 -1
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.github.js +242 -30
  24. package/dist/client.js +242 -30
  25. package/dist/client.js.map +1 -1
  26. package/dist/codex/app-server.js +2 -0
  27. package/dist/codex/app-server.js.map +1 -1
  28. package/dist/codex/domain.d.ts.map +1 -1
  29. package/dist/codex/domain.js +29 -7
  30. package/dist/codex/domain.js.map +1 -1
  31. package/dist/harness-remote-bridge.d.ts +1 -1
  32. package/dist/harness-remote-bridge.d.ts.map +1 -1
  33. package/dist/harness-remote-bridge.js +4 -2
  34. package/dist/harness-remote-bridge.js.map +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +6582 -454
  37. package/dist/index.js.map +4 -4
  38. package/dist/plugin-route-bridge.d.ts +23 -0
  39. package/dist/plugin-route-bridge.d.ts.map +1 -0
  40. package/dist/plugin-route-bridge.js +82 -0
  41. package/dist/plugin-route-bridge.js.map +1 -0
  42. package/dist/plugin-route-client.d.ts +20 -0
  43. package/dist/plugin-route-client.d.ts.map +1 -0
  44. package/dist/plugin-route-client.js +242 -0
  45. package/dist/plugin-route-client.js.map +1 -0
  46. package/dist/plugin-route-dispatcher.d.ts +10 -0
  47. package/dist/plugin-route-dispatcher.d.ts.map +1 -0
  48. package/dist/plugin-route-dispatcher.js +61 -0
  49. package/dist/plugin-route-dispatcher.js.map +1 -0
  50. package/dist/remote-terminal-controller.d.ts +90 -0
  51. package/dist/remote-terminal-controller.d.ts.map +1 -0
  52. package/dist/remote-terminal-controller.js +494 -0
  53. package/dist/remote-terminal-controller.js.map +1 -0
  54. package/dist/remote-terminal-provider.d.ts +46 -0
  55. package/dist/remote-terminal-provider.d.ts.map +1 -0
  56. package/dist/remote-terminal-provider.js +147 -0
  57. package/dist/remote-terminal-provider.js.map +1 -0
  58. package/dist/rpc-router.d.ts +4 -1
  59. package/dist/rpc-router.d.ts.map +1 -1
  60. package/dist/rpc-router.js +11 -1
  61. package/dist/rpc-router.js.map +1 -1
  62. package/dist/server-api.d.ts +12 -1
  63. package/dist/server-api.d.ts.map +1 -1
  64. package/dist/server-api.js +85 -11
  65. package/dist/server-api.js.map +1 -1
  66. package/dist/server-connection.d.ts.map +1 -1
  67. package/dist/server-connection.js +2 -0
  68. package/dist/server-connection.js.map +1 -1
  69. package/dist/service.d.ts +5 -2
  70. package/dist/service.d.ts.map +1 -1
  71. package/dist/service.js +27 -5
  72. package/dist/service.js.map +1 -1
  73. package/dist/terminal-policy.d.ts +6 -0
  74. package/dist/terminal-policy.d.ts.map +1 -1
  75. package/dist/terminal-policy.js +24 -6
  76. package/dist/terminal-policy.js.map +1 -1
  77. package/dist/tui-command.d.ts.map +1 -1
  78. package/dist/tui-command.js +58 -18
  79. package/dist/tui-command.js.map +1 -1
  80. package/dist/typert-gateway-contract.d.ts +4 -0
  81. package/dist/typert-gateway-contract.d.ts.map +1 -1
  82. package/dist/typert-gateway-switch.d.ts.map +1 -1
  83. package/dist/typert-gateway-switch.js +23 -3
  84. package/dist/typert-gateway-switch.js.map +1 -1
  85. package/dist/version.d.ts +1 -1
  86. package/dist/version.js +1 -1
  87. package/dist/workspace-bridge.d.ts +6 -89
  88. package/dist/workspace-bridge.d.ts.map +1 -1
  89. package/dist/workspace-bridge.js +37 -294
  90. package/dist/workspace-bridge.js.map +1 -1
  91. package/dsh-plugin.json +1 -1
  92. package/package.json +4 -2
package/dist/client.js CHANGED
@@ -1696,6 +1696,164 @@ Minimum version required to store current data is: ` + bestVersion + `.
1696
1696
  // src/control-route.ts
1697
1697
  var CONTROL_RPC_PREFIX = "/ds-harness-remote", STATUS_STREAM_ENDPOINT = "status.events", STATUS_STREAM_PATH = `${CONTROL_RPC_PREFIX}/${STATUS_STREAM_ENDPOINT}`;
1698
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
+
1699
1857
  // src/status-stream.ts
1700
1858
  function parseStatus(data) {
1701
1859
  if (typeof data == "string")
@@ -1991,6 +2149,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
1991
2149
  unknownDevice: "Unknown device",
1992
2150
  exitRemoteAccount: "Sign out",
1993
2151
  githubLogin: "GitHub QR",
2152
+ providerLogin: "{provider} QR",
2153
+ scanWithProvider: "Scan to continue with {provider}",
2154
+ loadingLoginProviders: "Loading sign-in methods\u2026",
2155
+ retryLoginProviders: "Retry loading sign-in methods",
2156
+ noLoginProviders: "QR sign-in is unavailable. Use email and password.",
1994
2157
  zhihuLogin: "Zhihu QR",
1995
2158
  scanWithGitHub: "Scan to continue with GitHub",
1996
2159
  scanWithZhihu: "Scan to continue with Zhihu",
@@ -2244,6 +2407,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
2244
2407
  unknownDevice: "\u672A\u77E5\u8BBE\u5907",
2245
2408
  exitRemoteAccount: "\u9000\u51FA\u8D26\u53F7",
2246
2409
  githubLogin: "GitHub \u626B\u7801",
2410
+ providerLogin: "{provider} \u626B\u7801",
2411
+ scanWithProvider: "\u4F7F\u7528 {provider} \u626B\u7801\u767B\u5F55",
2412
+ loadingLoginProviders: "\u6B63\u5728\u83B7\u53D6\u767B\u5F55\u65B9\u5F0F\u2026",
2413
+ retryLoginProviders: "\u91CD\u65B0\u83B7\u53D6\u767B\u5F55\u65B9\u5F0F",
2414
+ noLoginProviders: "\u6682\u65E0\u53EF\u7528\u7684\u626B\u7801\u767B\u5F55\u65B9\u5F0F\uFF0C\u8BF7\u4F7F\u7528\u90AE\u7BB1\u548C\u5BC6\u7801\u3002",
2247
2415
  zhihuLogin: "\u77E5\u4E4E\u626B\u7801",
2248
2416
  scanWithGitHub: "\u4F7F\u7528 GitHub \u626B\u7801\u767B\u5F55",
2249
2417
  scanWithZhihu: "\u4F7F\u7528\u77E5\u4E4E\u626B\u7801\u767B\u5F55",
@@ -2282,7 +2450,12 @@ Minimum version required to store current data is: ` + bestVersion + `.
2282
2450
  constructor(message) {
2283
2451
  super(message), this.name = "ControlRouteUnavailableError";
2284
2452
  }
2285
- };
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);
2286
2459
  function controlRouteUnavailableStatus() {
2287
2460
  return {
2288
2461
  mode: "local",
@@ -2290,7 +2463,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2290
2463
  controlUnavailable: !0,
2291
2464
  connected: !1,
2292
2465
  transport: "Disconnected",
2293
- remoteFeatures: { commandList: !1, fileViewer: !1, terminal: !1, codex: !1, cursor: !1, antigravity: !1 },
2466
+ remoteFeatures: { commandList: !1, fileViewer: !1, terminal: !1, codex: !1, pluginRoute: !1, cursor: !1, antigravity: !1 },
2294
2467
  hostAuthorizationAvailable: !1
2295
2468
  };
2296
2469
  }
@@ -2901,9 +3074,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
2901
3074
  );
2902
3075
  }
2903
3076
  function RemoteWorkspaceAction(props) {
2904
- 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(props.preferredQrProvider), [loginMethodManuallySelected, setLoginMethodManuallySelected] = React.useState(!1), [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);
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);
2905
3078
  React.useEffect(() => {
2906
- open || setDevicesOpen(!1);
3079
+ open || (setDevicesOpen(!1), qrFlowRun.current += 1, setBusy(!1));
2907
3080
  }, [open]), React.useEffect(() => {
2908
3081
  if (!open) return;
2909
3082
  let closeOnEscape = (event) => {
@@ -2954,8 +3127,26 @@ Minimum version required to store current data is: ` + bestVersion + `.
2954
3127
  }
2955
3128
  };
2956
3129
  React.useEffect(() => {
2957
- !open || !needsAuthorization || loginMethod === "password" || qrSession !== void 0 || qrExpired || startQrLogin(loginMethod);
2958
- }, [open, needsAuthorization, loginMethod, qrSession, qrExpired]), 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
+ });
3140
+ }).catch((reason) => {
3141
+ active && (setProvidersFailed(!0), setLoginMethod("password"), setError(messageOf(reason)));
3142
+ }).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(() => {
2959
3150
  if (!open || loginMethod === "password" || qrSession === void 0) return;
2960
3151
  let active = !0, polling = !1, settled = !1, run = qrFlowRun.current, timer, poll = () => {
2961
3152
  polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
@@ -2983,22 +3174,20 @@ Minimum version required to store current data is: ` + bestVersion + `.
2983
3174
  return poll(), timer = window.setInterval(poll, 1500), () => {
2984
3175
  active = !1, timer !== void 0 && window.clearInterval(timer);
2985
3176
  };
2986
- }, [open, loginMethod, qrSession]), React.useEffect(() => {
2987
- loginMethodManuallySelected || loginMethod === props.preferredQrProvider || (qrFlowRun.current += 1, setLoginMethod(props.preferredQrProvider), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setError(void 0));
2988
- }, [props.preferredQrProvider, loginMethodManuallySelected]);
3177
+ }, [open, loginMethod, qrSession]);
2989
3178
  let selectLoginMethod = (method) => {
2990
- setLoginMethodManuallySelected(!0), method !== loginMethod && (qrFlowRun.current += 1, setLoginMethod(method), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setError(void 0));
2991
- }, orderedQrProviders = props.preferredQrProvider === "zhihu" ? ["zhihu", "github"] : ["github", "zhihu"], qrLoginTab = (provider) => React.createElement("button", {
2992
- key: provider,
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,
2993
3182
  type: "button",
2994
3183
  role: "tab",
2995
- id: `dsh-remote-${provider}-tab`,
2996
- "aria-selected": loginMethod === provider,
2997
- "aria-controls": `dsh-remote-${provider}-panel`,
2998
- className: loginMethod === provider ? "isActive" : "",
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" : "",
2999
3188
  disabled: busy,
3000
- onClick: () => selectLoginMethod(provider)
3001
- }, t(provider === "github" ? "githubLogin" : "zhihuLogin")), selectHost = async (host) => {
3189
+ onClick: () => selectLoginMethod(`oauth:${provider.id}`)
3190
+ }, t("providerLogin", { provider: provider.displayName })), selectHost = async (host) => {
3002
3191
  setBusy(!0), setError(void 0), setConnectingHost(host), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1);
3003
3192
  try {
3004
3193
  let result = await runConnectHostProgress(
@@ -3162,7 +3351,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3162
3351
  setError(messageOf(reason)), setBusy(!1);
3163
3352
  }
3164
3353
  }
3165
- }, remoteLabel = status?.mode === "remote" ? t("activeRemote", { name: status.target?.name ?? t("host") }) : t("remoteEntry"), 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 : [
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 : [
3166
3355
  formatPlatform(selectedHost.platform),
3167
3356
  selectedHost.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: selectedHost.harnessVersion }),
3168
3357
  selectedHost.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: selectedHost.clientVersion })
@@ -3220,11 +3409,15 @@ Minimum version required to store current data is: ` + bestVersion + `.
3220
3409
  React.createElement(
3221
3410
  "div",
3222
3411
  { className: `dshRemoteSidebarEntry${status?.mode === "remote" ? " isActive" : ""}${props.wide ? " isWide" : " isRail"}` },
3223
- React.createElement(status?.mode === "remote" ? "div" : "button", {
3224
- ...status?.mode === "remote" ? {} : { type: "button", onClick: () => void show() },
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
+ },
3225
3418
  className: "dshRemoteModeButton",
3226
- title: remoteLabel,
3227
- "aria-label": remoteLabel
3419
+ title: props.wide ? remoteLabel : remoteActionLabel,
3420
+ "aria-label": props.wide ? remoteLabel : remoteActionLabel
3228
3421
  }, React.createElement(
3229
3422
  "svg",
3230
3423
  {
@@ -3337,7 +3530,15 @@ Minimum version required to store current data is: ` + bestVersion + `.
3337
3530
  onClick: () => selectLoginMethod("password")
3338
3531
  }, t("accountPasswordLogin"))
3339
3532
  ),
3340
- loginMethod !== "password" ? React.createElement(
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(
3341
3542
  "div",
3342
3543
  {
3343
3544
  className: "dshRemoteQrLogin",
@@ -3362,11 +3563,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
3362
3563
  src: qrImage,
3363
3564
  width: 184,
3364
3565
  height: 184,
3365
- alt: t(loginMethod === "github" ? "scanWithGitHub" : "scanWithZhihu")
3566
+ alt: scanLabel
3366
3567
  }),
3367
3568
  React.createElement("span", null, t("openInBrowser"), " \u2197")
3368
3569
  ) : null,
3369
- React.createElement("strong", null, t(loginMethod === "github" ? "scanWithGitHub" : "scanWithZhihu")),
3570
+ React.createElement("strong", null, scanLabel),
3370
3571
  React.createElement("p", null, t("scanLoginHint")),
3371
3572
  status?.serverUrl === void 0 ? null : React.createElement(
3372
3573
  "p",
@@ -4128,8 +4329,17 @@ Minimum version required to store current data is: ` + bestVersion + `.
4128
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}",
4129
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}",
4130
4331
  ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
4131
- ".dshRemoteSidebarEntry{box-sizing:border-box;position:relative;min-width:0;display:block;overflow:hidden}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:100%;min-width:0}.dshRemoteSidebarEntry.isWide{width:calc(100% + 8px);height:34px;margin:4px -4px}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{height:34px;min-height:34px;padding:6px 48px 6px 10px;border-radius:12px}.dshRemoteSidebarEntry.isRail{width:36px;height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{width:36px;height:36px;min-height:36px;justify-content:center;gap:0;margin:8px 0 10px;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isActive .dshRemoteModeButton{color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteSidebarLabel{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteExitLink{position:absolute;top:50%;right:10px;transform:translateY(-50%);white-space:nowrap;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;font:inherit;font-size:12px;line-height:20px;cursor:pointer}.dshRemoteExitLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}",
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}",
4132
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}",
4133
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}}',
4134
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)}}",
4135
4345
  ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
@@ -4161,7 +4371,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
4161
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}',
4162
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}",
4163
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}",
4164
- ".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%}.dshRemoteLoginTabs>button{min-width:0;flex:1;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}",
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: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}",
4165
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}}',
4166
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}",
4167
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)}",
@@ -4197,9 +4407,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
4197
4407
  }
4198
4408
  function apply(ctx) {
4199
4409
  if (window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__) return;
4200
- window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__ = !0, ctx.effect(() => () => {
4410
+ window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__ = !0, readyPluginSessions(ctx.sessions), ctx.effect(() => () => {
4201
4411
  window.__DS_HARNESS_REMOTE_CLIENT_ACTIVE__ = !1;
4202
- }, "ds-harness-remote: client singleton");
4412
+ }, "ds-harness-remote: client singleton"), ctx.effect(() => () => {
4413
+ pluginRouteFetch !== void 0 && window.fetch === pluginRouteFetch && (window.fetch = originalPluginFetch);
4414
+ }, "ds-harness-remote: plugin route fetch");
4203
4415
  let t = ctx.locale.bind(localeNamespace), controlRouteRetryAfter = 0, controlRouteBackoffIndex = 0, control = async (endpoint, payload = {}) => {
4204
4416
  if (endpoint === "status" && Date.now() < controlRouteRetryAfter)
4205
4417
  return controlRouteUnavailableStatus();