ds-harness-remote 0.5.13 → 0.5.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.
@@ -1680,7 +1680,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
1680
1680
  enterRegistrationCode: "Enter the device authorization code.",
1681
1681
  enterAccountPassword: "Enter the Server account and password.",
1682
1682
  associationSaved: "Associated. Restart Harness to apply.",
1683
- signedOut: "Signed out. Restart Harness to disconnect this mode.",
1683
+ signedOut: "Signed out and disconnected from Remote.",
1684
1684
  remoteRequestFailed: "Remote mode request failed.",
1685
1685
  remoteControlUnavailable: "Remote plugin control is still starting. Restart DSH if it stays unavailable.",
1686
1686
  switchTarget: "Switch Local / Remote Harness target",
@@ -1873,6 +1873,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
1873
1873
  scanWithProvider: "Scan to continue with {provider}",
1874
1874
  loadingLoginProviders: "Loading sign-in methods\u2026",
1875
1875
  retryLoginProviders: "Retry loading sign-in methods",
1876
+ serverApplied: "Server address applied.",
1876
1877
  noLoginProviders: "QR sign-in is unavailable. Use email and password.",
1877
1878
  zhihuLogin: "Zhihu QR",
1878
1879
  scanWithGitHub: "Scan to continue with GitHub",
@@ -1950,7 +1951,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
1950
1951
  enterRegistrationCode: "\u8BF7\u8F93\u5165\u8BBE\u5907\u6388\u6743\u7801\u3002",
1951
1952
  enterAccountPassword: "\u8BF7\u8F93\u5165 Server \u8D26\u53F7\u548C\u5BC6\u7801\u3002",
1952
1953
  associationSaved: "\u5173\u8054\u6210\u529F\u3002\u91CD\u542F Harness \u540E\u751F\u6548\u3002",
1953
- signedOut: "\u5DF2\u9000\u51FA\u6388\u6743\u3002\u91CD\u542F Harness \u540E\u5C06\u65AD\u5F00\u6B64\u6A21\u5F0F\u3002",
1954
+ signedOut: "\u5DF2\u9000\u51FA\u8D26\u53F7\u5E76\u65AD\u5F00 Remote \u8FDE\u63A5\u3002",
1954
1955
  remoteRequestFailed: "\u8FDC\u7A0B\u6A21\u5F0F\u8BF7\u6C42\u5931\u8D25\u3002",
1955
1956
  remoteControlUnavailable: "Remote \u63D2\u4EF6\u63A7\u5236\u901A\u9053\u4ECD\u5728\u542F\u52A8\uFF1B\u5982\u679C\u4E00\u76F4\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u542F DSH\u3002",
1956
1957
  switchTarget: "\u5207\u6362\u672C\u5730\u6216\u8FDC\u7A0B Harness",
@@ -2143,6 +2144,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2143
2144
  scanWithProvider: "\u4F7F\u7528 {provider} \u626B\u7801\u767B\u5F55",
2144
2145
  loadingLoginProviders: "\u6B63\u5728\u83B7\u53D6\u767B\u5F55\u65B9\u5F0F\u2026",
2145
2146
  retryLoginProviders: "\u91CD\u65B0\u83B7\u53D6\u767B\u5F55\u65B9\u5F0F",
2147
+ serverApplied: "Server \u5730\u5740\u5DF2\u751F\u6548\u3002",
2146
2148
  noLoginProviders: "\u6682\u65E0\u53EF\u7528\u7684\u626B\u7801\u767B\u5F55\u65B9\u5F0F\uFF0C\u8BF7\u4F7F\u7528\u90AE\u7BB1\u548C\u5BC6\u7801\u3002",
2147
2149
  zhihuLogin: "\u77E5\u4E4E\u626B\u7801",
2148
2150
  scanWithGitHub: "\u4F7F\u7528 GitHub \u626B\u7801\u767B\u5F55",
@@ -2558,24 +2560,42 @@ Minimum version required to store current data is: ` + bestVersion + `.
2558
2560
  // src/client/settings.ts
