@blue-soda/dsh-remote 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,7 @@ Continue DeepSeek Harness sessions and experimental Codex workspaces from anothe
23
23
  Add the current package version to the `web` profile, then restart Harness:
24
24
 
25
25
  ```sh
26
- dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.3
26
+ dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.4
27
27
  ```
28
28
 
29
29
  ### dsh-TUI Host
@@ -31,7 +31,7 @@ dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.3
31
31
  Remote can also run as a Host in a terminal-only [dsh-TUI](https://github.com/ccch1mneyyy/dsh-TUI) profile:
32
32
 
33
33
  ```sh
34
- dsh plugin --profile dsh-tui add -w @blue-soda/dsh-remote@0.5.3
34
+ dsh plugin --profile dsh-tui add -w @blue-soda/dsh-remote@0.5.4
35
35
  ```
36
36
 
37
37
  After starting dsh-TUI, manage Remote with `/remote`, `/remote login`, `/remote status`, and `/remote logout`.
@@ -265,7 +265,7 @@
265
265
  reconnectingAction: "Reconnecting\u2026",
266
266
  reconnectStarted: "Reconnect requested.",
267
267
  connectionAuthorizationExpired: "Authorization expired. Sign in again to authorize this device.",
268
- connectionReplaced: "Another instance is using this Host identity. Stop it or use a separate DSH_HOME before reconnecting.",
268
+ connectionReplaced: "Another instance is using this Host identity. Standing by: retrying every five minutes, and taking over as soon as it leaves.",
269
269
  connectionCredentialsBusy: "Credential refresh is locked. Stop other instances. After a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again.",
270
270
  connectionDeviceRevoked: "This device was removed on the Server. Sign in again to add it back.",
271
271
  connectionOwnershipRequired: "The Server no longer recognizes this Host as an owned device.",
@@ -328,12 +328,12 @@
328
328
  exitRemote: "Exit",
329
329
  stopReconnecting: "Stop reconnecting",
330
330
  addRemoteWorkspace: "Add remote workspace",
331
- addCodexWorkspace: "Add CodeX workspace",
332
- noCodexWorkspaces: "No CodeX workspaces yet.",
331
+ addCodexWorkspace: "Add Codex workspace",
332
+ noCodexWorkspaces: "No Codex workspaces yet.",
333
333
  cancelAddWorkspace: "Cancel",
334
334
  confirmAddWorkspace: "Add and open",
335
335
  showAllWorkspaces: "Show all DSH workspaces",
336
- showAllCodexWorkspaces: "Show all CodeX workspaces",
336
+ showAllCodexWorkspaces: "Show all Codex workspaces",
337
337
  remoteModeDsh: "Remote DSH \xB7 ",
338
338
  remoteModeCodex: "Remote Codex \xB7 ",
339
339
  remoteNetworkP2p: "P2P",
@@ -430,7 +430,7 @@
430
430
  accountPasswordLogin: "Password",
431
431
  qrLoginExpired: "This QR code expired. Refresh it to continue.",
432
432
  refreshQrCode: "Refresh QR code",
433
- codexVirtualWorkspace: "CodeX virtual workspace",
433
+ codexVirtualWorkspace: "Codex virtual workspace",
434
434
  codexVirtualSessions: "Sessions"
435
435
  }, zh = {
436
436
  terminalRemote: "\u8FDC\u7A0B\u7EC8\u7AEF",
@@ -539,7 +539,7 @@
539
539
  reconnectingAction: "\u6B63\u5728\u91CD\u8FDE\u2026",
540
540
  reconnectStarted: "\u5DF2\u53D1\u8D77\u91CD\u8FDE\u3002",
541
541
  connectionAuthorizationExpired: "\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u4EE5\u91CD\u65B0\u6388\u6743\u6B64\u8BBE\u5907\u3002",
542
- connectionReplaced: "\u53E6\u4E00\u5B9E\u4F8B\u6B63\u5728\u4F7F\u7528\u6B64 Host \u8EAB\u4EFD\u3002\u8BF7\u505C\u6B62\u8BE5\u5B9E\u4F8B\uFF0C\u6216\u4F7F\u7528\u72EC\u7ACB\u7684 DSH_HOME \u540E\u91CD\u65B0\u8FDE\u63A5\u3002",
542
+ connectionReplaced: "\u53E6\u4E00\u5B9E\u4F8B\u6B63\u5728\u4F7F\u7528\u6B64 Host \u8EAB\u4EFD\u3002\u672C\u673A\u5DF2\u8FDB\u5165\u5F85\u547D\uFF1A\u6BCF 5 \u5206\u949F\u91CD\u8BD5\u4E00\u6B21\uFF0C\u5BF9\u65B9\u9000\u51FA\u540E\u4F1A\u81EA\u52A8\u63A5\u7BA1\u3002",
543
543
  connectionCredentialsBusy: "\u51ED\u636E\u5237\u65B0\u88AB\u9501\u5B9A\uFF0C\u8BF7\u505C\u6B62\u5176\u4ED6\u5B9E\u4F8B\u3002\u82E5\u6B64\u524D\u5F02\u5E38\u9000\u51FA\uFF0C\u8BF7\u505C\u6B62\u6240\u6709\u5B9E\u4F8B\u540E\u79FB\u9664 server-credentials.json.refresh-lock \u5E76\u91CD\u65B0\u6388\u6743\u3002",
544
544
  connectionDeviceRevoked: "\u6B64\u8BBE\u5907\u5DF2\u5728 Server \u4E0A\u88AB\u79FB\u9664\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u4EE5\u91CD\u65B0\u6DFB\u52A0\u3002",
545
545
  connectionOwnershipRequired: "Server \u5DF2\u4E0D\u518D\u5C06\u6B64 Host \u8BC6\u522B\u4E3A\u5F53\u524D\u8D26\u53F7\u7684\u8BBE\u5907\u3002",
@@ -602,12 +602,12 @@
602
602
  exitRemote: "\u9000\u51FA",
603
603
  stopReconnecting: "\u505C\u6B62\u91CD\u8FDE",
604
604
  addRemoteWorkspace: "\u6DFB\u52A0\u8FDC\u7A0B\u5DE5\u4F5C\u533A",
605
- addCodexWorkspace: "\u6DFB\u52A0 CodeX \u5DE5\u4F5C\u533A",
606
- noCodexWorkspaces: "\u8FD8\u6CA1\u6709 CodeX \u5DE5\u4F5C\u533A\u3002",
605
+ addCodexWorkspace: "\u6DFB\u52A0 Codex \u5DE5\u4F5C\u533A",
606
+ noCodexWorkspaces: "\u8FD8\u6CA1\u6709 Codex \u5DE5\u4F5C\u533A\u3002",
607
607
  cancelAddWorkspace: "\u53D6\u6D88",
608
608
  confirmAddWorkspace: "\u786E\u8BA4\u5E76\u6253\u5F00",
609
609
  showAllWorkspaces: "\u663E\u793A\u5168\u90E8 DSH \u5DE5\u4F5C\u533A",
610
- showAllCodexWorkspaces: "\u663E\u793A\u5168\u90E8 CodeX \u5DE5\u4F5C\u533A",
610
+ showAllCodexWorkspaces: "\u663E\u793A\u5168\u90E8 Codex \u5DE5\u4F5C\u533A",
611
611
  remoteModeDsh: "\u8FDC\u7A0BDSH \xB7 ",
612
612
  remoteModeCodex: "\u8FDC\u7A0BCodex \xB7 ",
613
613
  remoteNetworkP2p: "P2P",
@@ -704,7 +704,7 @@
704
704
  accountPasswordLogin: "\u8D26\u53F7\u5BC6\u7801",
705
705
  qrLoginExpired: "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002",
706
706
  refreshQrCode: "\u5237\u65B0\u4E8C\u7EF4\u7801",
707
- codexVirtualWorkspace: "CodeX \u5DE5\u4F5C\u533A",
707
+ codexVirtualWorkspace: "Codex \u5DE5\u4F5C\u533A",
708
708
  codexVirtualSessions: "Sessions"
709
709
  };
