ds-harness-remote 0.4.13 → 0.4.14

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 (46) hide show
  1. package/dist/acp.d.ts +75 -0
  2. package/dist/acp.d.ts.map +1 -0
  3. package/dist/acp.js +61 -0
  4. package/dist/acp.js.map +1 -0
  5. package/dist/client-runtime.d.ts +6 -0
  6. package/dist/client-runtime.d.ts.map +1 -1
  7. package/dist/client-runtime.js.map +1 -1
  8. package/dist/client.github.js +224 -9
  9. package/dist/client.js +224 -9
  10. package/dist/client.js.map +1 -1
  11. package/dist/codex/method-policy.d.ts +10 -10
  12. package/dist/config.d.ts +24 -0
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +3 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/connection-controller.d.ts +5 -0
  17. package/dist/connection-controller.d.ts.map +1 -1
  18. package/dist/connection-controller.js +16 -1
  19. package/dist/connection-controller.js.map +1 -1
  20. package/dist/control-runtime.d.ts +4 -0
  21. package/dist/control-runtime.d.ts.map +1 -1
  22. package/dist/control-runtime.js +55 -0
  23. package/dist/control-runtime.js.map +1 -1
  24. package/dist/harness-api-bridge.d.ts.map +1 -1
  25. package/dist/harness-api-bridge.js +29 -8
  26. package/dist/harness-api-bridge.js.map +1 -1
  27. package/dist/harness-remote-bridge.d.ts +2 -1
  28. package/dist/harness-remote-bridge.d.ts.map +1 -1
  29. package/dist/harness-remote-bridge.js +44 -2
  30. package/dist/harness-remote-bridge.js.map +1 -1
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +328 -23
  34. package/dist/index.js.map +4 -4
  35. package/dist/rpc-router.d.ts +5 -2
  36. package/dist/rpc-router.d.ts.map +1 -1
  37. package/dist/rpc-router.js +18 -1
  38. package/dist/rpc-router.js.map +1 -1
  39. package/dist/service.d.ts +9 -0
  40. package/dist/service.d.ts.map +1 -1
  41. package/dist/service.js +31 -2
  42. package/dist/service.js.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/dsh-plugin.json +1 -1
  46. package/package.json +21 -21
@@ -1909,6 +1909,22 @@ Minimum version required to store current data is: ` + bestVersion + `.
1909
1909
  signInClientDescription: "Connect once. Available anytime.",
1910
1910
  startSignIn: "Start sign-in",
1911
1911
  allowControlCurrentDevice: "Allow control of this device",
1912
+ connectedClientCount: "{count} connected",
1913
+ checkAcp: "Check ACP",
1914
+ checkingAcp: "Checking ACP\u2026",
1915
+ acpAvailable: "ACP available",
1916
+ acpUnavailable: "ACP unavailable",
1917
+ acpHint: "Connect compatible coding agents through the Agent Client Protocol.",
1918
+ acpCheckPassed: "Check passed",
1919
+ acpCheckFailed: "Check failed",
1920
+ addAcp: "Add ACP",
1921
+ acpName: "Service name",
1922
+ acpCommand: "Command",
1923
+ acpArguments: "Arguments",
1924
+ removeAcp: "Remove",
1925
+ currentConnectedDevices: "Currently connected devices",
1926
+ noConnectedClients: "No devices are currently connected to this Host.",
1927
+ unknownDevice: "Unknown device",
1912
1928
  exitRemoteAccount: "Sign out",
1913
1929
  githubLogin: "GitHub QR",
1914
1930
  zhihuLogin: "Zhihu QR",
@@ -2116,6 +2132,22 @@ Minimum version required to store current data is: ` + bestVersion + `.
2116
2132
  signInClientDescription: "\u4E00\u6B21\u8FDE\u63A5\uFF0C\u968F\u65F6\u53EF\u7528\u3002",
2117
2133
  startSignIn: "\u5F00\u59CB\u767B\u5F55",
