ds-harness-remote 0.4.1 → 0.4.3

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 (70) hide show
  1. package/README.md +35 -11
  2. package/cordis.patch.yml +3 -0
  3. package/dist/client-runtime.d.ts +28 -0
  4. package/dist/client-runtime.d.ts.map +1 -1
  5. package/dist/client-runtime.js +327 -5
  6. package/dist/client-runtime.js.map +1 -1
  7. package/dist/client-secure-transport.d.ts.map +1 -1
  8. package/dist/client-secure-transport.js +9 -2
  9. package/dist/client-secure-transport.js.map +1 -1
  10. package/dist/client.github.js +167 -48
  11. package/dist/client.js +167 -48
  12. package/dist/client.js.map +1 -1
  13. package/dist/codex/app-server.d.ts +71 -0
  14. package/dist/codex/app-server.d.ts.map +1 -0
  15. package/dist/codex/app-server.js +268 -0
  16. package/dist/codex/app-server.js.map +1 -0
  17. package/dist/codex/domain.d.ts +82 -0
  18. package/dist/codex/domain.d.ts.map +1 -0
  19. package/dist/codex/domain.js +893 -0
  20. package/dist/codex/domain.js.map +1 -0
  21. package/dist/codex/method-policy.d.ts +297 -0
  22. package/dist/codex/method-policy.d.ts.map +1 -0
  23. package/dist/codex/method-policy.js +103 -0
  24. package/dist/codex/method-policy.js.map +1 -0
  25. package/dist/codex/peer-bridge.d.ts +57 -0
  26. package/dist/codex/peer-bridge.d.ts.map +1 -0
  27. package/dist/codex/peer-bridge.js +300 -0
  28. package/dist/codex/peer-bridge.js.map +1 -0
  29. package/dist/codex/virtual-harness.d.ts +178 -0
  30. package/dist/codex/virtual-harness.d.ts.map +1 -0
  31. package/dist/codex/virtual-harness.js +2515 -0
  32. package/dist/codex/virtual-harness.js.map +1 -0
  33. package/dist/config.d.ts +10 -0
  34. package/dist/config.d.ts.map +1 -1
  35. package/dist/config.js +12 -0
  36. package/dist/config.js.map +1 -1
  37. package/dist/control-runtime.d.ts +1 -0
  38. package/dist/control-runtime.d.ts.map +1 -1
  39. package/dist/control-runtime.js +22 -0
  40. package/dist/control-runtime.js.map +1 -1
  41. package/dist/harness-remote-bridge.d.ts +2 -2
  42. package/dist/harness-remote-bridge.d.ts.map +1 -1
  43. package/dist/harness-remote-bridge.js +2 -2
  44. package/dist/harness-remote-bridge.js.map +1 -1
  45. package/dist/index.d.ts +11 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +8550 -3884
  48. package/dist/index.js.map +4 -4
  49. package/dist/remote-typert-gateway.d.ts +1 -1
  50. package/dist/remote-typert-gateway.d.ts.map +1 -1
  51. package/dist/remote-typert-gateway.js +9 -2
  52. package/dist/remote-typert-gateway.js.map +1 -1
  53. package/dist/rpc-router.d.ts +5 -2
  54. package/dist/rpc-router.d.ts.map +1 -1
  55. package/dist/rpc-router.js +30 -1
  56. package/dist/rpc-router.js.map +1 -1
  57. package/dist/server-connection.d.ts +1 -0
  58. package/dist/server-connection.d.ts.map +1 -1
  59. package/dist/server-connection.js +69 -22
  60. package/dist/server-connection.js.map +1 -1
  61. package/dist/service.d.ts +20 -0
  62. package/dist/service.d.ts.map +1 -1
  63. package/dist/service.js +58 -2
  64. package/dist/service.js.map +1 -1
  65. package/dist/typert-gateway-contract.d.ts +2 -2
  66. package/dist/typert-gateway-contract.d.ts.map +1 -1
  67. package/dist/version.d.ts +1 -1
  68. package/dist/version.js +1 -1
  69. package/package.json +19 -23
  70. package/public.d.ts +4 -0