710
710
  function codexUnavailableKey(code) {
@@ -1410,7 +1410,12 @@
1410
1410
  );
1411
1411
  }
1412
1412
  function RemoteWorkspaceAction(props) {
1413
- 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([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [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), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
1413
+ let { t } = props, [open, setOpen] = React.useState(!1);
1414
+ React.useEffect(() => {
1415
+ open && props.control("settings.get").catch(() => {
1416
+ });
1417
+ }, [open]);
1418
+ let [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([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [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), authorizedOnce = React.useRef(!1), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
1414
1419
  isEnabledQrProvider(props.preferredQrProvider) ? props.preferredQrProvider : defaultQrProvider
1415
1420
  ), [qrSession, setQrSession] = 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), [confirmingSignOut, setConfirmingSignOut] = React.useState(!1), [confirmingRevoke, setConfirmingRevoke] = React.useState(!1), [error, setError] = React.useState(void 0);
1416
1421
  React.useEffect(() => {
@@ -1476,7 +1481,7 @@
1476
1481
  polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
1477
1482
  if (!(!active || settled || run !== qrFlowRun.current))
1478
1483
  if (result.status === "complete") {
1479
- settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
1484
+ settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), authorizedOnce.current = !0, setNeedsAuthorization(!1);
1480
1485
  try {
1481
1486
  let [nextDevices, nextStatus] = await Promise.all([
1482
1487
  props.control("devices"),
@@ -1514,7 +1519,12 @@
1514
1519
  targetDeviceId: host.deviceId
1515
1520
  }), codexReason, nextCodexWorkspaces = await props.control("codex.workspaces.list", {
1516
1521
  targetDeviceId: host.deviceId
1517
- }).catch((reason) => (codexReason = remoteErrorMessage(reason, t), [])), nextStatus = await props.control("status").catch(() => {
1522
+ }).catch(async (reason) => {
1523
+ let code = typeof reason?.code == "string" ? String(reason.code) : "";
1524
+ return ["TRANSPORT_CLOSED", "NOT_CONNECTED", "CONNECTION_FAILED", "RPC_TIMEOUT"].includes(code) ? await props.control("codex.workspaces.list", {
1525
+ targetDeviceId: host.deviceId
1526
+ }).catch((again) => (codexReason = remoteErrorMessage(again, t), [])) : (codexReason = remoteErrorMessage(reason, t), []);
1527
+ }), nextStatus = await props.control("status").catch(() => {
1518
1528
  });
1519
1529
  return nextStatus !== void 0 && setStatus(nextStatus), setCodexNotice(codexReason), { workspaces: nextWorkspaces, codexWorkspaces: nextCodexWorkspaces, status: nextStatus };
1520
1530
  },
@@ -1570,25 +1580,25 @@
1570
1580
  try {
1571
1581
  let nextStatus = await props.control("status");
1572
1582
  if (setStatus(nextStatus), !nextStatus.available) {
1573
- setDevices([]), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1583
+ setDevices([]), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1574
1584
  return;
1575
1585
  }
1576
1586
  let storedLocally;
1577
1587
  try {
1578
1588
  storedLocally = (await props.control("authorization.local"))?.stored === !0, setNeedsAuthorization(!storedLocally);
1579
1589
  } catch {
1580
- setNeedsAuthorization(!1);
1590
+ authorizedOnce.current = !0, setNeedsAuthorization(!1);
1581
1591
  } finally {
1582
1592
  setAuthorizationResolved(!0);
1583
1593
  }
1584
1594
  try {
1585
1595
  let nextDevices = await props.control("devices");
1586
- if (setDevices(nextDevices), storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
1596
+ if (setDevices(nextDevices), !authorizedOnce.current && storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
1587
1597
  let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
1588
1598
  nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
1589
1599
  }
1590
1600
  } catch {
1591
- setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1601
+ setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1592
1602
  }
1593
1603
  selectedHost !== void 0 && (await props.control("remote.session.recover").then((next) => setStatus(next)).catch(() => {
1594
1604
  }), await Promise.all([loadHarnessWorkspaces(selectedHost), loadCodexWorkspaces(selectedHost)]));
@@ -1599,6 +1609,17 @@
1599
1609
  }
1600
1610
  }, show = async () => {
1601
1611
  setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setOpen(!0), await refreshRemote();
1612
+ for (let attempt = 0; attempt < 10; attempt++) {
1613
+ let list = await props.control("devices").catch(() => {
1614
+ });
1615
+ if (list !== void 0) {
1616
+ setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), await refreshRemote();
1617
+ return;
1618
+ }
1619
+ await new Promise((resolve) => {
1620
+ setTimeout(resolve, 1e3);
1621
+ });
1622
+ }
1602
1623
  };
1603
1624
  React.useEffect(() => {
1604
1625
  if (!(!open || selectedHost !== void 0))
@@ -1624,7 +1645,22 @@
1624
1645
  }, [open, selectedHost]);
1625
1646
  let chooseAnotherHost = () => {
1626
1647
  setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCodexNotice(void 0), setCodexAvailable(!1), codexProbeAvailable.current = !1, setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
1627
- }, requestDeepSeekSignIn = async () => {
1648
+ }, signingIn = busy || status?.authorizing === !0 || needsAuthorization && status?.hasDeepSeekSession === !0;
1649
+ React.useEffect(() => {
1650
+ if (!signingIn) return;
1651
+ let tries = 0, timer = window.setInterval(() => {
1652
+ tries += 1, (async () => {
1653
+ let next = await props.control("status").catch(() => {
1654
+ });
1655
+ next !== void 0 && setStatus(next);
1656
+ let list = await props.control("devices").catch(() => {
1657
+ });
1658
+ list !== void 0 && (setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0));
1659
+ })(), tries >= 5 && window.clearInterval(timer);
1660
+ }, 1e3);
1661
+ return () => window.clearInterval(timer);
1662
+ }, [signingIn]);
1663
+ let requestDeepSeekSignIn = async () => {
1628
1664
  let transport = globalThis.__DSH_TRANSPORT__, callbackOrigin = transport?.streamBaseUrl !== void 0 ? new URL(transport.streamBaseUrl).origin : window.location.origin, result = await props.control("settings.configure", {
1629
1665
  // No `role`: a device has one identity, and the control writes only the Server address plus this
1630
1666
  // sign-in. Sending a role here was the last thing that made one look like a runtime switch.
@@ -1662,7 +1698,7 @@
1662
1698
  if (state.pending) throw new Error(t("deepseekSignInTimeout"));
1663
1699
  } else
1664
1700
  tab?.close();
1665
- setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
1701
+ setDevices(await props.control("devices")), setStatus(await props.control("status")), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
1666
1702
  } catch (reason) {
1667
1703
  setError(remoteErrorMessage(reason, t));
1668
1704
  } finally {
@@ -1687,7 +1723,7 @@
1687
1723
  }, revokeRemote = async () => {
1688
1724
  setBusy(!0), setError(void 0), setNotice(void 0);
1689
1725
  try {
1690
- await props.control("client.device.revoke"), setDevices([]), setNeedsAuthorization(!0), setStatus(await props.control("status"));
1726
+ await props.control("client.device.revoke"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setStatus(await props.control("status"));
1691
1727
  } catch (reason) {
1692
1728
  setError(remoteErrorMessage(reason, t));
1693
1729
  } finally {
@@ -1696,7 +1732,7 @@
1696
1732
  }, logoutRemote = async () => {
1697
1733
  setBusy(!0), setError(void 0), setNotice(void 0);
1698
1734
  try {
1699
- await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
1735
+ await props.control("settings.logout"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
1700
1736
  } catch (reason) {
1701
1737
  setError(remoteErrorMessage(reason, t));
1702
1738
  } finally {
@@ -1904,11 +1940,11 @@
1904
1940
  onClick: () => setEditingServerUrl(!0)
1905
1941
  }, loginServerUrl)
1906
1942
  ),
1907
- React.createElement(
1908
- "button",
1909
- { type: "button", disabled: busy || loginServerUrl.trim() === "", onClick: () => void signInClient() },
1910
- t(busy ? "signingIn" : "deepseekSignIn")
1911
- ),
1943
+ React.createElement("button", {
1944
+ type: "button",
1945
+ disabled: busy || signingIn || loginServerUrl.trim() === "",
1946
+ onClick: () => void signInClient()
1947
+ }, t(signingIn ? "signingIn" : "deepseekSignIn")),
1912
1948
  awaitingDeepSeek ? React.createElement(
1913
1949
  "p",
1914
1950
  { className: "dshRemoteServiceAddress" },
@@ -2219,7 +2255,7 @@
2219
2255
  )
2220
2256
  ),
2221
2257
  notice === void 0 ? null : React.createElement("p", { className: "dshRemoteNotice", role: "status" }, notice),
2222
- error === void 0 ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
2258
+ error === void 0 || error === codexNotice ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
2223
2259
  )
2224
2260
  )) : null
2225
2261
  );
package/dist/client.js CHANGED
@@ -265,7 +265,7 @@
265
265
  reconnectingAction: "Reconnecting\u2026",
266
266
  reconnectStarted: "Reconnect requested.",
267
267
  connectionAuthorizationExpired: "Authorization expired. Sign in again to authorize this device.",
268
- connectionReplaced: "Another instance is using this Host identity. Stop it or use a separate DSH_HOME before reconnecting.",
268
+ connectionReplaced: "Another instance is using this Host identity. Standing by: retrying every five minutes, and taking over as soon as it leaves.",
269
269
  connectionCredentialsBusy: "Credential refresh is locked. Stop other instances. After a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again.",
270
270
  connectionDeviceRevoked: "This device was removed on the Server. Sign in again to add it back.",
271
271
  connectionOwnershipRequired: "The Server no longer recognizes this Host as an owned device.",
@@ -328,12 +328,12 @@
328
328
  exitRemote: "Exit",
329
329
  stopReconnecting: "Stop reconnecting",
330
330
  addRemoteWorkspace: "Add remote workspace",
331
- addCodexWorkspace: "Add CodeX workspace",
332
- noCodexWorkspaces: "No CodeX workspaces yet.",
331
+ addCodexWorkspace: "Add Codex workspace",
332
+ noCodexWorkspaces: "No Codex workspaces yet.",
333
333
  cancelAddWorkspace: "Cancel",
334
334
  confirmAddWorkspace: "Add and open",
335
335
  showAllWorkspaces: "Show all DSH workspaces",
336
- showAllCodexWorkspaces: "Show all CodeX workspaces",
336
+ showAllCodexWorkspaces: "Show all Codex workspaces",
337
337
  remoteModeDsh: "Remote DSH \xB7 ",
338
338
  remoteModeCodex: "Remote Codex \xB7 ",
339
339
  remoteNetworkP2p: "P2P",
@@ -430,7 +430,7 @@
430
430
  accountPasswordLogin: "Password",
431
431
  qrLoginExpired: "This QR code expired. Refresh it to continue.",
432
432
  refreshQrCode: "Refresh QR code",
433
- codexVirtualWorkspace: "CodeX virtual workspace",
433
+ codexVirtualWorkspace: "Codex virtual workspace",
434
434
  codexVirtualSessions: "Sessions"
435
435
  }, zh = {
436
436
  terminalRemote: "\u8FDC\u7A0B\u7EC8\u7AEF",
@@ -539,7 +539,7 @@
539
539
  reconnectingAction: "\u6B63\u5728\u91CD\u8FDE\u2026",
540
540
  reconnectStarted: "\u5DF2\u53D1\u8D77\u91CD\u8FDE\u3002",
541
541
  connectionAuthorizationExpired: "\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u4EE5\u91CD\u65B0\u6388\u6743\u6B64\u8BBE\u5907\u3002",
542
- connectionReplaced: "\u53E6\u4E00\u5B9E\u4F8B\u6B63\u5728\u4F7F\u7528\u6B64 Host \u8EAB\u4EFD\u3002\u8BF7\u505C\u6B62\u8BE5\u5B9E\u4F8B\uFF0C\u6216\u4F7F\u7528\u72EC\u7ACB\u7684 DSH_HOME \u540E\u91CD\u65B0\u8FDE\u63A5\u3002",
542
+ connectionReplaced: "\u53E6\u4E00\u5B9E\u4F8B\u6B63\u5728\u4F7F\u7528\u6B64 Host \u8EAB\u4EFD\u3002\u672C\u673A\u5DF2\u8FDB\u5165\u5F85\u547D\uFF1A\u6BCF 5 \u5206\u949F\u91CD\u8BD5\u4E00\u6B21\uFF0C\u5BF9\u65B9\u9000\u51FA\u540E\u4F1A\u81EA\u52A8\u63A5\u7BA1\u3002",
543
543
  connectionCredentialsBusy: "\u51ED\u636E\u5237\u65B0\u88AB\u9501\u5B9A\uFF0C\u8BF7\u505C\u6B62\u5176\u4ED6\u5B9E\u4F8B\u3002\u82E5\u6B64\u524D\u5F02\u5E38\u9000\u51FA\uFF0C\u8BF7\u505C\u6B62\u6240\u6709\u5B9E\u4F8B\u540E\u79FB\u9664 server-credentials.json.refresh-lock \u5E76\u91CD\u65B0\u6388\u6743\u3002",
544
544
  connectionDeviceRevoked: "\u6B64\u8BBE\u5907\u5DF2\u5728 Server \u4E0A\u88AB\u79FB\u9664\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u4EE5\u91CD\u65B0\u6DFB\u52A0\u3002",
545
545
  connectionOwnershipRequired: "Server \u5DF2\u4E0D\u518D\u5C06\u6B64 Host \u8BC6\u522B\u4E3A\u5F53\u524D\u8D26\u53F7\u7684\u8BBE\u5907\u3002",
@@ -602,12 +602,12 @@
602
602
  exitRemote: "\u9000\u51FA",
603
603
  stopReconnecting: "\u505C\u6B62\u91CD\u8FDE",
604
604
  addRemoteWorkspace: "\u6DFB\u52A0\u8FDC\u7A0B\u5DE5\u4F5C\u533A",
605
- addCodexWorkspace: "\u6DFB\u52A0 CodeX \u5DE5\u4F5C\u533A",
606
- noCodexWorkspaces: "\u8FD8\u6CA1\u6709 CodeX \u5DE5\u4F5C\u533A\u3002",
605
+ addCodexWorkspace: "\u6DFB\u52A0 Codex \u5DE5\u4F5C\u533A",
606
+ noCodexWorkspaces: "\u8FD8\u6CA1\u6709 Codex \u5DE5\u4F5C\u533A\u3002",
607
607
  cancelAddWorkspace: "\u53D6\u6D88",
608
608
  confirmAddWorkspace: "\u786E\u8BA4\u5E76\u6253\u5F00",
609
609
  showAllWorkspaces: "\u663E\u793A\u5168\u90E8 DSH \u5DE5\u4F5C\u533A",
610
- showAllCodexWorkspaces: "\u663E\u793A\u5168\u90E8 CodeX \u5DE5\u4F5C\u533A",
610
+ showAllCodexWorkspaces: "\u663E\u793A\u5168\u90E8 Codex \u5DE5\u4F5C\u533A",
611
611
  remoteModeDsh: "\u8FDC\u7A0BDSH \xB7 ",
612
612
  remoteModeCodex: "\u8FDC\u7A0BCodex \xB7 ",
613
613
  remoteNetworkP2p: "P2P",
@@ -704,7 +704,7 @@
704
704
  accountPasswordLogin: "\u8D26\u53F7\u5BC6\u7801",
705
705
  qrLoginExpired: "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002",
706
706
  refreshQrCode: "\u5237\u65B0\u4E8C\u7EF4\u7801",
707
- codexVirtualWorkspace: "CodeX \u5DE5\u4F5C\u533A",
707
+ codexVirtualWorkspace: "Codex \u5DE5\u4F5C\u533A",
708
708
  codexVirtualSessions: "Sessions"
709
709
  };
710
710
  function codexUnavailableKey(code) {
@@ -1410,7 +1410,12 @@
1410
1410
  );
1411
1411
  }