2118
2134
  allowControlCurrentDevice: "\u5141\u8BB8\u63A7\u5236\u5F53\u524D\u8BBE\u5907",
2135
+ connectedClientCount: "{count} \u53F0\u5DF2\u8FDE\u63A5",
2136
+ checkAcp: "\u68C0\u6D4B ACP",
2137
+ checkingAcp: "\u6B63\u5728\u68C0\u6D4B ACP\u2026",
2138
+ acpAvailable: "ACP \u53EF\u7528",
2139
+ acpUnavailable: "ACP \u4E0D\u53EF\u7528",
2140
+ acpHint: "\u901A\u8FC7 Agent Client Protocol \u8FDE\u63A5\u517C\u5BB9\u7684\u7F16\u7801 Agent\u3002",
2141
+ acpCheckPassed: "\u68C0\u6D4B\u901A\u8FC7",
2142
+ acpCheckFailed: "\u68C0\u6D4B\u5931\u8D25",
2143
+ addAcp: "\u6DFB\u52A0 ACP",
2144
+ acpName: "\u670D\u52A1\u540D\u79F0",
2145
+ acpCommand: "\u542F\u52A8\u547D\u4EE4",
2146
+ acpArguments: "\u547D\u4EE4\u53C2\u6570",
2147
+ removeAcp: "\u79FB\u9664",
2148
+ currentConnectedDevices: "\u5F53\u524D\u8FDE\u63A5\u7684\u8BBE\u5907",
2149
+ noConnectedClients: "\u76EE\u524D\u6CA1\u6709\u8BBE\u5907\u8FDE\u63A5\u5230\u8FD9\u53F0\u4E3B\u673A\u3002",
2150
+ unknownDevice: "\u672A\u77E5\u8BBE\u5907",
2119
2151
  exitRemoteAccount: "\u9000\u51FA\u8D26\u53F7",
2120
2152
  githubLogin: "GitHub \u626B\u7801",
2121
2153
  zhihuLogin: "\u77E5\u4E4E\u626B\u7801",
@@ -2322,8 +2354,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
2322
2354
  }
2323
2355
  }