@@ -1697,7 +1697,25 @@ Minimum version required to store current data is: ` + bestVersion + `.
1697
1697
  var CONTROL_RPC_PREFIX = "/ds-harness-remote";
1698
1698
 
1699
1699
  // src/client.ts
1700
- var clientModuleId = "ds-harness-remote", localeNamespace = "ds-harness-remote", en = {
1700
+ var clientModuleId = "ds-harness-remote", pendingWorkspaceSelectionKey = "dsh-remote:pending-workspace-selection";
1701
+ function storedWorkspaceSelection() {
1702
+ let raw = window.sessionStorage.getItem(pendingWorkspaceSelectionKey);
1703
+ if (raw !== null)
1704
+ try {
1705
+ let value = JSON.parse(raw);
1706
+ if (typeof value.targetDeviceId != "string" || typeof value.workspaceId != "string") throw new Error("invalid");
1707
+ if (value.backend !== void 0 && value.backend !== "harness" && value.backend !== "codex") throw new Error("invalid");
1708
+ if (value.sessionId !== void 0 && typeof value.sessionId != "string") throw new Error("invalid");
1709
+ return value;
1710
+ } catch {
1711
+ window.sessionStorage.removeItem(pendingWorkspaceSelectionKey);
1712
+ return;
1713
+ }
1714
+ }
1715
+ function workspacesReady(snapshot) {
1716
+ return snapshot.baselinesReady === !0 || snapshot.phase === "ready";
1717
+ }
1718
+ var localeNamespace = "ds-harness-remote", en = {
1701
1719
  pluginTitle: "DeepSeek Remote",
1702
1720
  pluginDescription: "Connect once. Available anytime.",
1703
1721
  expandSettings: "Show settings: {name}",
@@ -1724,6 +1742,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
1724
1742
  serverUrl: "Server URL",
1725
1743
  serverUrlHint: "HTTPS origin used for account authorization and encrypted relay.",
1726
1744
  serverSaved: "Server address saved. Restart DSH to apply it.",
1745
+ codexRemote: "Codex Remote",
1746
+ codexRemoteHint: "Expose Codex projects through this Host. Restart DSH after changing this setting.",
1747
+ codexSaved: "Codex Remote setting saved. Restart DSH to apply it.",
1727
1748
  authorizeFromRemote: "Sign in from the Remote entry in the sidebar, then return here to manage this device.",
1728
1749
  authorizationMethod: "Authorization method",
1729
1750
  accountPassword: "Account password",
@@ -1893,7 +1914,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
1893
1914
  currentServiceAddress: "Current service address:",
1894
1915
  accountPasswordLogin: "Password",
1895
1916
  qrLoginExpired: "This QR code expired. Refresh it to continue.",
1896
- refreshQrCode: "Refresh QR code"
1917
+ refreshQrCode: "Refresh QR code",
1918
+ codexVirtualWorkspace: "CodeX virtual workspace",
1919
+ codexVirtualSessions: "Sessions"
1897
1920
  }, zh = {
1898
1921
  pluginTitle: "DeepSeek \u8FDC\u7A0B\u8FDE\u63A5",
1899
1922
  pluginDescription: "\u4E00\u6B21\u8FDE\u63A5\uFF0C\u968F\u65F6\u53EF\u7528\u3002",
@@ -1921,6 +1944,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
1921
1944
  serverUrl: "Server \u5730\u5740",
1922
1945
  serverUrlHint: "\u7528\u4E8E\u8D26\u53F7\u6388\u6743\u548C\u52A0\u5BC6\u4E2D\u7EE7\u7684 HTTPS \u5730\u5740\u3002",
1923
1946
  serverSaved: "Server \u5730\u5740\u5DF2\u4FDD\u5B58\uFF0C\u91CD\u542F DSH \u540E\u751F\u6548\u3002",
1947
+ codexRemote: "Codex Remote",
1948
+ codexRemoteHint: "\u901A\u8FC7\u8FD9\u53F0 Host \u63D0\u4F9B Codex \u9879\u76EE\uFF1B\u4FEE\u6539\u540E\u9700\u91CD\u542F DSH \u751F\u6548\u3002",
1949
+ codexSaved: "Codex Remote \u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u91CD\u542F DSH \u540E\u751F\u6548\u3002",
1924
1950
  authorizeFromRemote: "\u8BF7\u4ECE\u4FA7\u680F Remote \u5165\u53E3\u767B\u5F55\uFF0C\u767B\u5F55\u540E\u53EF\u5728\u8FD9\u91CC\u7BA1\u7406\u5F53\u524D\u8BBE\u5907\u3002",
1925
1951
  authorizationMethod: "\u6388\u6743\u65B9\u5F0F",
1926
1952
  accountPassword: "\u8D26\u53F7\u5BC6\u7801",
@@ -2090,7 +2116,9 @@ Minimum version required to store current data is: ` + bestVersion + `.
2090
2116
  currentServiceAddress: "\u5F53\u524D\u670D\u52A1\u5730\u5740\uFF1A",
2091
2117
  accountPasswordLogin: "\u8D26\u53F7\u5BC6\u7801",
2092
2118
  qrLoginExpired: "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002",
2093
- refreshQrCode: "\u5237\u65B0\u4E8C\u7EF4\u7801"
2119
+ refreshQrCode: "\u5237\u65B0\u4E8C\u7EF4\u7801",
2120
+ codexVirtualWorkspace: "CodeX \u5DE5\u4F5C\u533A",
2121
+ codexVirtualSessions: "Sessions"
2094
2122
  }, defaultPreferredTransports = ["lan", "p2p", "turn", "relay"];
2095
2123
  function normalizedPreferredTransports(value) {
2096
2124
  return value === void 0 || value.length === 0 ? [...defaultPreferredTransports] : [...value];
@@ -2176,7 +2204,13 @@ Minimum version required to store current data is: ` + bestVersion + `.
2176
2204
  window.__ModuleLoader__.load({
2177
2205
  id: clientModuleId,
2178
2206
  factory: (require2) => {
2179
- let module = { exports: {} }, React = require2("react"), inject = ["connection", "slots", "locale", "workspaces", "sessions"];
2207
+ let module = { exports: {} }, React = require2("react"), inject = [
2208
+ "connection",
2209
+ "slots",
2210
+ "locale",
2211
+ "workspaces",
2212
+ "sessions"
2213
+ ];
2180
2214
  function RemoteProgressView(props) {
2181
2215
  let progress = props.progress;
2182
2216
  if (progress === void 0) return null;
@@ -2214,7 +2248,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2214
2248
  "aria-valuemax": 100,
2215
2249
  "aria-valuenow": percent,
2216
2250
  "aria-label": props.t(progress.label)
2217
- }, React.createElement("span", { style: { width: `${percent}%` } }))
2251
+ }, React.createElement("span", { style: { transform: `scaleX(${percent / 100})` } }))
2218
2252
  );
2219
2253
  }
