@blue-soda/dsh-remote 0.5.1 → 0.5.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.
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.1
26
+ dsh plugin --profile web add -w @blue-soda/dsh-remote@0.5.3
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.1
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.1
34
+ dsh plugin --profile dsh-tui add -w @blue-soda/dsh-remote@0.5.3
35
35
  ```
36
36
 
37
37
  After starting dsh-TUI, manage Remote with `/remote`, `/remote login`, `/remote status`, and `/remote logout`.
@@ -2588,8 +2588,12 @@
2588
2588
  ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
2589
2589
  ".dshRemoteSidebarEntry{box-sizing:border-box;position:relative;min-width:0;display:block;overflow:hidden}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:100%;min-width:0}.dshRemoteSidebarEntry.isWide{width:calc(100% + 8px);height:34px;margin:4px -4px}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{height:34px;min-height:34px;padding:6px 48px 6px 10px;border-radius:12px}.dshRemoteSidebarEntry.isRail{width:36px;height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{width:36px;height:36px;min-height:36px;justify-content:center;gap:0;margin:8px 0 10px;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isActive .dshRemoteModeButton{color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteSidebarLabel{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteExitLink{position:absolute;top:50%;right:10px;transform:translateY(-50%);white-space:nowrap;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;font:inherit;font-size:12px;line-height:20px;cursor:pointer}.dshRemoteExitLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}",
2590
2590
  ".dshRemoteComputerIcon{box-sizing:border-box;width:18px;height:18px;flex:0 0 18px;color:var(--dsw-alias-label-secondary)}",
2591
- '.dshRemoteNetwork.isReconnecting{color:#f0a020;border-color:rgba(240,160,32,.55);cursor:pointer}.dshRemoteSessionHeader{position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap;overflow:hidden}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteModePrefix{flex:0 0 auto}.dshRemoteSessionTarget{flex:0 1 auto;min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
2592
- ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:auto;right:88px;transform:none;max-width:calc(100vw - 104px);padding:3px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteModePrefix,.dshRemoteEncrypted{display:none}.dshRemoteSessionTarget{max-width:min(30vw,150px)}}",
2591
+ '.dshRemoteNetwork.isReconnecting{color:#f0a020;border-color:rgba(240,160,32,.55);cursor:pointer}.dshRemoteSessionHeader{box-sizing:border-box;position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap;overflow:hidden}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteModePrefix{flex:0 0 auto}.dshRemoteSessionTarget{flex:0 1 auto;min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
2592
+ // Wide screens keep the pill beside the header's own right-hand controls. Narrow ones centre it on
2593
+ // screen: the harness collapses that row, so anchoring to the right left it visibly off-centre. Both
2594
+ // branches keep the same 28px *outer* height (the base rule is border-box) - the border and padding
2595
+ // here once grew the box to 36px, which dropped the text 4px below the header buttons' centre line.
2596
+ ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:50%;right:auto;transform:translateX(-50%);max-width:calc(100vw - 104px);padding:3px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteModePrefix,.dshRemoteEncrypted{display:none}.dshRemoteSessionTarget{max-width:min(30vw,150px)}}",
2593
2597
  ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
2594
2598
  ".dshRemotePage{width:min(720px,100%);max-height:min(760px,calc(100vh - 40px));display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;overflow:hidden;animation:dshRemotePageIn .18s cubic-bezier(.25,1,.5,1)}",
2595
2599
  ".dshRemotePageHeader{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:14px 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemotePageIntro{min-width:0;flex:1}.dshRemotePageHeader strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:18px;line-height:1.4}.dshRemotePageHeader p{min-width:0;max-width:70ch;margin:3px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.dshRemotePageActions{flex:0 0 auto;display:flex;align-items:center;gap:4px}.dshRemotePageActions>button{height:40px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:inherit;line-height:1;cursor:pointer}.dshRemotePageActions>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemotePageActions>button:disabled{opacity:.45;cursor:default}.dshRemotePageBack,.dshRemotePageRefresh{min-width:48px;padding:0 10px;font:inherit;font-size:13px}.dshRemotePageBack{color:var(--dsw-alias-label-secondary)!important}.dshRemotePageClose{width:40px;padding:0;font-size:24px}",
package/dist/client.js CHANGED
@@ -2588,8 +2588,12 @@
2588
2588
  ".dshRemoteModeButton:is(button):hover{background:var(--dsw-alias-interactive-bg-hover)}",
2589
2589
  ".dshRemoteSidebarEntry{box-sizing:border-box;position:relative;min-width:0;display:block;overflow:hidden}.dshRemoteSidebarEntry .dshRemoteModeButton{box-sizing:border-box;width:100%;min-width:0}.dshRemoteSidebarEntry.isWide{width:calc(100% + 8px);height:34px;margin:4px -4px}.dshRemoteSidebarEntry.isWide .dshRemoteModeButton{height:34px;min-height:34px;padding:6px 48px 6px 10px;border-radius:12px}.dshRemoteSidebarEntry.isRail{width:36px;height:54px}.dshRemoteSidebarEntry.isRail .dshRemoteModeButton{width:36px;height:36px;min-height:36px;justify-content:center;gap:0;margin:8px 0 10px;padding:0;border-radius:50%}.dshRemoteSidebarEntry.isActive .dshRemoteModeButton{color:var(--dsw-alias-label-secondary);background:transparent}.dshRemoteSidebarLabel{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dshRemoteExitLink{position:absolute;top:50%;right:10px;transform:translateY(-50%);white-space:nowrap;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:0;font:inherit;font-size:12px;line-height:20px;cursor:pointer}.dshRemoteExitLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteExitLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:2px}.dshRemoteExitLink:disabled{opacity:.45;cursor:default;text-decoration:none}",
2590
2590
  ".dshRemoteComputerIcon{box-sizing:border-box;width:18px;height:18px;flex:0 0 18px;color:var(--dsw-alias-label-secondary)}",
2591
- '.dshRemoteNetwork.isReconnecting{color:#f0a020;border-color:rgba(240,160,32,.55);cursor:pointer}.dshRemoteSessionHeader{position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap;overflow:hidden}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteModePrefix{flex:0 0 auto}.dshRemoteSessionTarget{flex:0 1 auto;min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
2592
- ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:auto;right:88px;transform:none;max-width:calc(100vw - 104px);padding:3px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteModePrefix,.dshRemoteEncrypted{display:none}.dshRemoteSessionTarget{max-width:min(30vw,150px)}}",
2591
+ '.dshRemoteNetwork.isReconnecting{color:#f0a020;border-color:rgba(240,160,32,.55);cursor:pointer}.dshRemoteSessionHeader{box-sizing:border-box;position:fixed;z-index:25;top:12px;left:50%;transform:translateX(-50%);max-width:calc(100vw - 360px);height:28px;display:inline-flex;align-items:center;gap:7px;color:var(--dsw-alias-label-secondary);font-size:12px;white-space:nowrap;overflow:hidden}.dshRemoteSessionHeader>svg{width:15px;height:15px;flex:0 0 auto}.dshRemoteModePrefix{flex:0 0 auto}.dshRemoteSessionTarget{flex:0 1 auto;min-width:0;max-width:260px;overflow:hidden;text-overflow:ellipsis}.dshRemoteNetwork{flex:0 0 auto;border:0;background:transparent;color:inherit;font:inherit;padding:3px 2px;display:inline-flex;align-items:center;gap:5px;cursor:pointer}.dshRemoteNetwork:hover:not(:disabled){color:var(--dsw-alias-label-primary);text-decoration:underline}.dshRemoteNetwork:disabled{cursor:default}.dshRemoteNetwork>i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork.isOnline>i{background:var(--dsw-alias-state-success-primary)}.dshRemoteNetwork.isOffline{color:var(--dsw-alias-state-error-primary)}.dshRemoteNetwork.isOffline>i{background:currentColor}.dshRemoteEncrypted{flex:0 0 auto;color:var(--dsw-alias-label-tertiary)}.dshRemoteNetwork:focus-visible,.dshRemoteRoutePanel>header button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.dshRemoteRouteBackdrop{position:fixed;inset:0;z-index:26}.dshRemoteRoutePanel{box-sizing:border-box;position:absolute;top:48px;right:28px;width:min(680px,calc(100vw - 32px));max-height:calc(100vh - 72px);overflow:auto;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;padding:16px;white-space:normal}.dshRemoteRoutePanel>header{position:sticky;top:-16px;z-index:1;display:flex;align-items:center;justify-content:space-between;margin:-16px -16px 0;padding:16px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteRoutePanel>header strong{font-size:14px}.dshRemoteRoutePanel>header button{width:28px;height:28px;border:0;border-radius:7px;background:transparent;color:inherit;font-size:20px;cursor:pointer}.dshRemoteRoutePanel>header button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteRoutePanel ol{display:flex;align-items:stretch;margin:12px 0 0;padding:0 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2);list-style:none}.dshRemoteRoutePanel li{position:relative;min-width:0;flex:1;display:flex;flex-direction:column;gap:4px;padding-right:20px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2192";position:absolute;right:7px;top:21px;color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li small{color:var(--dsw-alias-label-tertiary)}.dshRemoteRoutePanel li strong,.dshRemoteRoutePanel li span{overflow:hidden;text-overflow:ellipsis}.dshRemoteRoutePanel li strong{font-size:13px}.dshRemoteRoutePanel li span{color:var(--dsw-alias-label-secondary);font-size:11px}.dshRemoteRouteSection{padding-top:16px}.dshRemoteRouteSection h3{margin:0 0 10px;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}.dshRemoteRouteSection dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;margin:0}.dshRemoteRouteSection dl>div{min-width:0;display:grid;grid-template-columns:minmax(104px,auto) minmax(0,1fr);gap:10px;padding:7px 0;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:12px;line-height:1.45}.dshRemoteRouteSection dt{color:var(--dsw-alias-label-tertiary)}.dshRemoteRouteSection dd{min-width:0;margin:0;text-align:right;overflow-wrap:anywhere}.dshRemoteRouteSection dd.isMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px}.dshRemoteRoutePanel>p{margin:16px 0 0;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}@media(max-width:620px){.dshRemoteSessionHeader{top:8px;max-width:calc(100vw - 112px)}.dshRemoteSessionHeader>svg{display:none}.dshRemoteSessionTarget{max-width:130px}.dshRemoteEncrypted{display:none}.dshRemoteRoutePanel{top:42px;right:12px;max-height:calc(100vh - 56px)}.dshRemoteRoutePanel ol{flex-direction:column;gap:18px}.dshRemoteRoutePanel li:not(:last-child)::after{content:"\u2193";top:auto;right:auto;bottom:-16px;left:3px}.dshRemoteRouteSection dl{grid-template-columns:1fr}.dshRemoteRouteSection dl>div{grid-template-columns:1fr;gap:2px}.dshRemoteRouteSection dd{text-align:left}}',
2592
+ // Wide screens keep the pill beside the header's own right-hand controls. Narrow ones centre it on
2593
+ // screen: the harness collapses that row, so anchoring to the right left it visibly off-centre. Both
2594
+ // branches keep the same 28px *outer* height (the base rule is border-box) - the border and padding
2595
+ // here once grew the box to 36px, which dropped the text 4px below the header buttons' centre line.
2596
+ ".dshRemoteSessionHeader{left:auto;right:148px;transform:none;max-width:calc(100vw - 420px)}@media(max-width:760px){.dshRemoteSessionHeader{left:50%;right:auto;transform:translateX(-50%);max-width:calc(100vw - 104px);padding:3px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.dshRemoteModePrefix,.dshRemoteEncrypted{display:none}.dshRemoteSessionTarget{max-width:min(30vw,150px)}}",
2593
2597
  ".dshRemoteModeButton:focus-visible,.dshRemotePage button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}",
2594
2598
  ".dshRemotePage{width:min(720px,100%);max-height:min(760px,calc(100vh - 40px));display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;overflow:hidden;animation:dshRemotePageIn .18s cubic-bezier(.25,1,.5,1)}",
2595
2599
  ".dshRemotePageHeader{min-height:72px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:14px 24px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dshRemotePageIntro{min-width:0;flex:1}.dshRemotePageHeader strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:18px;line-height:1.4}.dshRemotePageHeader p{min-width:0;max-width:70ch;margin:3px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.dshRemotePageActions{flex:0 0 auto;display:flex;align-items:center;gap:4px}.dshRemotePageActions>button{height:40px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:inherit;line-height:1;cursor:pointer}.dshRemotePageActions>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemotePageActions>button:disabled{opacity:.45;cursor:default}.dshRemotePageBack,.dshRemotePageRefresh{min-width:48px;padding:0 10px;font:inherit;font-size:13px}.dshRemotePageBack{color:var(--dsw-alias-label-secondary)!important}.dshRemotePageClose{width:40px;padding:0;font-size:24px}",
package/dist/index.js CHANGED
@@ -13162,7 +13162,7 @@ function fromBase64Url2(value) {
13162
13162
  import { platform } from "node:os";
13163
13163
 
13164
13164
  // src/server-credentials.ts
13165
- import { chmod, mkdir, readFile, rm as rm2, stat as stat2, writeFile } from "node:fs/promises";
13165
+ import { chmod, mkdir, readFile, rename as rename2, rm as rm2, stat as stat2, writeFile } from "node:fs/promises";
13166
13166
  import { dirname, join as join2 } from "node:path";
13167
13167
 
13168
13168
  // src/atomic-file.ts
@@ -13237,6 +13237,11 @@ function uuidV7(now = Date.now()) {
13237
13237
  }
13238
13238
 
13239
13239
  // src/server-credentials.ts
13240
+ var LOCK_ABANDONED_MS = 10 * 6e4;
13241
+ var lockOwnerSchema = external_exports.object({
13242
+ pid: external_exports.number().int().positive(),
13243
+ at: external_exports.number().int().nonnegative()
13244
+ });
13240
13245
  var credentialSchema = external_exports.object({
13241
13246
  schemaVersion: external_exports.literal(1),
13242
13247
  serverUrl: external_exports.string().url(),
@@ -13254,8 +13259,13 @@ var ServerCredentialStore = class {
13254
13259
  this.path = join2(directory, "server-credentials.json");
13255
13260
  }
13256
13261
  /** Serialize the complete read/refresh/write transaction across processes.
13257
- * Never steal an old lock: a suspended owner may still consume a one-use token.
13258
- * After a crash, stop all instances before removing the orphaned lock.
13262
+ *
13263
+ * A lock left by a process that no longer exists can never be released by that process, and being killed
13264
+ * mid-refresh is routine on a phone (the app is backgrounded or swept away) - the old rule then left the user
13265
+ * with `SERVER_CREDENTIALS_BUSY` forever and told them to delete a file they cannot reach. So the lock now
13266
+ * records its owner and a contender reclaims it when that owner is **gone**. Liveness is what is checked, not
13267
+ * age: an owner that is merely suspended still protects its one-use refresh token, which is exactly what the
13268
+ * old unconditional rule was guarding against.
13259
13269
  */
13260
13270
  async withRefreshLock(operation) {
13261
13271
  const lock = `${this.path}.refresh-lock`;
@@ -13263,10 +13273,11 @@ var ServerCredentialStore = class {
13263
13273
  const deadline = Date.now() + 15e3;
13264
13274
  for (; ; ) {
13265
13275
  try {
13266
- await mkdir(lock, { mode: 448 });
13276
+ await claimRefreshLock(lock);
13267
13277
  break;
13268
13278
  } catch (error) {
13269
13279
  if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") throw error;
13280
+ if (await reclaimAbandonedRefreshLock(lock)) continue;
13270
13281
  if (Date.now() >= deadline) throw new ServerCredentialsBusyError();
13271
13282
  await new Promise((resolve4) => setTimeout(resolve4, 50));
13272
13283
  }
@@ -13274,7 +13285,7 @@ var ServerCredentialStore = class {
13274
13285
  try {
13275
13286
  return await operation();
13276
13287
  } finally {
13277
- await rm2(lock, { recursive: true });
13288
+ await rm2(lock, { recursive: true, force: true });
13278
13289
  }
13279
13290
  }
13280
13291
  async load(serverUrl, deviceId) {
@@ -13307,6 +13318,49 @@ var ServerCredentialsBusyError = class extends Error {
13307
13318
  super("Credential refresh is locked. Stop other instances; after a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again.");
13308
13319
  }
13309
13320
  };
13321
+ async function claimRefreshLock(lock) {
13322
+ await mkdir(lock, { mode: 448 });
13323
+ await writeFile(join2(lock, "owner.json"), `${JSON.stringify({ pid: process.pid, at: Date.now() })}
13324
+ `, {
13325
+ encoding: "utf8",
13326
+ mode: 384
13327
+ });
13328
+ }
13329
+ async function reclaimAbandonedRefreshLock(lock) {
13330
+ const owner = await readRefreshLockOwner(lock);
13331
+ const abandoned = owner === void 0 ? await olderThan(lock, LOCK_ABANDONED_MS) : !processAlive(owner.pid);
13332
+ if (!abandoned) return false;
13333
+ const tomb = `${lock}.${process.pid}.${uuidV7()}.abandoned`;
13334
+ try {
13335
+ await rename2(lock, tomb);
13336
+ } catch {
13337
+ return false;
13338
+ }
13339
+ await rm2(tomb, { recursive: true, force: true });
13340
+ return true;
13341
+ }
13342
+ async function readRefreshLockOwner(lock) {
13343
+ try {
13344
+ return lockOwnerSchema.parse(JSON.parse(await readFile(join2(lock, "owner.json"), "utf8")));
13345
+ } catch {
13346
+ return void 0;
13347
+ }
13348
+ }
13349
+ function processAlive(pid) {
13350
+ try {
13351
+ process.kill(pid, 0);
13352
+ return true;
13353
+ } catch (error) {
13354
+ return !(error instanceof Error && "code" in error && error.code === "ESRCH");
13355
+ }
13356
+ }
13357
+ async function olderThan(path, ageMs) {
13358
+ try {
13359
+ return Date.now() - (await stat2(path)).mtimeMs > ageMs;
13360
+ } catch {
13361
+ return false;
13362
+ }
13363
+ }
13310
13364
  async function atomicWrite(path, contents) {
13311
13365
  const directory = dirname(path);
13312
13366
  await mkdir(directory, { recursive: true, mode: 448 });
@@ -13462,7 +13516,7 @@ function normalizeServerUrl(value) {
13462
13516
  }
13463
13517
 
13464
13518
  // src/version.ts
13465
- var PLUGIN_VERSION = "0.5.1";
13519
+ var PLUGIN_VERSION = "0.5.3";
13466
13520
 
13467
13521
  // src/server-api.ts
13468
13522
  var ENABLED_QR_PROVIDERS = ["github"];
@@ -20291,8 +20345,12 @@ var TypertGatewaySwitch = class {
20291
20345
  installed = false;
20292
20346
  /** Defaults to reachable so a caller that never wires this keeps the old behaviour. */
20293
20347
  remoteAvailability = () => true;
20294
- constructor(gateway) {
20348
+ /** Supplies the peer carrier calls speak for; see {@link ownerPeer}. */
20349
+ peerFor;
20350
+ peer;
20351
+ constructor(gateway, options = {}) {
20295
20352
  this.runtime = gateway;
20353
+ this.peerFor = options.peer;
20296
20354
  this.originalInvoke = gateway.invoke;
20297
20355
  this.localInvoke = this.originalInvoke.bind(gateway);
20298
20356
  this.originalStream = gateway.stream;
@@ -20300,18 +20358,42 @@ var TypertGatewaySwitch = class {
20300
20358
  this.originalDispatch = this.runtime.dispatchRpc;
20301
20359
  this.localDispatch = this.runtime.dispatchRpc?.bind(gateway);
20302
20360
  this.originalOpen = this.runtime.openWireStream;
20303
- this.localOpen = createLocalOpen(gateway, this.runtime);
20361
+ this.localOpen = createLocalOpen(gateway, this.runtime, () => this.ownerPeer());
20362
+ }
20363
+ /**
20364
+ * The peer a carrier call speaks for, created once and reused.
20365
+ *
20366
+ * dsh 0.2.1-rc.2 reads `peer.signal` on every carrier call and rejects one that arrives without a peer; a remote
20367
+ * client runs with the Host owner's authority (decided 2026-10-19), which is the same principal dsh gives its own
20368
+ * browser peer, so the plugin serves remote calls as the owner. Releases before rc.2 ignore the argument, and a
20369
+ * profile without a `connection` service simply has no peer to offer.
20370
+ */
20371
+ ownerPeer() {
20372
+ if (this.peer !== void 0) return this.peer;
20373
+ this.peer = this.peerFor?.();
20374
+ return this.peer;
20375
+ }
20376
+ /** Trailing argument the carrier wants when the caller did not supply one. */
20377
+ peerArguments() {
20378
+ const peer = this.ownerPeer();
20379
+ return peer === void 0 ? [] : [peer];
20304
20380
  }
20305
20381
  /** Original local dispatcher, used by the Host bridge without switch recursion. */
20306
20382
  local() {
20307
- const dispatch = this.localDispatch ?? (async (endpoint, payload, signal) => {
20383
+ const bare = this.localDispatch;
20384
+ const dispatch = bare === void 0 ? (async (endpoint, payload, signal) => {
20308
20385
  try {
20309
20386
  const request = requestFromCarrier(endpoint, payload, signal);
20310
20387
  return { ok: true, value: await this.localInvoke(request) };
20311
20388
  } catch (error) {
20312
20389
  return { ok: false, error: this.failure(error) };
20313
20390
  }
20314
- });
20391
+ }) : (endpoint, payload, signal, ...rest) => Promise.resolve(bare(
20392
+ endpoint,
20393
+ payload,
20394
+ signal,
20395
+ ...rest.length === 0 ? this.peerArguments() : rest
20396
+ ));
20315
20397
  const open = this.localOpen ?? (async (endpoint, payload, signal) => {
20316
20398
  if (this.localStream === void 0) throw new Error("The local Harness Gateway does not support Remote streams.");
20317
20399
  return this.localStream(requestFromCarrier(endpoint, payload, signal));
@@ -20346,17 +20428,17 @@ var TypertGatewaySwitch = class {
20346
20428
  );
20347
20429
  }
20348
20430
  if (previousDispatch !== void 0) {
20349
- this.runtime.dispatchRpc = (endpoint, payload, signal) => forwards(endpoint) ? Promise.resolve(previousDispatch(endpoint, payload, signal)).catch((error) => {
20431
+ this.runtime.dispatchRpc = (endpoint, payload, signal, ...rest) => forwards(endpoint) ? Promise.resolve(previousDispatch(endpoint, payload, signal, ...rest)).catch((error) => {
20350
20432
  console.warn("[dsh-remote] local call failed with no remote target selected", {
20351
20433
  endpoint,
20352
20434
  code: typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0,
20353
20435
  message: error instanceof Error ? error.message : String(error)
20354
20436
  });
20355
20437
  throw error;
20356
- }) : !this.routesToRemote(endpoint) ? this.localDispatch(endpoint, payload, signal) : this.withLocalFallback(
20438
+ }) : !this.routesToRemote(endpoint) ? this.localDispatch(endpoint, payload, signal, ...rest) : this.withLocalFallback(
20357
20439
  endpoint,
20358
20440
  () => Promise.resolve(this.remoteTarget.dispatch(endpoint, payload, signal)),
20359
- () => this.localDispatch(endpoint, payload, signal)
20441
+ () => this.localDispatch(endpoint, payload, signal, ...rest)
20360
20442
  ).then((result) => normalizeByteResult3(endpoint, result));
20361
20443
  }
20362
20444
  if (previousOpen !== void 0) {
@@ -20495,17 +20577,17 @@ function linkControl(signal) {
20495
20577
  else signal.addEventListener("abort", () => control.abort(signal.reason), { once: true });
20496
20578
  return control;
20497
20579
  }
20498
- function createLocalOpen(gateway, runtime) {
20580
+ function createLocalOpen(gateway, runtime, peer = () => void 0) {
20499
20581
  const open = runtime.openWireStream;
20500
20582
  if (open !== void 0) {
20501
- return usesRc1Arity(open) ? (endpoint, payload, signal) => open.call(runtime, endpoint, payload, endedUplink(), void 0, signal, linkControl(signal)) : (endpoint, payload, signal) => open.call(runtime, endpoint, payload, signal);
20583
+ return usesRc1Arity(open) ? (endpoint, payload, signal) => open.call(runtime, endpoint, payload, endedUplink(), peer(), signal, linkControl(signal)) : (endpoint, payload, signal) => open.call(runtime, endpoint, payload, signal);
20502
20584
  }
20503
20585
  const wire = gateway.wireStream;
20504
20586
  if (wire === void 0) return void 0;
20505
20587
  const wireOpen = wire.open;
20506
20588
  if (usesRc1Arity(wireOpen)) {
20507
20589
  const rc1 = wireOpen;
20508
- return (endpoint, payload, signal) => rc1.call(wire, endpoint, payload, endedUplink(), void 0, signal);
20590
+ return (endpoint, payload, signal) => rc1.call(wire, endpoint, payload, endedUplink(), peer(), signal);
20509
20591
  }
20510
20592
  const legacy = wireOpen;
20511
20593
  return (endpoint, payload, signal) => legacy.call(wire, endpoint, payload, signal);
@@ -21673,7 +21755,7 @@ var QUICK_RECONNECT_RETRY_DELAY_MS = 5e3;
21673
21755
  var QUICK_RECONNECT_FORCE_RELAY = true;
21674
21756
  var BACKGROUND_RETRY_DELAYS_MS = [5e3, 1e4, 2e4, 3e4, 3e4, 3e4, 3e4];
21675
21757
  var ClientModeRuntime = class {
21676
- constructor(config, identities, server, apiProxy, typertGateway, logger, host, rtcFactoryProvider = loadNodeRtcFactory, targetStore) {
21758
+ constructor(config, identities, server, apiProxy, typertGateway, logger, host, rtcFactoryProvider = loadNodeRtcFactory, targetStore, peer) {
21677
21759
  this.config = config;
21678
21760
  this.identities = identities;
21679
21761
  this.server = server;
@@ -21681,8 +21763,9 @@ var ClientModeRuntime = class {
21681
21763
  this.host = host;
21682
21764
  this.rtcFactoryProvider = rtcFactoryProvider;
21683
21765
  this.targetStore = targetStore;
21766
+ this.peer = peer;
21684
21767
  this.proxySwitch = apiProxy === void 0 ? void 0 : new ApiProxySwitch(apiProxy);
21685
- this.gatewaySwitch = new TypertGatewaySwitch(typertGateway);
21768
+ this.gatewaySwitch = new TypertGatewaySwitch(typertGateway, { peer: this.peer });
21686
21769
  this.gatewaySwitch.setRemoteAvailability(() => this.connected !== void 0);
21687
21770
  }
21688
21771
  preview;
@@ -30269,8 +30352,18 @@ async function activate(ctx, readConfig, entryId, tuiBinding) {
30269
30352
  const deviceDirectory = config.serverUrl === void 0 ? defaultIdentityDirectory : await ensureDeviceDirectory(defaultIdentityDirectory, config.serverUrl);
30270
30353
  const hostIdentities = new IdentityStore({ directory: deviceDirectory });
30271
30354
  const apiProxy = ctx.get("apiProxy");
30355
+ const connectionService = ctx.get("connection", false);
30356
+ let ownerPeerResolved = false;
30357
+ let ownerPeer;
30358
+ const peerFor = () => {
30359
+ if (!ownerPeerResolved) {
30360
+ ownerPeerResolved = true;
30361
+ ownerPeer = connectionService?.createPeer?.({ principal: { kind: "owner" } });
30362
+ }
30363
+ return ownerPeer;
30364
+ };
30272
30365
  const nativeTypertGateway = ctx.get("typertGateway");
30273
- const localTypertGateway = new TypertGatewaySwitch(nativeTypertGateway).local();
30366
+ const localTypertGateway = new TypertGatewaySwitch(nativeTypertGateway, { peer: peerFor }).local();
30274
30367
  const subprocess = ctx.get("subprocess", false);
30275
30368
  const deepseekAccount = ctx.get("deepseekAccount", false);
30276
30369
  const deepseekSession = deepseekAccount === void 0 ? void 0 : {
@@ -30319,7 +30412,8 @@ async function activate(ctx, readConfig, entryId, tuiBinding) {
30319
30412
  hostControl,
30320
30413
  // The RTC factory keeps its default; the target store lives beside the plugin state.
30321
30414
  void 0,
30322
- new ClientTargetStore(defaultIdentityDirectory)
30415
+ new ClientTargetStore(defaultIdentityDirectory),
30416
+ peerFor
30323
30417
  );
30324
30418
  }
30325
30419
  const controlRuntime = connection === void 0 ? void 0 : new PluginControlRuntime(config, defaultIdentityDirectory, settingsBinding, clientRuntime, hostControl, deepseekSession);