2324
2356
  function RemotePluginOptions(props) {
2325
- let { t } = props, [open, setOpen] = React.useState(!1), [serverUrl, setServerUrl] = React.useState(""), [codexEnabled, setCodexEnabled] = React.useState(!0), 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), [codexBusy, setCodexBusy] = React.useState(!1), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [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) => {
2326
- setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setCodexEnabled(view.config.codex?.enabled ?? !0), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
2357
+ let { t } = props, [open, setOpen] = React.useState(!1), [serverUrl, setServerUrl] = React.useState(""), [codexEnabled, setCodexEnabled] = React.useState(!0), 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), [codexBusy, setCodexBusy] = 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), [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) => {
2358
+ setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setCodexEnabled(view.config.codex?.enabled ?? !0), 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);
2327
2359
  }, load = async () => {
2328
2360
  let [view, status] = await Promise.all([
2329
2361
  props.control("settings.get"),
@@ -2401,6 +2433,46 @@ Minimum version required to store current data is: ` + bestVersion + `.
2401
2433
  } finally {
2402
2434
  setCodexBusy(!1);
2403
2435
  }
2436
+ }, checkAcp = async (backend) => {
2437
+ setAcpChecking((current) => ({ ...current, [backend]: !0 })), setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), setError(void 0);
2438
+ try {
2439
+ let view = await props.control("settings.get");
2440
+ applyView(view);
2441
+ let available = view.acpAvailability?.[backend] === !0;
2442
+ if (!available) {
2443
+ let disabledView = await props.control("settings.acp.set", { backend, enabled: !1 });
2444
+ applyView(disabledView);
2445
+ }
2446
+ setAcpCheckResults((current) => ({ ...current, [backend]: available })), setNotice({ key: available ? "acpAvailable" : "acpUnavailable" }), window.setTimeout(() => setAcpCheckResults((current) => ({ ...current, [backend]: void 0 })), 5e3);
2447
+ } catch (reason) {
2448
+ setError(messageOf(reason));
2449
+ } finally {
2450
+ setAcpChecking((current) => ({ ...current, [backend]: !1 }));
2451
+ }
2452
+ }, addAcp = async () => {
2453
+ setBusy(!0), setError(void 0);
2454
+ try {
2455
+ let view = await props.control("settings.acp.add", {
2456
+ id: acpName.trim(),
2457
+ command: acpCommand.trim(),
2458
+ args: acpArguments.trim() === "" ? [] : acpArguments.trim().split(/\s+/)
2459
+ });
2460
+ applyView(view), setAddingAcp(!1), setAcpName(""), setAcpCommand(""), setAcpArguments("acp");
2461
+ } catch (reason) {
2462
+ setError(messageOf(reason));
2463
+ } finally {
2464
+ setBusy(!1);
2465
+ }
2466
+ }, removeAcp = async (backend) => {
2467
+ setBusy(!0), setError(void 0);
2468
+ try {
2469
+ let view = await props.control("settings.acp.remove", { id: backend });
2470
+ applyView(view);
2471
+ } catch (reason) {
2472
+ setError(messageOf(reason));
2473
+ } finally {
2474
+ setBusy(!1);
2475
+ }
2404
2476
  }, discard = () => {
2405
2477
  settingsView !== void 0 && applyView(settingsView), setRegistrationCode(""), setNotice(void 0), setError(void 0);
2406
2478
  }, codexSetting = React.createElement(
@@ -2420,6 +2492,61 @@ Minimum version required to store current data is: ` + bestVersion + `.
2420
2492
  checked: codexEnabled,
2421
2493
  onChange: (event) => void setCodexRemote(event.target.checked)
2422
2494
  })
2495
+ ), acpSetting = React.createElement(
2496
+ "details",
2497
+ { className: "dshRemoteAuthorizationSetting dshRemoteAcpSetting" },
2498
+ React.createElement(
2499
+ "summary",
2500
+ null,
2501
+ React.createElement(
2502
+ "div",
2503
+ { className: "dshRemoteAcpSummaryText" },
2504
+ React.createElement("strong", null, "ACP Agent backends"),
2505
+ React.createElement("p", null, t("acpHint"))
2506
+ )
2507
+ ),
2508
+ React.createElement(
2509
+ "div",
2510
+ { className: "dshRemoteAcpList" },
2511
+ acpBackends.map((item) => React.createElement(
2512
+ "div",
2513
+ { key: item.id, className: "dshRemoteAuthorizationSetting" },
2514
+ React.createElement("span", null, item.id),
2515
+ React.createElement(
2516
+ "span",
2517
+ { className: "dshRemoteAcpCheckCell" },
2518
+ React.createElement(
2519
+ "a",
2520
+ { href: `#check-acp-${item.id}`, className: `dshRemoteAcpCheckLink${acpChecking[item.id] ? " isChecking" : acpCheckResults[item.id] === void 0 ? "" : acpCheckResults[item.id] ? " isPassed" : " isFailed"}`, onClick: (event) => {
2521
+ event.preventDefault(), checkAcp(item.id);
2522
+ } },
2523
+ acpChecking[item.id] ? t("checkingAcp") : acpCheckResults[item.id] === void 0 ? t("checkAcp") : t(acpCheckResults[item.id] ? "acpCheckPassed" : "acpCheckFailed")
2524
+ )
2525
+ ),
2526
+ ["codex", "cursor", "kimi"].includes(item.id) ? null : React.createElement("a", { href: `#remove-acp-${item.id}`, className: "dshRemoteAcpRemoveLink", onClick: (event) => {
2527
+ event.preventDefault(), removeAcp(item.id);
2528
+ } }, t("removeAcp")),
2529
+ React.createElement("input", {
2530
+ type: "checkbox",
2531
+ role: "switch",
2532
+ checked: item.enabled && acpAvailability[item.id] === !0,
2533
+ disabled: busy || !writable || !acpAvailability[item.id],
2534
+ onChange: (event) => void props.control("settings.acp.set", { backend: item.id, enabled: event.target.checked }).then((view) => {
2535
+ applyView(view), setAcpBackends((view.config.acp?.backends ?? []).map((v) => ({ id: v.id, enabled: v.enabled !== !1 })));
2536
+ }).catch((reason) => setError(messageOf(reason)))
2537
+ })
2538
+ )),
2539
+ addingAcp ? React.createElement(
2540
+ "div",
2541
+ { className: "dshRemoteAcpAddForm" },
2542
+ React.createElement("input", { value: acpName, placeholder: t("acpName"), "aria-label": t("acpName"), onChange: (event) => setAcpName(event.target.value) }),
2543
+ React.createElement("input", { value: acpCommand, placeholder: t("acpCommand"), "aria-label": t("acpCommand"), onChange: (event) => setAcpCommand(event.target.value) }),
2544
+ React.createElement("input", { value: acpArguments, placeholder: t("acpArguments"), "aria-label": t("acpArguments"), onChange: (event) => setAcpArguments(event.target.value) }),
2545
+ React.createElement("button", { type: "button", disabled: busy || acpName.trim() === "" || acpCommand.trim() === "", onClick: () => void addAcp() }, t("addAcp"))
2546
+ ) : React.createElement("a", { href: "#add-acp", className: "dshRemoteAcpAddLink", onClick: (event) => {
2547
+ event.preventDefault(), setAddingAcp(!0);
2548
+ } }, t("addAcp"))
2549
+ )
2423
2550
  );