2220
2254
  async function runRemoteProgress(steps, setProgress, progressRun, action, readyProgress) {
@@ -2237,8 +2271,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
2237
2271
  { label: "remoteProgressSwitchingWorkspace", detail: "remoteProgressSwitchingWorkspaceDetail", percent: 74, delayMs: 520 }
2238
2272
  ];
2239
2273
  function RemotePluginOptions(props) {
2240
- let { t } = props, [open, setOpen] = React.useState(!1), [serverUrl, setServerUrl] = 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), [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) => {
2241
- setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
2274
+ 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) => {
2275
+ 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);
2242
2276
  }, load = async () => {
2243
2277
  let [view, status] = await Promise.all([
2244
2278
  props.control("settings.get"),
@@ -2305,9 +2339,37 @@ Minimum version required to store current data is: ` + bestVersion + `.
2305
2339
  } finally {
2306
2340
  setBusy(!1);
2307
2341
  }
2342
+ }, setCodexRemote = async (enabled) => {
2343
+ let previous = codexEnabled;
2344
+ setCodexEnabled(enabled), setCodexBusy(!0), setError(void 0), setNotice(void 0);
2345
+ try {
2346
+ let view = await props.control("settings.codex.set", { enabled });
2347
+ applyView(view), setNotice({ key: "codexSaved" });
2348
+ } catch (reason) {
2349
+ setCodexEnabled(previous), setError(messageOf(reason));
2350
+ } finally {
2351
+ setCodexBusy(!1);
2352
+ }
2308
2353
  }, discard = () => {
2309
2354
  settingsView !== void 0 && applyView(settingsView), setRegistrationCode(""), setNotice(void 0), setError(void 0);
2310
- };
2355
+ }, codexSetting = React.createElement(
2356
+ "div",
2357
+ { className: "dshRemoteAuthorizationSetting" },
2358
+ React.createElement(
2359
+ "div",
2360
+ null,
2361
+ React.createElement("strong", null, t("codexRemote")),
2362
+ React.createElement("p", null, t("codexRemoteHint"))
2363
+ ),
2364
+ React.createElement("input", {
2365
+ type: "checkbox",
2366
+ role: "switch",
2367
+ disabled: busy || codexBusy || !writable,
2368
+ "aria-label": t("codexRemote"),
2369
+ checked: codexEnabled,
2370
+ onChange: (event) => void setCodexRemote(event.target.checked)
2371
+ })
2372
+ );
2311
2373
  return React.createElement(
2312
2374
  "li",
2313
2375
  { className: `dshRemotePluginCard${open ? " isOpen" : ""}` },
@@ -2369,6 +2431,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2369
2431
  }),