1412
1412
  function RemoteWorkspaceAction(props) {
1413
- 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([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [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), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
1413
+ let { t } = props, [open, setOpen] = React.useState(!1);
1414
+ React.useEffect(() => {
1415
+ open && props.control("settings.get").catch(() => {
1416
+ });
1417
+ }, [open]);
1418
+ let [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([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [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), authorizedOnce = React.useRef(!1), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
1414
1419
  isEnabledQrProvider(props.preferredQrProvider) ? props.preferredQrProvider : defaultQrProvider
1415
1420
  ), [qrSession, setQrSession] = 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), [confirmingSignOut, setConfirmingSignOut] = React.useState(!1), [confirmingRevoke, setConfirmingRevoke] = React.useState(!1), [error, setError] = React.useState(void 0);
1416
1421
  React.useEffect(() => {
@@ -1476,7 +1481,7 @@
1476
1481
  polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
1477
1482
  if (!(!active || settled || run !== qrFlowRun.current))
1478
1483
  if (result.status === "complete") {
1479
- settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
1484
+ settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), authorizedOnce.current = !0, setNeedsAuthorization(!1);
1480
1485
  try {
1481
1486
  let [nextDevices, nextStatus] = await Promise.all([
1482
1487
  props.control("devices"),
@@ -1514,7 +1519,12 @@
1514
1519
  targetDeviceId: host.deviceId
1515
1520
  }), codexReason, nextCodexWorkspaces = await props.control("codex.workspaces.list", {
1516
1521
  targetDeviceId: host.deviceId
1517
- }).catch((reason) => (codexReason = remoteErrorMessage(reason, t), [])), nextStatus = await props.control("status").catch(() => {
1522
+ }).catch(async (reason) => {
1523
+ let code = typeof reason?.code == "string" ? String(reason.code) : "";
1524
+ return ["TRANSPORT_CLOSED", "NOT_CONNECTED", "CONNECTION_FAILED", "RPC_TIMEOUT"].includes(code) ? await props.control("codex.workspaces.list", {
1525
+ targetDeviceId: host.deviceId
1526
+ }).catch((again) => (codexReason = remoteErrorMessage(again, t), [])) : (codexReason = remoteErrorMessage(reason, t), []);
1527
+ }), nextStatus = await props.control("status").catch(() => {
1518
1528
  });
1519
1529
  return nextStatus !== void 0 && setStatus(nextStatus), setCodexNotice(codexReason), { workspaces: nextWorkspaces, codexWorkspaces: nextCodexWorkspaces, status: nextStatus };
1520
1530
  },
@@ -1570,25 +1580,25 @@
1570
1580
  try {
1571
1581
  let nextStatus = await props.control("status");
1572
1582
  if (setStatus(nextStatus), !nextStatus.available) {
1573
- setDevices([]), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1583
+ setDevices([]), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1574
1584
  return;
1575
1585
  }
1576
1586
  let storedLocally;
1577
1587
  try {
1578
1588
  storedLocally = (await props.control("authorization.local"))?.stored === !0, setNeedsAuthorization(!storedLocally);
1579
1589
  } catch {
1580
- setNeedsAuthorization(!1);
1590
+ authorizedOnce.current = !0, setNeedsAuthorization(!1);
1581
1591
  } finally {
1582
1592
  setAuthorizationResolved(!0);
1583
1593
  }
1584
1594
  try {
1585
1595
  let nextDevices = await props.control("devices");
1586
- if (setDevices(nextDevices), storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
1596
+ if (setDevices(nextDevices), !authorizedOnce.current && storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
1587
1597
  let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
1588
1598
  nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
1589
1599
  }
1590
1600
  } catch {
1591
- setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1601
+ setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
1592
1602
  }
1593
1603
  selectedHost !== void 0 && (await props.control("remote.session.recover").then((next) => setStatus(next)).catch(() => {
1594
1604
  }), await Promise.all([loadHarnessWorkspaces(selectedHost), loadCodexWorkspaces(selectedHost)]));
@@ -1599,6 +1609,17 @@
1599
1609
  }
1600
1610
  }, show = async () => {
1601
1611
  setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setOpen(!0), await refreshRemote();
1612
+ for (let attempt = 0; attempt < 10; attempt++) {
1613
+ let list = await props.control("devices").catch(() => {
1614
+ });
1615
+ if (list !== void 0) {
1616
+ setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), await refreshRemote();
1617
+ return;
1618
+ }
1619
+ await new Promise((resolve) => {
1620
+ setTimeout(resolve, 1e3);
1621
+ });
1622
+ }
1602
1623
  };
1603
1624
  React.useEffect(() => {
1604
1625
  if (!(!open || selectedHost !== void 0))
@@ -1624,7 +1645,22 @@
1624
1645
  }, [open, selectedHost]);
1625
1646
  let chooseAnotherHost = () => {
1626
1647
  setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCodexNotice(void 0), setCodexAvailable(!1), codexProbeAvailable.current = !1, setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
1627
- }, requestDeepSeekSignIn = async () => {
1648
+ }, signingIn = busy || status?.authorizing === !0 || needsAuthorization && status?.hasDeepSeekSession === !0;
1649
+ React.useEffect(() => {
1650
+ if (!signingIn) return;
1651
+ let tries = 0, timer = window.setInterval(() => {
1652
+ tries += 1, (async () => {
1653
+ let next = await props.control("status").catch(() => {
1654
+ });
1655
+ next !== void 0 && setStatus(next);
1656
+ let list = await props.control("devices").catch(() => {
1657
+ });
1658
+ list !== void 0 && (setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0));
1659
+ })(), tries >= 5 && window.clearInterval(timer);
1660
+ }, 1e3);
1661
+ return () => window.clearInterval(timer);
1662
+ }, [signingIn]);
1663
+ let requestDeepSeekSignIn = async () => {
1628
1664
  let transport = globalThis.__DSH_TRANSPORT__, callbackOrigin = transport?.streamBaseUrl !== void 0 ? new URL(transport.streamBaseUrl).origin : window.location.origin, result = await props.control("settings.configure", {
1629
1665
  // No `role`: a device has one identity, and the control writes only the Server address plus this
1630
1666
  // sign-in. Sending a role here was the last thing that made one look like a runtime switch.
@@ -1662,7 +1698,7 @@
1662
1698
  if (state.pending) throw new Error(t("deepseekSignInTimeout"));
1663
1699
  } else
1664
1700
  tab?.close();
1665
- setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
1701
+ setDevices(await props.control("devices")), setStatus(await props.control("status")), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
1666
1702
  } catch (reason) {
1667
1703
  setError(remoteErrorMessage(reason, t));
1668
1704
  } finally {
@@ -1687,7 +1723,7 @@
1687
1723
  }, revokeRemote = async () => {
1688
1724
  setBusy(!0), setError(void 0), setNotice(void 0);
1689
1725
  try {
1690
- await props.control("client.device.revoke"), setDevices([]), setNeedsAuthorization(!0), setStatus(await props.control("status"));
1726
+ await props.control("client.device.revoke"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setStatus(await props.control("status"));
1691
1727
  } catch (reason) {
1692
1728
  setError(remoteErrorMessage(reason, t));
1693
1729
  } finally {
@@ -1696,7 +1732,7 @@
1696
1732
  }, logoutRemote = async () => {
1697
1733
  setBusy(!0), setError(void 0), setNotice(void 0);
1698
1734
  try {
1699
- await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
1735
+ await props.control("settings.logout"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
1700
1736
  } catch (reason) {
1701
1737
  setError(remoteErrorMessage(reason, t));
1702
1738
  } finally {
@@ -1904,11 +1940,11 @@
1904
1940
  onClick: () => setEditingServerUrl(!0)
1905
1941
  }, loginServerUrl)
1906
1942
  ),
1907
- React.createElement(
1908
- "button",
1909
- { type: "button", disabled: busy || loginServerUrl.trim() === "", onClick: () => void signInClient() },
1910
- t(busy ? "signingIn" : "deepseekSignIn")
1911
- ),
1943
+ React.createElement("button", {
1944
+ type: "button",
1945
+ disabled: busy || signingIn || loginServerUrl.trim() === "",
1946
+ onClick: () => void signInClient()
1947
+ }, t(signingIn ? "signingIn" : "deepseekSignIn")),
1912
1948
  awaitingDeepSeek ? React.createElement(
1913
1949
  "p",
1914
1950
  { className: "dshRemoteServiceAddress" },
@@ -2219,7 +2255,7 @@
2219
2255
  )
2220
2256
  ),
2221
2257
  notice === void 0 ? null : React.createElement("p", { className: "dshRemoteNotice", role: "status" }, notice),
2222
- error === void 0 ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
2258
+ error === void 0 || error === codexNotice ? null : React.createElement("p", { className: "dshRemoteError", role: "alert" }, error)
2223
2259
  )
2224
2260
  )) : null
2225
2261
  );