2424
2551
  return React.createElement(
2425
2552
  "li",
@@ -2483,6 +2610,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2483
2610
  React.createElement("p", null, t("serverUrlHint"))
2484
2611
  ),
2485
2612
  codexSetting,
2613
+ acpSetting,
2486
2614
  React.createElement(
2487
2615
  "div",
2488
2616
  { className: "dshRemoteAuthorizationSetting" },
@@ -2565,6 +2693,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2565
2693
  React.createElement("p", null, t("serverUrlHint"))
2566
2694
  ),
2567
2695
  codexSetting,
2696
+ acpSetting,
2568
2697
  React.createElement("p", { className: "dshRemoteSettingsState" }, t("authorizeFromRemote")),
2569
2698
  writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
2570
2699
  React.createElement(
@@ -2579,14 +2708,31 @@ Minimum version required to store current data is: ` + bestVersion + `.
2579
2708
  );
2580
2709
  }
2581
2710
  function RemoteWorkspaceAction(props) {
2582
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = 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), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [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);
2711
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = 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), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [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);
2583
2712
  React.useEffect(() => {
2713
+ open || setDevicesOpen(!1);
2714
+ }, [open]), React.useEffect(() => {
2584
2715
  if (!open) return;
2585
2716
  let closeOnEscape = (event) => {
2586
- event.key === "Escape" && setOpen(!1);
2717
+ if (event.key === "Escape") {
2718
+ if (devicesOpen) {
2719
+ event.stopPropagation(), setDevicesOpen(!1);
2720
+ return;
2721
+ }
2722
+ setOpen(!1);
2723
+ }
2587
2724
  };
2588
2725
  return window.addEventListener("keydown", closeOnEscape), () => window.removeEventListener("keydown", closeOnEscape);
2589
- }, [open]), React.useEffect(() => {
2726
+ }, [open, devicesOpen]), React.useEffect(() => {
2727
+ if (!devicesOpen) return;
2728
+ let closeOnPointer = (event) => {
2729
+ let target = event.target;
2730
+ target instanceof Element && target.closest(".dshRemoteConnectedMenu") === null && setDevicesOpen(!1);
2731
+ };
2732
+ return window.addEventListener("mousedown", closeOnPointer), () => window.removeEventListener("mousedown", closeOnPointer);
2733
+ }, [devicesOpen]), React.useEffect(() => {
2734
+ (status?.host?.connectedClients?.length ?? 0) === 0 && setDevicesOpen(!1);
2735
+ }, [status?.host?.connectedClients?.length]), React.useEffect(() => {
2590
2736
  props.control("status").then(setStatus).catch(() => {
2591
2737
  });
2592
2738
  }, []), React.useEffect(() => {
@@ -2727,7 +2873,16 @@ Minimum version required to store current data is: ` + bestVersion + `.
2727
2873
  }
2728
2874
  }, show = async () => {
2729
2875
  setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setOpen(!0), await refreshRemote();
2730
- }, chooseAnotherHost = () => {
2876
+ };
2877
+ React.useEffect(() => {
2878
+ if (!open || selectedHost !== void 0) return;
2879
+ let timer = window.setInterval(() => {
2880
+ props.control("status").then(setStatus).catch(() => {
2881
+ });
2882
+ }, 1500);
2883
+ return () => window.clearInterval(timer);
2884
+ }, [open, selectedHost]);
2885
+ let chooseAnotherHost = () => {
2731
2886
  setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
2732
2887
  }, signInClient = async () => {
2733
2888
  if (!(email.trim() === "" || password === "")) {
@@ -2789,7 +2944,54 @@ Minimum version required to store current data is: ` + bestVersion + `.
2789
2944
  formatPlatform(selectedHost.platform),
2790
2945
  selectedHost.harnessVersion === void 0 ? void 0 : t("harnessVersion", { version: selectedHost.harnessVersion }),
2791
2946
  selectedHost.clientVersion === void 0 ? void 0 : t("pluginVersion", { version: selectedHost.clientVersion })
2792
- ].filter(Boolean).join(" \xB7 ");
2947
+ ].filter(Boolean).join(" \xB7 "), connectedClients = status?.host?.connectedClients ?? [], connectedCount = connectedClients.length, connectedCountLabel = t("connectedClientCount", { count: connectedCount }), connectedMenu = !needsAuthorization && status?.hostAuthorizationAvailable === !0 ? React.createElement(
2948
+ "div",
2949
+ {
2950
+ className: `dshRemoteConnectedMenu${devicesOpen ? " isOpen" : ""}`
2951
+ },
2952
+ React.createElement("a", {
2953
+ href: connectedCount > 0 ? "#connected-devices" : void 0,
2954
+ className: `dshRemoteConnectedCount${connectedCount > 0 ? " isOnline isInteractive" : ""}`,
2955
+ "aria-expanded": connectedCount > 0 ? devicesOpen : void 0,
2956
+ "aria-haspopup": connectedCount > 0 ? "dialog" : void 0,
2957
+ title: connectedCountLabel,
2958
+ "aria-label": connectedCountLabel,
2959
+ onClick: (event) => {
2960
+ event.preventDefault(), connectedCount !== 0 && setDevicesOpen((current) => !current);
2961
+ }
2962
+ }, connectedCountLabel),
2963
+ devicesOpen && connectedCount > 0 ? React.createElement(
2964
+ "div",
2965
+ {
2966
+ className: "dshRemoteConnectedPanel",
2967
+ id: "connected-devices",
2968
+ role: "dialog",
2969
+ "aria-label": t("currentConnectedDevices")
2970
+ },
2971
+ React.createElement("strong", { className: "dshRemoteConnectedPanelTitle" }, t("currentConnectedDevices")),
2972
+ React.createElement(
2973
+ "div",
2974
+ { className: "dshRemoteClientList", "aria-label": t("currentConnectedDevices") },
2975
+ ...connectedClients.map((client) => React.createElement(
2976
+ "div",
2977
+ {
2978
+ key: client.deviceId,
2979
+ className: "dshRemoteClientRow"
2980
+ },
2981
+ React.createElement(
2982
+ "span",
2983
+ null,
2984
+ React.createElement("strong", null, client.name.trim() === "" ? t("unknownDevice") : client.name),
2985
+ React.createElement("small", null, [
2986
+ client.platform === void 0 ? void 0 : formatPlatform(client.platform),
2987
+ connectedClientModeLabel(client.mode, t)
2988
+ ].filter(Boolean).join(" \xB7 "))
2989
+ ),
2990
+ React.createElement("small", { className: "dshRemoteClientOnline" }, t("connected"))
2991
+ ))
2992
+ )
2993
+ ) : null
2994
+ ) : null;
2793
2995
  return React.createElement(
2794
2996
  React.Fragment,
2795
2997
  null,
@@ -3010,7 +3212,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
3010
3212
  className: "dshRemoteAccountExit",
3011
3213
  disabled: busy,
3012
3214
  onClick: () => void logoutRemote()
3013
- }, t("exitRemoteAccount"))
3215
+ }, t("exitRemoteAccount")),
3216
+ connectedMenu
3014
3217
  )