2370
2432
  React.createElement("p", null, t("serverUrlHint"))
2371
2433
  ),
2434
+ codexSetting,
2372
2435
  React.createElement(
2373
2436
  "div",
2374
2437
  { className: "dshRemoteAuthorizationSetting" },
@@ -2450,6 +2513,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2450
2513
  }),
2451
2514
  React.createElement("p", null, t("serverUrlHint"))
2452
2515
  ),
2516
+ codexSetting,
2453
2517
  React.createElement("p", { className: "dshRemoteSettingsState" }, t("authorizeFromRemote")),
2454
2518
  writable ? null : React.createElement("p", { className: "dshRemoteError" }, t("readOnly")),
2455
2519
  React.createElement(
@@ -2464,7 +2528,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2464
2528
  );
2465
2529
  }
2466
2530
  function RemoteWorkspaceAction(props) {
2467
- 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([]), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [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);
2531
+ 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), [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);
2468
2532
  React.useEffect(() => {
2469
2533
  if (!open) return;
2470
2534
  let closeOnEscape = (event) => {
@@ -2543,20 +2607,24 @@ Minimum version required to store current data is: ` + bestVersion + `.
2543
2607
  disabled: busy,
2544
2608
  onClick: () => selectLoginMethod(provider)
2545
2609
  }, t(provider === "github" ? "githubLogin" : "zhihuLogin")), selectHost = async (host) => {
2546
- setBusy(!0), setError(void 0);
2610
+ setBusy(!0), setError(void 0), setCodexWorkspaces([]);
2547
2611
  try {
2548
2612
  let result = await runRemoteProgress(
2549
2613
  connectHostProgressSteps(status?.preferredTransports),
2550
2614
  setProgress,
2551
2615
  progressRun,
2552
2616
  async () => {
2553
- let nextWorkspaces = await props.control("workspaces.list", { targetDeviceId: host.deviceId }), nextStatus = await props.control("status").catch(() => {
2617
+ let nextWorkspaces = await props.control("workspaces.list", {
2618
+ targetDeviceId: host.deviceId
2619
+ }), nextCodexWorkspaces = await props.control("codex.workspaces.list", {
2620
+ targetDeviceId: host.deviceId
2621
+ }).catch(() => []), nextStatus = await props.control("status").catch(() => {
2554
2622
  });
2555
- return nextStatus !== void 0 && setStatus(nextStatus), { workspaces: nextWorkspaces, status: nextStatus };
2623
+ return nextStatus !== void 0 && setStatus(nextStatus), { workspaces: nextWorkspaces, codexWorkspaces: nextCodexWorkspaces, status: nextStatus };
2556
2624
  },
2557
2625
  (result2) => connectedProgress(result2.status)
2558
2626
  );
2559
- setWorkspaces(result.workspaces), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2627
+ setWorkspaces(result.workspaces), setCodexWorkspaces(result.codexWorkspaces), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2560
2628
  } catch (reason) {
2561
2629
  setError(messageOf(reason));
2562
2630
  } finally {
@@ -2570,7 +2638,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2570
2638
  targetDeviceId: selectedHost.deviceId,
2571
2639
  ...nextPath === void 0 ? {} : { path: nextPath }
2572
2640
  });
2573
- setDirectory(listing), setPath(listing.path);
2641
+ setDirectory(listing), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(listing.path);
2574
2642
  } catch (reason) {
2575
2643
  setError(messageOf(reason));
2576
2644
  } finally {
@@ -2582,17 +2650,17 @@ Minimum version required to store current data is: ` + bestVersion + `.
2582
2650
  try {
2583
2651
  let nextStatus = await props.control("status");
2584
2652
  if (setStatus(nextStatus), !nextStatus.available) {
2585
- setDevices([]), setNeedsAuthorization(!1), setSelectedHost(void 0), setWorkspaces([]), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2653
+ setDevices([]), setNeedsAuthorization(!1), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2586
2654
  return;
2587
2655
  }
2588
2656
  try {
2589
2657
  let nextDevices = await props.control("devices");
2590
2658
  if (setDevices(nextDevices), setNeedsAuthorization(!1), selectedHost !== void 0) {
2591
2659
  let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
2592
- nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
2660
+ nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
2593
2661
  }
2594
2662
  } catch {
2595
- setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2663
+ setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2596
2664
  }
2597
2665
  } catch (reason) {
2598
2666
  setError(messageOf(reason));
@@ -2638,20 +2706,23 @@ Minimum version required to store current data is: ` + bestVersion + `.
2638
2706
  setBusy(!1);
2639
2707
  }
2640
2708
  }, openWorkspace = async () => {
2641
- if (!(selectedHost === void 0 || path.trim() === "")) {
2709
+ if (!(selectedHost === void 0 || workspaceBackend === "harness" && path.trim() === "" || workspaceBackend === "codex" && codexWorkspaceId === void 0)) {
2642
2710
  setBusy(!0), setError(void 0);
2643
2711
  try {
2644
2712
  let nextStatus = await runRemoteProgress(
2645
2713
  openWorkspaceProgressSteps,
2646
2714
  setProgress,
2647
2715
  progressRun,
2648
- () => props.control("workspace.open", {
2716
+ () => workspaceBackend === "codex" ? props.control("codex.workspace.open", {
2717
+ targetDeviceId: selectedHost.deviceId,
2718
+ workspaceId: codexWorkspaceId
2719
+ }) : props.control("workspace.open", {
2649
2720
  targetDeviceId: selectedHost.deviceId,
2650
2721
  path: path.trim()
2651
2722
  }),
2652
2723
  connectedProgress
2653
2724
  );
2654
- setStatus(nextStatus), window.location.reload();
2725
+ setStatus(nextStatus), nextStatus.workspaceSelection !== void 0 && window.sessionStorage.setItem(pendingWorkspaceSelectionKey, JSON.stringify(nextStatus.workspaceSelection)), window.location.reload();
2655
2726
  } catch (reason) {
2656
2727
  setError(messageOf(reason)), setBusy(!1);
2657
2728
  }
@@ -2873,7 +2944,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2873
2944
  React.createElement("button", {
2874
2945
  type: "button",
2875
2946
  onClick: () => {
2876
- setSelectedHost(void 0), setWorkspaces([]), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
2947
+ setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
2877
2948
  }
2878
2949
  }, t("backToHosts"))
2879
2950
  )
@@ -2927,22 +2998,56 @@ Minimum version required to store current data is: ` + bestVersion + `.
2927
2998
  }
2928
2999
  }, "+")
2929
3000
  ),
2930
- React.createElement("div", { className: "dshRemoteDirectoryList" }, workspaces.length === 0 ? React.createElement("p", null, t("noRemoteWorkspaces")) : workspaces.map((workspace) => React.createElement(
2931
- "button",
2932
- {
2933
- type: "button",
2934
- key: workspace.workspaceId,
2935
- disabled: busy,
2936
- className: !addingWorkspace && path === workspace.path ? "isSelected" : "",
2937
- "aria-pressed": !addingWorkspace && path === workspace.path,
2938
- onClick: () => {
2939
- setAddingWorkspace(!1), setPath(workspace.path);
2940
- }
2941
- },
2942
- React.createElement("span", { "aria-hidden": !0 }, "\u25B1"),
2943
- React.createElement("span", null, workspace.title),
2944
- React.createElement("small", null, workspace.path)
2945
- ))),
3001
+ React.createElement(
3002
+ "div",
3003
+ { className: "dshRemoteWorkspaceLists" },
3004
+ React.createElement("div", { className: "dshRemoteDirectoryList" }, workspaces.length === 0 ? React.createElement("p", null, t("noRemoteWorkspaces")) : workspaces.map((workspace) => React.createElement(
3005
+ "button",
3006
+ {
3007
+ type: "button",
3008
+ key: workspace.workspaceId,
3009
+ disabled: busy,
3010
+ className: workspaceBackend === "harness" && !addingWorkspace && path === workspace.path ? "isSelected" : "",
3011
+ "aria-pressed": workspaceBackend === "harness" && !addingWorkspace && path === workspace.path,
3012
+ onClick: () => {
3013
+ setAddingWorkspace(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(workspace.path);
3014
+ }
3015
+ },
3016
+ React.createElement("span", { "aria-hidden": !0 }, "\u25B1"),
3017
+ React.createElement("span", null, workspace.title),
3018
+ React.createElement("small", null, workspace.path)
3019
+ ))),
3020
+ codexWorkspaces.length === 0 ? null : React.createElement(
3021
+ React.Fragment,
3022
+ null,
3023
+ React.createElement(
3024
+ "div",
3025
+ { className: "dshRemoteWorkspaceSourceHeading" },
3026
+ React.createElement("strong", null, t("codexVirtualWorkspace")),
3027
+ React.createElement("small", null, t("codexVirtualSessions"))
3028
+ ),
3029
+ React.createElement(
3030
+ "div",
3031
+ { className: "dshRemoteDirectoryList dshRemoteCodexWorkspaceList" },
3032
+ codexWorkspaces.map((workspace) => React.createElement(
3033
+ "button",
3034
+ {
3035
+ type: "button",
3036
+ key: workspace.workspaceId,
3037
+ disabled: busy,
3038
+ className: workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId ? "isSelected" : "",
3039
+ "aria-pressed": workspaceBackend === "codex" && codexWorkspaceId === workspace.workspaceId,
3040
+ onClick: () => {
3041
+ setAddingWorkspace(!1), setWorkspaceBackend("codex"), setCodexWorkspaceId(workspace.workspaceId), setPath(workspace.path);
3042
+ }
3043
+ },
3044
+ React.createElement("span", { className: "dshRemoteCodexMark", "aria-hidden": !0 }, "C"),
3045
+ React.createElement("span", null, workspace.title),
3046
+ React.createElement("small", null, `${workspace.path} \xB7 ${workspace.sessionCount}`)
3047
+ ))
3048
+ )
3049
+ )
3050
+ ),
2946
3051
  addingWorkspace ? React.createElement(
2947
3052
  "div",
2948
3053
  { className: "dshRemoteFolderBrowser" },
@@ -2972,7 +3077,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
2972
3077
  "footer",
2973
3078
  { className: "dshRemoteOpenBar" },
2974
3079
  React.createElement("div", null, React.createElement("span", null, t("currentDirectory")), React.createElement("strong", null, path || "\u2014")),
2975
- React.createElement("button", { type: "button", disabled: busy || path.trim() === "", onClick: () => void openWorkspace() }, t(busy ? "openingWorkspace" : "openWorkspace"))
3080
+ React.createElement("button", {
3081
+ type: "button",
3082
+ disabled: busy || workspaceBackend === "harness" && path.trim() === "" || workspaceBackend === "codex" && codexWorkspaceId === void 0,
3083
+ onClick: () => void openWorkspace()
3084
+ }, t(busy ? "openingWorkspace" : "openWorkspace"))
2976
3085
  )
2977
3086
  )
2978
3087
  )
@@ -3149,7 +3258,10 @@ Minimum version required to store current data is: ` + bestVersion + `.
3149
3258
  }, []), React.useEffect(() => {
3150
3259
  if (status?.mode === "remote")
3151
3260
  return hideLocalSessionActions();
3152
- }, [status?.mode]), React.useEffect(() => {
3261
+ }, [status?.mode]), React.useEffect(() => (document.documentElement.classList.toggle(
3262
+ "dshRemoteCodexTargetActive",
3263
+ status?.mode === "remote" && status.backend === "codex"
3264
+ ), () => document.documentElement.classList.remove("dshRemoteCodexTargetActive")), [status?.mode, status?.backend]), React.useEffect(() => {
3153
3265
  if (!routeOpen) return;
3154
3266
  let closeOnEscape = (event) => {
3155
3267
  event.key === "Escape" && setRouteOpen(!1);
@@ -3311,6 +3423,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3311
3423
  let style = document.createElement("style");
3312
3424
  return style.dataset.pluginCss = "dsh-remote", style.textContent = [
3313
3425
  'html.dshRemoteTargetActive button[aria-label="\u6DFB\u52A0\u5DE5\u4F5C\u533A"],html.dshRemoteTargetActive button[aria-label="Add workspace"]{display:none!important}',
3426
+ 'html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="\u6307\u4EE4"],html.dshRemoteCodexTargetActive [data-composer-card] button[aria-haspopup="listbox"][aria-label="Commands"]{display:none!important}',
3314
3427
  "[data-dsh-remote-hidden-action]{display:none!important}",
3315
3428
  ".dshRemoteModeButton{min-height:36px;border:0;background:transparent;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;padding:0 10px;border-radius:8px}.dshRemoteModeButton:is(button){cursor:pointer}",
3316
3429
  ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
@@ -3326,9 +3439,11 @@ Minimum version required to store current data is: ` + bestVersion + `.
3326
3439
  ".dshRemoteSectionHeading>.dshRemoteAddWorkspace{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:50%;font-size:20px;line-height:1}.dshRemoteSectionHeading>.dshRemoteAddWorkspace:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
3327
3440
  ".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,.dshRemoteSelectedHost small{color:var(--dsw-alias-label-secondary);font-size:12px}",
3328
3441
  ".dshRemoteSelectedHost{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-layer-2)}",
3329
- ".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;height:100%;border-radius:inherit;background:var(--dsw-alias-brand-primary);transition:width .22s ease-out}.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}}",
3442
+ '.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}}',
3330
3443
  '.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}',
3331
- ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto 1fr;column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child{grid-row:1/3}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary);overflow:hidden;text-overflow:ellipsis}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3444
+ ".dshRemoteWorkspaceLists{max-height:min(360px,42vh);overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-label-tertiary) transparent}.dshRemoteWorkspaceLists::-webkit-scrollbar{width:8px}.dshRemoteWorkspaceLists::-webkit-scrollbar-thumb{border:2px solid transparent;border-radius:8px;background:var(--dsw-alias-label-tertiary);background-clip:padding-box}.dshRemoteWorkspaceLists::-webkit-scrollbar-track{background:transparent}",
3445
+ ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child{grid-row:1/3}.dshRemoteDirectoryList>button>span:not(:first-child),.dshRemoteDirectoryList>button>small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary)}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3446
+ ".dshRemoteWorkspaceSourceHeading{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:16px;padding:8px 4px 7px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteWorkspaceSourceHeading>strong{font-size:13px}.dshRemoteWorkspaceSourceHeading>small{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteCodexWorkspaceList{min-height:0}.dshRemoteCodexMark{box-sizing:border-box;width:22px;height:22px;display:grid;place-items:center;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}",
3332
3447
  ".dshRemoteFolderBrowser{margin-top:14px}.dshRemoteFolderBrowser>p,.dshRemoteFolderList>p{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}.dshRemoteFolderList{max-height:260px;overflow:auto;border-block:1px solid var(--dsw-alias-border-l2)}.dshRemoteFolderList>button{width:100%;min-height:42px;display:flex;align-items:center;gap:9px;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:7px 6px;text-align:left;cursor:pointer}.dshRemoteFolderList>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteFolderBrowser>small{display:block;margin-top:8px;color:var(--dsw-alias-state-warn-label)}",