2559
2561
  function createRemotePluginOptions(React) {
2560
2562
  function RemotePluginOptions(props) {
2561
- let { t } = props, [open, setOpen] = React.useState(props.view === "page"), [serverUrl, setServerUrl] = React.useState(""), [portsBusy, setPortsBusy] = React.useState(!1), [previewPorts, setPreviewPorts] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [terminalEnabled, setTerminalEnabled] = React.useState(!1), [terminalBusy, setTerminalBusy] = React.useState(!1), [acpBackends, setAcpBackends] = React.useState([]), [acpAvailability, setAcpAvailability] = React.useState({}), [acpChecking, setAcpChecking] = React.useState({}), [acpCheckResults, setAcpCheckResults] = React.useState({}), [addingAcp, setAddingAcp] = React.useState(!1), [acpName, setAcpName] = React.useState(""), [acpCommand, setAcpCommand] = React.useState(""), [acpArguments, setAcpArguments] = React.useState("acp"), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [hostName, setHostName] = React.useState(""), [hostDeviceId, setHostDeviceId] = React.useState(""), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyView = (view) => {
2562
- setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setTerminalEnabled(view.config.terminal?.enabled ?? !0), setPreviewPorts((view.config.loopback?.ports ?? []).join(", ")), setAcpBackends((view.config.acp?.backends ?? []).map((item) => ({ id: item.id, enabled: item.enabled !== !1 }))), setAcpAvailability(view.acpAvailability ?? {}), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
2563
+ let { t } = props, [open, setOpen] = React.useState(props.view === "page"), [serverUrl, setServerUrl] = React.useState(""), [portsBusy, setPortsBusy] = React.useState(!1), [previewPorts, setPreviewPorts] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [terminalEnabled, setTerminalEnabled] = React.useState(!1), [terminalBusy, setTerminalBusy] = React.useState(!1), [acpBackends, setAcpBackends] = React.useState([]), [acpAvailability, setAcpAvailability] = React.useState({}), [acpChecking, setAcpChecking] = React.useState({}), [acpCheckResults, setAcpCheckResults] = React.useState({}), [addingAcp, setAddingAcp] = React.useState(!1), [acpName, setAcpName] = React.useState(""), [acpCommand, setAcpCommand] = React.useState(""), [acpArguments, setAcpArguments] = React.useState("acp"), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [hostName, setHostName] = React.useState(""), [hostDeviceId, setHostDeviceId] = React.useState(""), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), associationReadRun = React.useRef(0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyAssociations = (view) => {
2564
+ setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association }));
2565
+ }, applyView = (view, updateAssociations = !0) => {
2566
+ setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setTerminalEnabled(view.config.terminal?.enabled ?? !0), setPreviewPorts((view.config.loopback?.ports ?? []).join(", ")), setAcpBackends((view.config.acp?.backends ?? []).map((item) => ({ id: item.id, enabled: item.enabled !== !1 }))), setAcpAvailability(view.acpAvailability ?? {}), updateAssociations && applyAssociations(view), setWritable(view.writable), setLoaded(!0);
2563
2567
  }, load = async () => {
2564
- let [view, status] = await Promise.all([
2568
+ let run = ++associationReadRun.current, [view, status] = await Promise.all([
2565
2569
  props.control("settings.get"),
2566
2570
  props.control("status").catch(() => {
2567
2571
  })
2568
2572
  ]);
2569
- applyView(view), setHostStatus(status?.host), setHostName(status?.deviceName ?? ""), setHostDeviceId(status?.host?.deviceId ?? "");
2573
+ applyView(view, run === associationReadRun.current), setHostStatus(status?.host), setHostName(status?.deviceName ?? ""), setHostDeviceId(status?.host?.deviceId ?? "");
2570
2574
  };
2571
2575
  React.useEffect(() => {
2572
2576
  load().catch((reason) => setError(messageOf(reason)));
2573
2577
  }, []), React.useEffect(() => {
2574
- if (association !== void 0)
2575
- return props.statusFeed.subscribe((status) => {
2576
- setHostStatus(status.host), setHostName(status.deviceName ?? ""), setHostDeviceId(status.host?.deviceId ?? "");
2578
+ let active = !0, authorizationKey, unsubscribe = props.statusFeed.subscribe((status) => {
2579
+ setHostStatus(status.host), setHostName(status.deviceName ?? ""), setHostDeviceId(status.host?.deviceId ?? "");
2580
+ let key = JSON.stringify([
2581
+ status.serverUrl,
2582
+ status.deviceId,
2583
+ status.host?.deviceId,
2584
+ status.host?.authorized,
2585
+ status.host?.account
2586
+ ]);
2587
+ if (key === authorizationKey) return;
2588
+ authorizationKey = key;
2589
+ let run = ++associationReadRun.current;
2590
+ props.control("settings.get").then((view) => {
2591
+ active && run === associationReadRun.current && applyAssociations(view);
2592
+ }).catch(() => {
2577
2593
  });
2578
- }, [association !== void 0]);
2594
+ });
2595
+ return () => {
2596
+ active = !1, unsubscribe();
2597
+ };
2598
+ }, [props.statusFeed]);
2579
2599
  let save = async (event) => {
2580
2600
  if (event?.preventDefault(), !(!writable || !serverDirty)) {
2581
2601
  setBusy(!0), setNotice(void 0), setError(void 0);
@@ -2583,7 +2603,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2583
2603
  let view = await props.control("settings.server.set", {
2584
2604
  serverUrl
2585
2605
  });
2586
- applyView(view), setNotice({ key: "serverSaved" });
2606
+ applyView(view), setNotice({ key: view.applies === "live" ? "serverApplied" : "serverSaved" });
2587
2607
  } catch (reason) {
2588
2608
  setError(messageOf(reason));
2589
2609
  } finally {
@@ -2591,10 +2611,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
2591
2611
  }
2592
2612
  }
2593
2613
  }, logout = async () => {
2614
+ let run = ++associationReadRun.current;
2594
2615
  setBusy(!0), setError(void 0), setNotice(void 0);
2595
2616
  try {
2596
2617
  let view = await props.control("settings.logout");
2597
- applyView(view), setRegistrationCode(""), setNotice({ key: "signedOut" });
2618
+ applyView(view, run === associationReadRun.current), setRegistrationCode(""), setNotice({ key: "signedOut" });
2598
2619
  } catch (reason) {
2599
2620
  setError(messageOf(reason));
2600
2621
  } finally {
@@ -3054,6 +3075,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3054
3075
  ".dshRemoteOpenBar{position:sticky;bottom:-96px;display:flex;align-items:center;justify-content:space-between;gap:20px;margin-top:20px;padding:14px 0;background:var(--dsw-alias-bg-layer-1);border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteOpenBar>div{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteOpenBar span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteOpenBar strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.dshRemoteOpenBar>button,.dshRemoteEnable>button{min-height:40px;flex:0 0 auto;border:0;border-radius:8px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-1);padding:8px 16px;cursor:pointer}.dshRemoteOpenBar>button:disabled,.dshRemoteEnable>button:disabled{opacity:.5;cursor:default}",
3055
3076
  ".dshRemoteEnable{box-sizing:border-box;width:min(440px,100%);max-width:100%;min-height:388px;margin:0 auto;display:flex;flex-direction:column;align-items:stretch;gap:10px}.dshRemoteEnable p{margin:0;color:var(--dsw-alias-label-secondary);line-height:1.5}",
3056
3077
  '.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}',
3078
+ ".dshRemoteLoginServer{width:100%;display:flex;flex-direction:column;gap:6px;margin:12px 0}.dshRemoteLoginServer>label{font-size:12px;color:var(--dsw-alias-label-secondary)}.dshRemoteLoginServer>div{display:flex;flex-wrap:wrap;gap:8px}.dshRemoteLoginServer input{box-sizing:border-box;flex:1 1 220px;min-width:0;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}.dshRemoteLoginServer button{flex:0 0 auto;min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:8px 12px;font:inherit;cursor:pointer}",
3057
3079
  ".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}",
3058
3080
  ".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}",
3059
3081
  ".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}",
@@ -3116,7 +3138,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3116
3138
  function createRemoteWorkspaceAction(React) {
3117
3139
  let RemoteProgressView = createRemoteProgressView(React);
3118
3140
  function RemoteWorkspaceAction(props) {
3119
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [cursorWorkspaces, setCursorWorkspaces] = React.useState([]), [antigravityWorkspaces, setAntigravityWorkspaces] = React.useState([]), [piWorkspaces, setPiWorkspaces] = React.useState([]), [opencodeWorkspaces, setOpencodeWorkspaces] = React.useState([]), [claudeWorkspaces, setClaudeWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [cursorWorkspaceId, setCursorWorkspaceId] = React.useState(void 0), [antigravityWorkspaceId, setAntigravityWorkspaceId] = React.useState(void 0), [piWorkspaceId, setPiWorkspaceId] = React.useState(void 0), [opencodeWorkspaceId, setOpencodeWorkspaceId] = React.useState(void 0), [claudeWorkspaceId, setClaudeWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), [showAllCursorWorkspaces, setShowAllCursorWorkspaces] = React.useState(!1), [showAllAntigravityWorkspaces, setShowAllAntigravityWorkspaces] = React.useState(!1), [showAllPiWorkspaces, setShowAllPiWorkspaces] = React.useState(!1), [showAllOpencodeWorkspaces, setShowAllOpencodeWorkspaces] = React.useState(!1), [showAllClaudeWorkspaces, setShowAllClaudeWorkspaces] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", cursorWorkspaceHeadingId = "dsh-remote-cursor-workspace-heading", cursorWorkspaceListId = "dsh-remote-cursor-workspace-list", antigravityWorkspaceHeadingId = "dsh-remote-antigravity-workspace-heading", piWorkspaceHeadingId = "dsh-remote-pi-workspace-heading", opencodeWorkspaceHeadingId = "dsh-remote-opencode-workspace-heading", claudeWorkspaceHeadingId = "dsh-remote-claude-workspace-heading", antigravityWorkspaceListId = "dsh-remote-antigravity-workspace-list", piWorkspaceListId = "dsh-remote-pi-workspace-list", opencodeWorkspaceListId = "dsh-remote-opencode-workspace-list", claudeWorkspaceListId = "dsh-remote-claude-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);
3141
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [cursorWorkspaces, setCursorWorkspaces] = React.useState([]), [antigravityWorkspaces, setAntigravityWorkspaces] = React.useState([]), [piWorkspaces, setPiWorkspaces] = React.useState([]), [opencodeWorkspaces, setOpencodeWorkspaces] = React.useState([]), [claudeWorkspaces, setClaudeWorkspaces] = React.useState([]), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [cursorWorkspaceId, setCursorWorkspaceId] = React.useState(void 0), [antigravityWorkspaceId, setAntigravityWorkspaceId] = React.useState(void 0), [piWorkspaceId, setPiWorkspaceId] = React.useState(void 0), [opencodeWorkspaceId, setOpencodeWorkspaceId] = React.useState(void 0), [claudeWorkspaceId, setClaudeWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), [showAllCursorWorkspaces, setShowAllCursorWorkspaces] = React.useState(!1), [showAllAntigravityWorkspaces, setShowAllAntigravityWorkspaces] = React.useState(!1), [showAllPiWorkspaces, setShowAllPiWorkspaces] = React.useState(!1), [showAllOpencodeWorkspaces, setShowAllOpencodeWorkspaces] = React.useState(!1), [showAllClaudeWorkspaces, setShowAllClaudeWorkspaces] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", cursorWorkspaceHeadingId = "dsh-remote-cursor-workspace-heading", cursorWorkspaceListId = "dsh-remote-cursor-workspace-list", antigravityWorkspaceHeadingId = "dsh-remote-antigravity-workspace-heading", piWorkspaceHeadingId = "dsh-remote-pi-workspace-heading", opencodeWorkspaceHeadingId = "dsh-remote-opencode-workspace-heading", claudeWorkspaceHeadingId = "dsh-remote-claude-workspace-heading", antigravityWorkspaceListId = "dsh-remote-antigravity-workspace-list", piWorkspaceListId = "dsh-remote-pi-workspace-list", opencodeWorkspaceListId = "dsh-remote-opencode-workspace-list", claudeWorkspaceListId = "dsh-remote-claude-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"), [savingServer, setSavingServer] = React.useState(!1), serverDirty = loginServerUrl.trim() !== (status?.serverUrl ?? ""), [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), providerRequestRun = React.useRef(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);
3120
3142
  React.useEffect(() => {
3121
3143
  open || (setDevicesOpen(!1), qrFlowRun.current += 1, setBusy(!1));
3122
3144
  }, [open]), React.useEffect(() => {
@@ -3144,7 +3166,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3144
3166
  props.control("status").then(setStatus).catch(() => {
3145
3167
  });
3146
3168
  }, []), React.useEffect(() => {
3147
- status?.serverUrl !== void 0 && loginServerUrl === "https://dsh.r2049.cn" && setLoginServerUrl(status.serverUrl);
3169
+ status?.serverUrl !== void 0 && setLoginServerUrl(status.serverUrl);
3148
3170
  }, [status?.serverUrl]), React.useEffect(() => {
3149
3171
  let remoteActive = status?.mode === "remote";
3150
3172
  return document.documentElement.classList.toggle("dshRemoteTargetActive", remoteActive), () => {
@@ -3169,10 +3191,10 @@ Minimum version required to store current data is: ` + bestVersion + `.
3169
3191
  }
3170
3192
  };
3171
3193
  React.useEffect(() => {
3172
- if (!open || !needsAuthorization) return;
3173
- let active = !0;
3194
+ if (!open || !needsAuthorization || savingServer || serverDirty) return;
3195
+ let active = !0, run = ++providerRequestRun.current;
3174
3196
  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) => {
3175
- if (!active) return;
3197
+ if (!active || run !== providerRequestRun.current) return;
3176
3198
  let available = items.filter((item) => item.qrStartUrl != null);
3177
3199
  setOAuthProviders(available), setLoginMethod((current) => {
3178
3200
  if (loginMethodManuallySelected.current && (current === "password" || available.some((item) => `oauth:${item.id}` === current))) return current;
@@ -3180,16 +3202,16 @@ Minimum version required to store current data is: ` + bestVersion + `.
3180
3202
  return preferred === void 0 ? "password" : `oauth:${preferred.id}`;
3181
3203
  });
3182
3204
  }).catch((reason) => {
3183
- active && (setProvidersFailed(!0), setLoginMethod("password"), setError(messageOf(reason)));
3205
+ !active || run !== providerRequestRun.current || (setProvidersFailed(!0), setLoginMethod("password"), setError(messageOf(reason)));
3184
3206
  }).finally(() => {
3185
- active && setProvidersLoading(!1);
3207
+ active && run === providerRequestRun.current && setProvidersLoading(!1);
3186
3208
  }), () => {
3187
3209
  active = !1;
3188
3210
  };
3189
- }, [open, needsAuthorization, status?.serverUrl, props.preferredQrProvider, providerReload]), React.useEffect(() => {
3190
- !open || !needsAuthorization || providersLoading || loginMethod === "password" || !oauthProviders.some((item) => `oauth:${item.id}` === loginMethod) || qrSession !== void 0 || qrExpired || startQrLogin(loginMethod.slice(6));
3191
- }, [open, needsAuthorization, providersLoading, oauthProviders, loginMethod, qrSession, qrExpired]), React.useEffect(() => {
3192
- if (!open || loginMethod === "password" || qrSession === void 0) return;
3211
+ }, [open, needsAuthorization, status?.serverUrl, props.preferredQrProvider, providerReload, savingServer, serverDirty]), React.useEffect(() => {
3212
+ !open || !needsAuthorization || savingServer || serverDirty || providersLoading || loginMethod === "password" || !oauthProviders.some((item) => `oauth:${item.id}` === loginMethod) || qrSession !== void 0 || qrExpired || startQrLogin(loginMethod.slice(6));
3213
+ }, [open, needsAuthorization, providersLoading, oauthProviders, loginMethod, qrSession, qrExpired, savingServer, serverDirty]), React.useEffect(() => {
3214
+ if (!open || savingServer || serverDirty || loginMethod === "password" || qrSession === void 0) return;
3193
3215
  let active = !0, polling = !1, settled = !1, run = qrFlowRun.current, timer, poll = () => {
3194
3216
  polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
3195
3217
  if (!(!active || settled || run !== qrFlowRun.current))
@@ -3216,7 +3238,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3216
3238
  return poll(), timer = window.setInterval(poll, 1500), () => {
3217
3239
  active = !1, timer !== void 0 && window.clearInterval(timer);
3218
3240
  };
3219
- }, [open, loginMethod, qrSession]);
3241
+ }, [open, loginMethod, qrSession, savingServer, serverDirty]);
3220
3242
  let selectLoginMethod = (method) => {
3221
3243
  loginMethodManuallySelected.current = !0, method !== loginMethod && (qrFlowRun.current += 1, setLoginMethod(method), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setError(void 0));
3222
3244
  }, 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", {
@@ -3332,8 +3354,26 @@ Minimum version required to store current data is: ` + bestVersion + `.
3332
3354
  }, [open, selectedHost]);
3333
3355
  let chooseAnotherHost = () => {
3334
3356
  setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setOpencodeWorkspaces([]), setClaudeWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setShowAllCursorWorkspaces(!1), setShowAllAntigravityWorkspaces(!1), setShowAllPiWorkspaces(!1), setShowAllOpencodeWorkspaces(!1), setShowAllClaudeWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setCursorWorkspaceId(void 0), setAntigravityWorkspaceId(void 0), setPiWorkspaceId(void 0), setOpencodeWorkspaceId(void 0), setClaudeWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
3357
+ }, resetLoginFlow = () => {
3358
+ providerRequestRun.current += 1, qrFlowRun.current += 1, setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setOAuthProviders([]), setProvidersFailed(!1), setProvidersLoading(!1), setLoginMethod("password"), loginMethodManuallySelected.current = !1, setPassword(""), setError(void 0), setNotice(void 0);
3359
+ }, saveLoginServer = async () => {
3360
+ if (!(loginServerUrl.trim() === "" || savingServer)) {
3361
+ resetLoginFlow(), setSavingServer(!0), setBusy(!0);
3362
+ try {
3363
+ if ((await props.control("settings.server.set", { serverUrl: loginServerUrl.trim() })).applies !== "live") {
3364
+ setNotice(t("serverSaved"));
3365
+ return;
3366
+ }
3367
+ let nextStatus = await props.control("status");
3368
+ setStatus(nextStatus), setLoginServerUrl(nextStatus.serverUrl ?? loginServerUrl.trim()), setProviderReload((value) => value + 1);
3369
+ } catch (reason) {
3370
+ setError(messageOf(reason));
3371
+ } finally {
3372
+ setSavingServer(!1), setBusy(!1);
3373
+ }
3374
+ }
3335
3375
  }, signInClient = async () => {
3336
- if (!(email.trim() === "" || password === "" || loginServerUrl.trim() === "")) {
3376
+ if (!(serverDirty || savingServer || email.trim() === "" || password === "" || loginServerUrl.trim() === "")) {
3337
3377
  setBusy(!0), setError(void 0);
3338
3378
  try {
3339
3379
  await props.control("settings.configure", {
@@ -3365,9 +3405,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
3365
3405
  setBusy(!1);
3366
3406
  }
3367
3407
  }, logoutRemote = async () => {
3368
- setBusy(!0), setError(void 0);
3408
+ qrFlowRun.current += 1, progressRun.current += 1, setBusy(!0), setError(void 0);
3369
3409
  try {
3370
- await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setStatus(await props.control("status"));
3410
+ await props.control("settings.logout"), setDevices([]), setSelectedHost(void 0), setConnectingHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCursorWorkspaces([]), setAntigravityWorkspaces([]), setPiWorkspaces([]), setOpencodeWorkspaces([]), setClaudeWorkspaces([]), setDirectory(void 0), setPath(""), setPassword(""), setProgress(void 0), setNeedsAuthorization(!0), setQrSession(void 0), setQrImage(void 0), setQrExpired(!1), setStatus(await props.control("status"));
3371
3411
  } catch (reason) {
3372
3412
  setError(messageOf(reason));
3373
3413
  } finally {
@@ -3566,6 +3606,36 @@ Minimum version required to store current data is: ` + bestVersion + `.
3566
3606
  React.createElement("strong", { className: "dshRemoteLoginTitle" }, t("signInClient")),
3567
3607
  React.createElement("span", null, t("signInClientDescription"))
3568
3608
  ),
3609
+ React.createElement(
3610
+ "form",
3611
+ {
3612
+ className: "dshRemoteLoginServer",
3613
+ onSubmit: (event) => {
3614
+ event.preventDefault(), saveLoginServer();
3615
+ }
3616
+ },
3617
+ React.createElement("label", { htmlFor: "dsh-remote-login-server" }, t("serverUrl")),
3618
+ React.createElement(
3619
+ "div",
3620
+ null,
3621
+ React.createElement("input", {
3622
+ id: "dsh-remote-login-server",
3623
+ type: "url",
3624
+ required: !0,
3625
+ value: loginServerUrl,
3626
+ disabled: busy || savingServer,
3627
+ autoComplete: "url",
3628
+ placeholder: t("serverUrl"),
3629
+ onChange: (event) => {
3630
+ resetLoginFlow(), setLoginServerUrl(event.target.value);
3631
+ }
3632
+ }),
3633
+ React.createElement("button", {
3634
+ type: "submit",
3635
+ disabled: busy || savingServer || loginServerUrl.trim() === ""
3636
+ }, t(savingServer ? "saving" : "save"))
3637
+ )
3638
+ ),
3569
3639
  React.createElement(
3570
3640
  "div",
3571
3641
  { className: "dshRemoteLoginTabs", role: "tablist" },
@@ -3577,18 +3647,12 @@ Minimum version required to store current data is: ` + bestVersion + `.
3577
3647
  "aria-selected": loginMethod === "password",
3578
3648
  "aria-controls": "dsh-remote-password-panel",
3579
3649
  className: loginMethod === "password" ? "isActive" : "",
3580
- disabled: busy,
3650
+ disabled: busy || savingServer || serverDirty,
3581
3651
  onClick: () => selectLoginMethod("password")
3582
3652
  }, t("accountPasswordLogin"))
3583
3653
  ),
3584
3654
  providersLoading ? React.createElement("p", { role: "status" }, t("loadingLoginProviders")) : null,
3585
- providersFailed ? React.createElement("button", {
3586
- type: "button",
3587
- onClick: () => {
3588
- setError(void 0), setProviderReload((value) => value + 1);
3589
- }
3590
- }, t("retryLoginProviders")) : null,
3591
- !providersLoading && !providersFailed && oauthProviders.length === 0 ? React.createElement("p", { role: "status" }, t("noLoginProviders")) : null,
3655
+ !savingServer && !serverDirty && !providersLoading && !providersFailed && oauthProviders.length === 0 ? React.createElement("p", { role: "status" }, t("noLoginProviders")) : null,
3592
3656
  loginMethod !== "password" && selectedProvider !== void 0 ? React.createElement(
3593
3657
  "div",
3594
3658
  {
@@ -3644,15 +3708,6 @@ Minimum version required to store current data is: ` + bestVersion + `.
3644
3708
  id: "dsh-remote-password-panel",
3645
3709
  "aria-labelledby": "dsh-remote-password-tab"
3646
3710
  },
3647
- React.createElement("input", {
3648
- type: "url",
3649
- value: loginServerUrl,
3650
- disabled: busy,
3651
- autoComplete: "url",
3652
- placeholder: t("serverUrl"),
3653
- "aria-label": t("serverUrl"),
3654
- onChange: (event) => setLoginServerUrl(event.target.value)
3655
- }),
3656
3711
  React.createElement("input", {
3657
3712
  type: "email",
3658
3713
  value: email,
@@ -3671,7 +3726,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3671
3726
  "aria-label": t("password"),
3672
3727
  onChange: (event) => setPassword(event.target.value)
3673
3728
  }),
3674
- React.createElement("button", { type: "button", disabled: busy || loginServerUrl.trim() === "" || email.trim() === "" || password === "", onClick: () => void signInClient() }, t(busy ? "signingIn" : "startSignIn"))
3729
+ React.createElement("button", { type: "button", disabled: busy || savingServer || serverDirty || loginServerUrl.trim() === "" || email.trim() === "" || password === "", onClick: () => void signInClient() }, t(busy ? "signingIn" : "startSignIn"))
3675
3730
  )
3676
3731
  ) : null,
3677
3732
  needsAuthorization ? null : React.createElement(