3015
3218
  ),
3016
3219
  React.createElement("div", { className: "dshRemoteHostList" }, devices.length === 0 ? React.createElement("p", null, t(busy ? "checkingConnection" : "noRemoteHosts")) : devices.map((device) => React.createElement(
@@ -3549,9 +3752,18 @@ Minimum version required to store current data is: ` + bestVersion + `.
3549
3752
  ".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)}",
3550
3753
  ".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}",
3551
3754
  ".dshRemotePageBody{padding:24px;overflow:auto;display:flex;flex-direction:column;gap:24px}.dshRemotePageBody button{font:inherit;color:inherit}",
3755
+ ".dshRemotePageTitleRow{display:flex;align-items:center;gap:10px;min-width:0}.dshRemotePageTitleRow>strong{min-width:0}",
3552
3756
  ".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}",
3757
+ ".dshRemoteSectionTitle{flex:1}.dshRemoteSectionTitle>.dshRemoteConnectedMenu{margin-left:auto}",
3758
+ '.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}',
3759
+ ".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)}",
3760
+ ".dshRemoteAcpCheckResult.isPassed,.dshRemoteAcpCheckResult.isFailed{color:var(--dsw-alias-label-secondary)}",
3761
+ ".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}",
3762
+ ".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)}",
3553
3763
  ".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}",
3554
3764
  ".dshRemoteHostList{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteHostList>button{min-height:58px;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>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}",
3765
+ '.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}',
3766
+ ".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}",
3555
3767
  '.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}}',
3556
3768
  '.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}',
3557
3769
  ".dshRemoteWorkspaceLists{overflow:visible}",
@@ -3687,7 +3899,10 @@ Minimum version required to store current data is: ` + bestVersion + `.
3687
3899
  }
3688
3900
  function formatPlatform(value) {
3689
3901
  let normalized = value.toLowerCase();
3690
- return normalized === "darwin" || normalized === "macos" ? "macOS" : normalized === "win32" || normalized === "windows" ? "Windows" : normalized === "linux" ? "Linux" : value;
3902
+ return normalized === "darwin" || normalized === "macos" ? "macOS" : normalized === "win32" || normalized === "windows" ? "Windows" : normalized === "linux" ? "Linux" : normalized === "android" ? "Android" : value;
3903
+ }
3904
+ function connectedClientModeLabel(mode, t) {
3905
+ return t(mode === "LAN" ? "remoteNetworkLan" : mode === "P2P" ? "remoteNetworkP2p" : mode === "TURN" ? "remoteNetworkTurn" : mode === "Relay" ? "remoteNetworkRelay" : "connected");
3691
3906
  }
3692
3907
  return module.exports.apply = apply, module.exports.inject = inject, module.exports;
3693
3908
  }