3333
3448
  ".dshRemotePathField{display:flex;flex-direction:column;gap:6px;margin-top:20px}.dshRemotePathField>span{font-size:13px;font-weight:600}.dshRemotePathField>input{min-height:40px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);color:inherit;padding:0 12px;font:inherit}.dshRemotePathField>small{color:var(--dsw-alias-label-secondary)}",
3334
3449
  ".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}",
@@ -3382,21 +3497,25 @@ Minimum version required to store current data is: ` + bestVersion + `.
3382
3497
  return result.value;
3383
3498
  };
3384
3499
  ctx.effect(() => {
3385
- let disposed = !1, unsubscribe, selection, opening = !1, reconcile = () => {
3500
+ let disposed = !1, unsubscribeWorkspaces, unsubscribeSessions, selection, opening = !1, reconcile = () => {
3386
3501
  if (disposed || opening || selection === void 0) return;
3387
- let pending = selection, snapshot = ctx.workspaces.list.getSnapshot();
3388
- !snapshot.baselinesReady || !snapshot.items.some((workspace) => workspace.workspaceId === pending.workspaceId) || (opening = !0, unsubscribe?.(), unsubscribe = void 0, ctx.workspaces.connectWorkspace(pending.workspaceId).then(async (sessionId) => {
3389
- disposed || (ctx.sessions.open(sessionId), await control("workspace.selection.consume", pending).catch(() => {
3502
+ let pending = selection, workspaceSnapshot = ctx.workspaces.list.getSnapshot();
3503
+ if (!workspacesReady(workspaceSnapshot) || !workspaceSnapshot.items.some((workspace) => workspace.workspaceId === pending.workspaceId)) return;
3504
+ let sessionSnapshot = ctx.sessions.list.getSnapshot();
3505
+ if (pending.backend === "codex" && pending.sessionId !== void 0 && sessionSnapshot.phase !== "ready") return;
3506
+ opening = !0, unsubscribeWorkspaces?.(), unsubscribeSessions?.(), unsubscribeWorkspaces = void 0, unsubscribeSessions = void 0, (pending.backend === "codex" && pending.sessionId !== void 0 && sessionSnapshot.ids.includes(pending.sessionId) ? Promise.resolve(pending.sessionId) : ctx.workspaces.connectWorkspace(pending.workspaceId)).then(async (sessionId) => {
3507
+ disposed || (ctx.sessions.open(sessionId), window.sessionStorage.removeItem(pendingWorkspaceSelectionKey), await control("workspace.selection.consume", pending).catch(() => {
3390
3508
  }));
3391
3509
  }).catch((reason) => {
3392
3510
  disposed || console.warn("remote workspace selection failed:", reason);
3393
- }));
3511
+ });
3394
3512
  };
3395
3513
  return control("status").then((status) => {
3396
- disposed || status.mode !== "remote" || status.workspaceSelection === void 0 || status.target?.deviceId !== status.workspaceSelection.targetDeviceId || (selection = status.workspaceSelection, unsubscribe = ctx.workspaces.list.subscribe(reconcile), reconcile());
3514
+ let pending = status.workspaceSelection ?? storedWorkspaceSelection();
3515
+ disposed || status.mode !== "remote" || pending === void 0 || status.target?.deviceId !== pending.targetDeviceId || (selection = pending, unsubscribeWorkspaces = ctx.workspaces.list.subscribe(reconcile), unsubscribeSessions = ctx.sessions.list.subscribe(reconcile), reconcile());
3397
3516
  }).catch(() => {
3398
3517
  }), () => {
3399
- disposed = !0, unsubscribe?.();
3518
+ disposed = !0, unsubscribeWorkspaces?.(), unsubscribeSessions?.();
3400
3519
  };
3401
3520
  }, "ds-harness-remote: resume selected workspace"), ctx.inject(["fileViewer"], (fileViewerContext) => {
3402
3521
  let viewer = fileViewerContext.get("fileViewer");