@blue-soda/dsh-remote 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.github.js +46 -15
- package/dist/client.js +46 -15
- package/dist/index.js +76 -13
- package/dist/index.js.map +3 -3
- package/dsh-plugin.json +1 -1
- package/package.json +1 -1
package/dist/client.github.js
CHANGED
|
@@ -1410,7 +1410,12 @@
|
|
|
1410
1410
|
);
|
|
1411
1411
|
}
|
|
1412
1412
|
function RemoteWorkspaceAction(props) {
|
|
1413
|
-
let { t } = props, [open, setOpen] = React.useState(!1)
|
|
1413
|
+
let { t } = props, [open, setOpen] = React.useState(!1);
|
|
1414
|
+
React.useEffect(() => {
|
|
1415
|
+
open && props.control("settings.get").catch(() => {
|
|
1416
|
+
});
|
|
1417
|
+
}, [open]);
|
|
1418
|
+
let [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), authorizedOnce = React.useRef(!1), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
|
|
1414
1419
|
isEnabledQrProvider(props.preferredQrProvider) ? props.preferredQrProvider : defaultQrProvider
|
|
1415
1420
|
), [qrSession, setQrSession] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), qrFlowRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [confirmingSignOut, setConfirmingSignOut] = React.useState(!1), [confirmingRevoke, setConfirmingRevoke] = React.useState(!1), [error, setError] = React.useState(void 0);
|
|
1416
1421
|
React.useEffect(() => {
|
|
@@ -1476,7 +1481,7 @@
|
|
|
1476
1481
|
polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
|
|
1477
1482
|
if (!(!active || settled || run !== qrFlowRun.current))
|
|
1478
1483
|
if (result.status === "complete") {
|
|
1479
|
-
settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
|
|
1484
|
+
settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), authorizedOnce.current = !0, setNeedsAuthorization(!1);
|
|
1480
1485
|
try {
|
|
1481
1486
|
let [nextDevices, nextStatus] = await Promise.all([
|
|
1482
1487
|
props.control("devices"),
|
|
@@ -1575,25 +1580,25 @@
|
|
|
1575
1580
|
try {
|
|
1576
1581
|
let nextStatus = await props.control("status");
|
|
1577
1582
|
if (setStatus(nextStatus), !nextStatus.available) {
|
|
1578
|
-
setDevices([]), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1583
|
+
setDevices([]), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1579
1584
|
return;
|
|
1580
1585
|
}
|
|
1581
1586
|
let storedLocally;
|
|
1582
1587
|
try {
|
|
1583
1588
|
storedLocally = (await props.control("authorization.local"))?.stored === !0, setNeedsAuthorization(!storedLocally);
|
|
1584
1589
|
} catch {
|
|
1585
|
-
setNeedsAuthorization(!1);
|
|
1590
|
+
authorizedOnce.current = !0, setNeedsAuthorization(!1);
|
|
1586
1591
|
} finally {
|
|
1587
1592
|
setAuthorizationResolved(!0);
|
|
1588
1593
|
}
|
|
1589
1594
|
try {
|
|
1590
1595
|
let nextDevices = await props.control("devices");
|
|
1591
|
-
if (setDevices(nextDevices), storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
|
|
1596
|
+
if (setDevices(nextDevices), !authorizedOnce.current && storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
|
|
1592
1597
|
let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
|
|
1593
1598
|
nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
|
|
1594
1599
|
}
|
|
1595
1600
|
} catch {
|
|
1596
|
-
setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1601
|
+
setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1597
1602
|
}
|
|
1598
1603
|
selectedHost !== void 0 && (await props.control("remote.session.recover").then((next) => setStatus(next)).catch(() => {
|
|
1599
1604
|
}), await Promise.all([loadHarnessWorkspaces(selectedHost), loadCodexWorkspaces(selectedHost)]));
|
|
@@ -1604,6 +1609,17 @@
|
|
|
1604
1609
|
}
|
|
1605
1610
|
}, show = async () => {
|
|
1606
1611
|
setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setOpen(!0), await refreshRemote();
|
|
1612
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
1613
|
+
let list = await props.control("devices").catch(() => {
|
|
1614
|
+
});
|
|
1615
|
+
if (list !== void 0) {
|
|
1616
|
+
setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), await refreshRemote();
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
await new Promise((resolve) => {
|
|
1620
|
+
setTimeout(resolve, 1e3);
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1607
1623
|
};
|
|
1608
1624
|
React.useEffect(() => {
|
|
1609
1625
|
if (!(!open || selectedHost !== void 0))
|
|
@@ -1629,7 +1645,22 @@
|
|
|
1629
1645
|
}, [open, selectedHost]);
|
|
1630
1646
|
let chooseAnotherHost = () => {
|
|
1631
1647
|
setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCodexNotice(void 0), setCodexAvailable(!1), codexProbeAvailable.current = !1, setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
|
|
1632
|
-
},
|
|
1648
|
+
}, signingIn = busy || status?.authorizing === !0 || needsAuthorization && status?.hasDeepSeekSession === !0;
|
|
1649
|
+
React.useEffect(() => {
|
|
1650
|
+
if (!signingIn) return;
|
|
1651
|
+
let tries = 0, timer = window.setInterval(() => {
|
|
1652
|
+
tries += 1, (async () => {
|
|
1653
|
+
let next = await props.control("status").catch(() => {
|
|
1654
|
+
});
|
|
1655
|
+
next !== void 0 && setStatus(next);
|
|
1656
|
+
let list = await props.control("devices").catch(() => {
|
|
1657
|
+
});
|
|
1658
|
+
list !== void 0 && (setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0));
|
|
1659
|
+
})(), tries >= 5 && window.clearInterval(timer);
|
|
1660
|
+
}, 1e3);
|
|
1661
|
+
return () => window.clearInterval(timer);
|
|
1662
|
+
}, [signingIn]);
|
|
1663
|
+
let requestDeepSeekSignIn = async () => {
|
|
1633
1664
|
let transport = globalThis.__DSH_TRANSPORT__, callbackOrigin = transport?.streamBaseUrl !== void 0 ? new URL(transport.streamBaseUrl).origin : window.location.origin, result = await props.control("settings.configure", {
|
|
1634
1665
|
// No `role`: a device has one identity, and the control writes only the Server address plus this
|
|
1635
1666
|
// sign-in. Sending a role here was the last thing that made one look like a runtime switch.
|
|
@@ -1667,7 +1698,7 @@
|
|
|
1667
1698
|
if (state.pending) throw new Error(t("deepseekSignInTimeout"));
|
|
1668
1699
|
} else
|
|
1669
1700
|
tab?.close();
|
|
1670
|
-
setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
|
|
1701
|
+
setDevices(await props.control("devices")), setStatus(await props.control("status")), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
|
|
1671
1702
|
} catch (reason) {
|
|
1672
1703
|
setError(remoteErrorMessage(reason, t));
|
|
1673
1704
|
} finally {
|
|
@@ -1692,7 +1723,7 @@
|
|
|
1692
1723
|
}, revokeRemote = async () => {
|
|
1693
1724
|
setBusy(!0), setError(void 0), setNotice(void 0);
|
|
1694
1725
|
try {
|
|
1695
|
-
await props.control("client.device.revoke"), setDevices([]), setNeedsAuthorization(!0), setStatus(await props.control("status"));
|
|
1726
|
+
await props.control("client.device.revoke"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setStatus(await props.control("status"));
|
|
1696
1727
|
} catch (reason) {
|
|
1697
1728
|
setError(remoteErrorMessage(reason, t));
|
|
1698
1729
|
} finally {
|
|
@@ -1701,7 +1732,7 @@
|
|
|
1701
1732
|
}, logoutRemote = async () => {
|
|
1702
1733
|
setBusy(!0), setError(void 0), setNotice(void 0);
|
|
1703
1734
|
try {
|
|
1704
|
-
await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
|
|
1735
|
+
await props.control("settings.logout"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
|
|
1705
1736
|
} catch (reason) {
|
|
1706
1737
|
setError(remoteErrorMessage(reason, t));
|
|
1707
1738
|
} finally {
|
|
@@ -1909,11 +1940,11 @@
|
|
|
1909
1940
|
onClick: () => setEditingServerUrl(!0)
|
|
1910
1941
|
}, loginServerUrl)
|
|
1911
1942
|
),
|
|
1912
|
-
React.createElement(
|
|
1913
|
-
"button",
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
),
|
|
1943
|
+
React.createElement("button", {
|
|
1944
|
+
type: "button",
|
|
1945
|
+
disabled: busy || signingIn || loginServerUrl.trim() === "",
|
|
1946
|
+
onClick: () => void signInClient()
|
|
1947
|
+
}, t(signingIn ? "signingIn" : "deepseekSignIn")),
|
|
1917
1948
|
awaitingDeepSeek ? React.createElement(
|
|
1918
1949
|
"p",
|
|
1919
1950
|
{ className: "dshRemoteServiceAddress" },
|
package/dist/client.js
CHANGED
|
@@ -1410,7 +1410,12 @@
|
|
|
1410
1410
|
);
|
|
1411
1411
|
}
|
|
1412
1412
|
function RemoteWorkspaceAction(props) {
|
|
1413
|
-
let { t } = props, [open, setOpen] = React.useState(!1)
|
|
1413
|
+
let { t } = props, [open, setOpen] = React.useState(!1);
|
|
1414
|
+
React.useEffect(() => {
|
|
1415
|
+
open && props.control("settings.get").catch(() => {
|
|
1416
|
+
});
|
|
1417
|
+
}, [open]);
|
|
1418
|
+
let [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [connectingHost, setConnectingHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [codexWorkspaces, setCodexWorkspaces] = React.useState([]), [codexNotice, setCodexNotice] = React.useState(void 0), [codexAvailable, setCodexAvailable] = React.useState(!1), codexProbeAvailable = React.useRef(!1), [codexOpen, setCodexOpen] = React.useState(!1), [workspaceBackend, setWorkspaceBackend] = React.useState("harness"), [codexWorkspaceId, setCodexWorkspaceId] = React.useState(void 0), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [showAllWorkspaces, setShowAllWorkspaces] = React.useState(!1), [showAllCodexWorkspaces, setShowAllCodexWorkspaces] = React.useState(!1), [devicesOpen, setDevicesOpen] = React.useState(!1), workspaceListId = "dsh-remote-workspace-list", codexWorkspaceHeadingId = "dsh-remote-codex-workspace-heading", codexWorkspaceListId = "dsh-remote-codex-workspace-list", [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), authorizedOnce = React.useRef(!1), [authorizationResolved, setAuthorizationResolved] = React.useState(!1), [loginServerUrl, setLoginServerUrl] = React.useState(DEFAULT_REMOTE_SERVER_URL), [editingServerUrl, setEditingServerUrl] = React.useState(!1), [awaitingDeepSeek, setAwaitingDeepSeek] = React.useState(!1), [pendingAuthorizeUrl, setPendingAuthorizeUrl] = React.useState(void 0), [loginMethod] = React.useState(
|
|
1414
1419
|
isEnabledQrProvider(props.preferredQrProvider) ? props.preferredQrProvider : defaultQrProvider
|
|
1415
1420
|
), [qrSession, setQrSession] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), qrFlowRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [confirmingSignOut, setConfirmingSignOut] = React.useState(!1), [confirmingRevoke, setConfirmingRevoke] = React.useState(!1), [error, setError] = React.useState(void 0);
|
|
1416
1421
|
React.useEffect(() => {
|
|
@@ -1476,7 +1481,7 @@
|
|
|
1476
1481
|
polling || settled || (polling = !0, props.control("client.account.qr.poll", { qrId: qrSession.qrId }).then(async (result) => {
|
|
1477
1482
|
if (!(!active || settled || run !== qrFlowRun.current))
|
|
1478
1483
|
if (result.status === "complete") {
|
|
1479
|
-
settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), setNeedsAuthorization(!1);
|
|
1484
|
+
settled = !0, timer !== void 0 && window.clearInterval(timer), setBusy(!0), setError(void 0), setQrExpired(!1), authorizedOnce.current = !0, setNeedsAuthorization(!1);
|
|
1480
1485
|
try {
|
|
1481
1486
|
let [nextDevices, nextStatus] = await Promise.all([
|
|
1482
1487
|
props.control("devices"),
|
|
@@ -1575,25 +1580,25 @@
|
|
|
1575
1580
|
try {
|
|
1576
1581
|
let nextStatus = await props.control("status");
|
|
1577
1582
|
if (setStatus(nextStatus), !nextStatus.available) {
|
|
1578
|
-
setDevices([]), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1583
|
+
setDevices([]), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1579
1584
|
return;
|
|
1580
1585
|
}
|
|
1581
1586
|
let storedLocally;
|
|
1582
1587
|
try {
|
|
1583
1588
|
storedLocally = (await props.control("authorization.local"))?.stored === !0, setNeedsAuthorization(!storedLocally);
|
|
1584
1589
|
} catch {
|
|
1585
|
-
setNeedsAuthorization(!1);
|
|
1590
|
+
authorizedOnce.current = !0, setNeedsAuthorization(!1);
|
|
1586
1591
|
} finally {
|
|
1587
1592
|
setAuthorizationResolved(!0);
|
|
1588
1593
|
}
|
|
1589
1594
|
try {
|
|
1590
1595
|
let nextDevices = await props.control("devices");
|
|
1591
|
-
if (setDevices(nextDevices), storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
|
|
1596
|
+
if (setDevices(nextDevices), !authorizedOnce.current && storedLocally !== void 0 && setNeedsAuthorization(authorizationStillNeeded(storedLocally, nextDevices.length)), selectedHost !== void 0) {
|
|
1592
1597
|
let nextSelectedHost = nextDevices.find((device) => device.deviceId === selectedHost.deviceId);
|
|
1593
1598
|
nextSelectedHost === void 0 ? (setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0)) : setSelectedHost(nextSelectedHost);
|
|
1594
1599
|
}
|
|
1595
1600
|
} catch {
|
|
1596
|
-
setDevices([]), setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1601
|
+
setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
|
|
1597
1602
|
}
|
|
1598
1603
|
selectedHost !== void 0 && (await props.control("remote.session.recover").then((next) => setStatus(next)).catch(() => {
|
|
1599
1604
|
}), await Promise.all([loadHarnessWorkspaces(selectedHost), loadCodexWorkspaces(selectedHost)]));
|
|
@@ -1604,6 +1609,17 @@
|
|
|
1604
1609
|
}
|
|
1605
1610
|
}, show = async () => {
|
|
1606
1611
|
setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setOpen(!0), await refreshRemote();
|
|
1612
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
1613
|
+
let list = await props.control("devices").catch(() => {
|
|
1614
|
+
});
|
|
1615
|
+
if (list !== void 0) {
|
|
1616
|
+
setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), await refreshRemote();
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
await new Promise((resolve) => {
|
|
1620
|
+
setTimeout(resolve, 1e3);
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1607
1623
|
};
|
|
1608
1624
|
React.useEffect(() => {
|
|
1609
1625
|
if (!(!open || selectedHost !== void 0))
|
|
@@ -1629,7 +1645,22 @@
|
|
|
1629
1645
|
}, [open, selectedHost]);
|
|
1630
1646
|
let chooseAnotherHost = () => {
|
|
1631
1647
|
setSelectedHost(void 0), setWorkspaces([]), setCodexWorkspaces([]), setCodexNotice(void 0), setCodexAvailable(!1), codexProbeAvailable.current = !1, setShowAllWorkspaces(!1), setShowAllCodexWorkspaces(!1), setWorkspaceBackend("harness"), setCodexWorkspaceId(void 0), setDirectory(void 0), setPath(""), setAddingWorkspace(!1), setError(void 0);
|
|
1632
|
-
},
|
|
1648
|
+
}, signingIn = busy || status?.authorizing === !0 || needsAuthorization && status?.hasDeepSeekSession === !0;
|
|
1649
|
+
React.useEffect(() => {
|
|
1650
|
+
if (!signingIn) return;
|
|
1651
|
+
let tries = 0, timer = window.setInterval(() => {
|
|
1652
|
+
tries += 1, (async () => {
|
|
1653
|
+
let next = await props.control("status").catch(() => {
|
|
1654
|
+
});
|
|
1655
|
+
next !== void 0 && setStatus(next);
|
|
1656
|
+
let list = await props.control("devices").catch(() => {
|
|
1657
|
+
});
|
|
1658
|
+
list !== void 0 && (setDevices(list), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0));
|
|
1659
|
+
})(), tries >= 5 && window.clearInterval(timer);
|
|
1660
|
+
}, 1e3);
|
|
1661
|
+
return () => window.clearInterval(timer);
|
|
1662
|
+
}, [signingIn]);
|
|
1663
|
+
let requestDeepSeekSignIn = async () => {
|
|
1633
1664
|
let transport = globalThis.__DSH_TRANSPORT__, callbackOrigin = transport?.streamBaseUrl !== void 0 ? new URL(transport.streamBaseUrl).origin : window.location.origin, result = await props.control("settings.configure", {
|
|
1634
1665
|
// No `role`: a device has one identity, and the control writes only the Server address plus this
|
|
1635
1666
|
// sign-in. Sending a role here was the last thing that made one look like a runtime switch.
|
|
@@ -1667,7 +1698,7 @@
|
|
|
1667
1698
|
if (state.pending) throw new Error(t("deepseekSignInTimeout"));
|
|
1668
1699
|
} else
|
|
1669
1700
|
tab?.close();
|
|
1670
|
-
setDevices(await props.control("devices")), setStatus(await props.control("status")), setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
|
|
1701
|
+
setDevices(await props.control("devices")), setStatus(await props.control("status")), authorizedOnce.current = !0, setNeedsAuthorization(!1), setAuthorizationResolved(!0), setNotice(void 0);
|
|
1671
1702
|
} catch (reason) {
|
|
1672
1703
|
setError(remoteErrorMessage(reason, t));
|
|
1673
1704
|
} finally {
|
|
@@ -1692,7 +1723,7 @@
|
|
|
1692
1723
|
}, revokeRemote = async () => {
|
|
1693
1724
|
setBusy(!0), setError(void 0), setNotice(void 0);
|
|
1694
1725
|
try {
|
|
1695
|
-
await props.control("client.device.revoke"), setDevices([]), setNeedsAuthorization(!0), setStatus(await props.control("status"));
|
|
1726
|
+
await props.control("client.device.revoke"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setStatus(await props.control("status"));
|
|
1696
1727
|
} catch (reason) {
|
|
1697
1728
|
setError(remoteErrorMessage(reason, t));
|
|
1698
1729
|
} finally {
|
|
@@ -1701,7 +1732,7 @@
|
|
|
1701
1732
|
}, logoutRemote = async () => {
|
|
1702
1733
|
setBusy(!0), setError(void 0), setNotice(void 0);
|
|
1703
1734
|
try {
|
|
1704
|
-
await props.control("settings.logout"), setDevices([]), setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
|
|
1735
|
+
await props.control("settings.logout"), setDevices([]), authorizedOnce.current = !1, setNeedsAuthorization(!0), setQrSession(void 0), setQrExpired(!1), setStatus(await props.control("status"));
|
|
1705
1736
|
} catch (reason) {
|
|
1706
1737
|
setError(remoteErrorMessage(reason, t));
|
|
1707
1738
|
} finally {
|
|
@@ -1909,11 +1940,11 @@
|
|
|
1909
1940
|
onClick: () => setEditingServerUrl(!0)
|
|
1910
1941
|
}, loginServerUrl)
|
|
1911
1942
|
),
|
|
1912
|
-
React.createElement(
|
|
1913
|
-
"button",
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
),
|
|
1943
|
+
React.createElement("button", {
|
|
1944
|
+
type: "button",
|
|
1945
|
+
disabled: busy || signingIn || loginServerUrl.trim() === "",
|
|
1946
|
+
onClick: () => void signInClient()
|
|
1947
|
+
}, t(signingIn ? "signingIn" : "deepseekSignIn")),
|
|
1917
1948
|
awaitingDeepSeek ? React.createElement(
|
|
1918
1949
|
"p",
|
|
1919
1950
|
{ className: "dshRemoteServiceAddress" },
|
package/dist/index.js
CHANGED
|
@@ -13521,7 +13521,7 @@ function normalizeServerUrl(value) {
|
|
|
13521
13521
|
}
|
|
13522
13522
|
|
|
13523
13523
|
// src/version.ts
|
|
13524
|
-
var PLUGIN_VERSION = "0.5.
|
|
13524
|
+
var PLUGIN_VERSION = "0.5.5";
|
|
13525
13525
|
|
|
13526
13526
|
// src/server-api.ts
|
|
13527
13527
|
var ENABLED_QR_PROVIDERS = ["github"];
|
|
@@ -14109,7 +14109,7 @@ var HostServerConnection = class {
|
|
|
14109
14109
|
if (TERMINAL_AUTH_ERRORS.has(code)) {
|
|
14110
14110
|
this.logger.warn(code === "CONNECTION_REPLACED" ? "Another instance is using this Host identity. Standing by: retrying in five minutes, and taking over as soon as it leaves." : code === "SERVER_CREDENTIALS_BUSY" ? "Credential refresh is locked. Stop other instances; after a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again." : "Host authorization failed. Run /remote login or authorize this Host again in Remote settings.");
|
|
14111
14111
|
}
|
|
14112
|
-
if (code === "DEVICE_REVOKED") {
|
|
14112
|
+
if (code === "DEVICE_REVOKED" || code === "AUTH_INVALID") {
|
|
14113
14113
|
try {
|
|
14114
14114
|
await this.api.clearAuthorization();
|
|
14115
14115
|
} catch (clearError) {
|
|
@@ -21920,10 +21920,16 @@ var ClientModeRuntime = class {
|
|
|
21920
21920
|
registerControl(connection, webServer) {
|
|
21921
21921
|
return registerControlRoute(connection, (endpoint, payload, signal) => this.handleControl(endpoint, payload, signal), webServer);
|
|
21922
21922
|
}
|
|
21923
|
+
/** True while the plugin is exchanging DSH's DeepSeek credential for this device's Server credentials. */
|
|
21924
|
+
authorizingWithDeepSeek = false;
|
|
21925
|
+
/** Whether DSH held a DeepSeek session at the last reconciliation. */
|
|
21926
|
+
hasDeepSeekSession = false;
|
|
21923
21927
|
status() {
|
|
21924
21928
|
const targetStatus = this.gatewaySwitch.supportsCarrier() ? this.gatewaySwitch.status() : this.proxySwitch?.status() ?? this.gatewaySwitch.status();
|
|
21925
21929
|
return {
|
|
21926
21930
|
available: this.config.serverUrl !== void 0,
|
|
21931
|
+
authorizing: this.authorizingWithDeepSeek,
|
|
21932
|
+
hasDeepSeekSession: this.hasDeepSeekSession,
|
|
21927
21933
|
identityReady: this.identity !== void 0,
|
|
21928
21934
|
deviceId: this.identity?.deviceId,
|
|
21929
21935
|
deviceName: this.identity?.name,
|
|
@@ -22086,6 +22092,11 @@ var ClientModeRuntime = class {
|
|
|
22086
22092
|
reloadCredentials() {
|
|
22087
22093
|
this.server.reloadCredentials();
|
|
22088
22094
|
}
|
|
22095
|
+
/** Whether this device holds Server credentials, i.e. the panel shows it as signed in. */
|
|
22096
|
+
async hasServerAuthorization() {
|
|
22097
|
+
if (this.server.hasStoredAuthorization === void 0) return false;
|
|
22098
|
+
return await this.server.hasStoredAuthorization().catch(() => false);
|
|
22099
|
+
}
|
|
22089
22100
|
async setHostAuthorization(enabled) {
|
|
22090
22101
|
if (this.host === void 0) throw new ClientModeError("METHOD_NOT_ALLOWED", "This plugin is not running as a Host.");
|
|
22091
22102
|
if (!enabled) {
|
|
@@ -25014,12 +25025,24 @@ var CodexRemoteDomain = class {
|
|
|
25014
25025
|
idempotencyKey: call.params.idempotencyKey
|
|
25015
25026
|
}));
|
|
25016
25027
|
}
|
|
25028
|
+
if (isRecord12(call.params) && typeof call.params.threadId === "string") {
|
|
25029
|
+
const rowKey = call.params.threadId;
|
|
25030
|
+
const separator = rowKey.indexOf("~");
|
|
25031
|
+
if (separator > 0) call.params.threadId = rowKey.slice(0, separator);
|
|
25032
|
+
}
|
|
25017
25033
|
if (call.method === "thread/list") {
|
|
25018
25034
|
const result = sanitizeThreadList(await this.callUpstream(call.method, call.params));
|
|
25019
|
-
|
|
25035
|
+
const authorized = filterThreadListByWorkspaceAuthority(
|
|
25020
25036
|
result,
|
|
25021
25037
|
await this.readWorkspaceAuthority(result.data)
|
|
25022
25038
|
);
|
|
25039
|
+
return {
|
|
25040
|
+
...authorized,
|
|
25041
|
+
data: authorized.data.map((row, index) => ({
|
|
25042
|
+
...row,
|
|
25043
|
+
id: `${String(row.id)}~${String(row.createdAt ?? "")}~${index}`
|
|
25044
|
+
}))
|
|
25045
|
+
};
|
|
25023
25046
|
}
|
|
25024
25047
|
if (call.method === "thread/start") {
|
|
25025
25048
|
const cwd = await this.requireCodexWorkspacePath(call.params.cwd);
|
|
@@ -26228,7 +26251,6 @@ var PluginControlRuntime = class {
|
|
|
26228
26251
|
*
|
|
26229
26252
|
* `undefined` means no sign-in is in flight, which is also the state after a completed authorization.
|
|
26230
26253
|
*/
|
|
26231
|
-
deepSeekSignIn;
|
|
26232
26254
|
register(connection, webServer) {
|
|
26233
26255
|
const statusStream = new ControlStatusStream(() => this.streamStatus());
|
|
26234
26256
|
return registerControlRoute(
|
|
@@ -26337,15 +26359,13 @@ var PluginControlRuntime = class {
|
|
|
26337
26359
|
throw new ClientModeError("METHOD_NOT_ALLOWED", "DeepSeek account sign-in is unavailable in this profile.");
|
|
26338
26360
|
}
|
|
26339
26361
|
const session = await this.deepseekSession.read();
|
|
26340
|
-
|
|
26341
|
-
if (!counted) {
|
|
26362
|
+
if (session === void 0) {
|
|
26342
26363
|
const started = await this.deepseekSession.startSignIn({
|
|
26343
26364
|
callbackOrigin: typeof value.callbackOrigin === "string" ? value.callbackOrigin : "",
|
|
26344
26365
|
loginSource: value.loginSource === "desktop" ? "desktop" : "web",
|
|
26345
26366
|
locale: typeof value.locale === "string" ? value.locale : "en",
|
|
26346
26367
|
timezoneOffsetSeconds: typeof value.timezoneOffsetSeconds === "number" ? value.timezoneOffsetSeconds : 0
|
|
26347
26368
|
});
|
|
26348
|
-
this.deepSeekSignIn = true;
|
|
26349
26369
|
return {
|
|
26350
26370
|
status: "deepseek-sign-in-required",
|
|
26351
26371
|
...started.authorizeUrl === void 0 ? {} : { authorizeUrl: started.authorizeUrl }
|
|
@@ -26358,7 +26378,6 @@ var PluginControlRuntime = class {
|
|
|
26358
26378
|
this.verifiedDeepSeekToken = session.token;
|
|
26359
26379
|
this.verifiedDeepSeekAuthorization = authorization;
|
|
26360
26380
|
}
|
|
26361
|
-
this.deepSeekSignIn = void 0;
|
|
26362
26381
|
} else {
|
|
26363
26382
|
if (typeof value.email !== "string" || typeof value.password !== "string") {
|
|
26364
26383
|
throw new ClientModeError("INVALID_MESSAGE", "Email and password are required for account authorization.");
|
|
@@ -26371,7 +26390,8 @@ var PluginControlRuntime = class {
|
|
|
26371
26390
|
if (this.host !== void 0 && !hostPaused) {
|
|
26372
26391
|
try {
|
|
26373
26392
|
this.host.reconnectHost?.();
|
|
26374
|
-
} catch {
|
|
26393
|
+
} catch (error) {
|
|
26394
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26375
26395
|
}
|
|
26376
26396
|
}
|
|
26377
26397
|
await this.settings.replace(editableConfig(next));
|
|
@@ -26471,14 +26491,13 @@ var PluginControlRuntime = class {
|
|
|
26471
26491
|
await this.settings.replace(editableConfig({ ...current, acp: { enabled: current.acp?.enabled ?? true, backends } }));
|
|
26472
26492
|
return this.settingsView();
|
|
26473
26493
|
}
|
|
26474
|
-
async logout() {
|
|
26494
|
+
async logout(options = {}) {
|
|
26475
26495
|
if (this.settings === void 0) {
|
|
26476
26496
|
throw new ClientModeError("SETTINGS_UNAVAILABLE", "DSH user settings are unavailable in this profile.");
|
|
26477
26497
|
}
|
|
26478
26498
|
const config = resolveConfig(this.settings.get());
|
|
26479
26499
|
this.verifiedDeepSeekToken = void 0;
|
|
26480
26500
|
this.verifiedDeepSeekAuthorization = void 0;
|
|
26481
|
-
this.deepSeekSignIn = void 0;
|
|
26482
26501
|
if (config.serverUrl !== void 0) {
|
|
26483
26502
|
await Promise.all([
|
|
26484
26503
|
this.client?.clearClientAuthorization(),
|
|
@@ -26487,11 +26506,13 @@ var PluginControlRuntime = class {
|
|
|
26487
26506
|
const directory = await ensureDeviceDirectory(this.identityDirectory, config.serverUrl);
|
|
26488
26507
|
await new ServerCredentialStore(directory).clear();
|
|
26489
26508
|
}
|
|
26509
|
+
if (this.client !== void 0) this.client.hasDeepSeekSession = false;
|
|
26490
26510
|
let deepseekSignedOut = false;
|
|
26491
26511
|
if (this.deepseekSession !== void 0) {
|
|
26492
26512
|
try {
|
|
26493
|
-
deepseekSignedOut = await this.deepseekSession.signOut();
|
|
26494
|
-
} catch {
|
|
26513
|
+
deepseekSignedOut = options.releaseDeepSeek === false ? false : await this.deepseekSession.signOut();
|
|
26514
|
+
} catch (error) {
|
|
26515
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26495
26516
|
deepseekSignedOut = false;
|
|
26496
26517
|
}
|
|
26497
26518
|
}
|
|
@@ -26522,7 +26543,49 @@ var PluginControlRuntime = class {
|
|
|
26522
26543
|
}
|
|
26523
26544
|
return this.client === void 0 ? this.hostOnlyStatus() : await this.client.status();
|
|
26524
26545
|
}
|
|
26546
|
+
/** Consecutive reconciliations without a DSH session: DSH refreshes its grant, so one empty read is not a sign-out. */
|
|
26547
|
+
/** Guards against re-entry through configure(), which reads the settings view back. */
|
|
26548
|
+
reconcilingWithDeepSeek = false;
|
|
26549
|
+
/**
|
|
26550
|
+
* Keep this device's Server credentials in step with DSH's DeepSeek session - that session is the credential, and
|
|
26551
|
+
* the Server verifies it before issuing this device its own tokens.
|
|
26552
|
+
*
|
|
26553
|
+
* Three cases: DSH signed in and this device not authorized -> authorize; DSH signed out and this device authorized
|
|
26554
|
+
* -> sign out; otherwise nothing. At most once per ten seconds, from the settings poll the panel already makes.
|
|
26555
|
+
*/
|
|
26556
|
+
async reconcileWithDeepSeek() {
|
|
26557
|
+
if (this.deepseekSession === void 0 || this.reconcilingWithDeepSeek) return;
|
|
26558
|
+
this.reconcilingWithDeepSeek = true;
|
|
26559
|
+
try {
|
|
26560
|
+
const session = await this.deepseekSession.read();
|
|
26561
|
+
if (this.client !== void 0) this.client.hasDeepSeekSession = session !== void 0;
|
|
26562
|
+
const authorized = this.client === void 0 ? false : await this.client.hasServerAuthorization();
|
|
26563
|
+
console.error(`[dsh-remote] reconcile ${JSON.stringify({ hasSession: session !== void 0, authorized })}`);
|
|
26564
|
+
if (session === void 0 && authorized) {
|
|
26565
|
+
await this.logout({ releaseDeepSeek: false });
|
|
26566
|
+
return;
|
|
26567
|
+
}
|
|
26568
|
+
if (session === void 0 || authorized) return;
|
|
26569
|
+
if (this.client !== void 0) this.client.authorizingWithDeepSeek = true;
|
|
26570
|
+
void (async () => {
|
|
26571
|
+
try {
|
|
26572
|
+
await this.configure({ provider: "deepseek", serverUrl: this.config.serverUrl });
|
|
26573
|
+
} catch (error) {
|
|
26574
|
+
console.error(`[dsh-remote] reconcile failed ${JSON.stringify({ code: String(error?.code ?? "") })}`);
|
|
26575
|
+
} finally {
|
|
26576
|
+
if (this.client !== void 0) this.client.authorizingWithDeepSeek = false;
|
|
26577
|
+
}
|
|
26578
|
+
})();
|
|
26579
|
+
} finally {
|
|
26580
|
+
this.reconcilingWithDeepSeek = false;
|
|
26581
|
+
}
|
|
26582
|
+
}
|
|
26583
|
+
/**
|
|
26584
|
+
* Keeps the reconciliation alive without the panel: DSH can be signed in or out while the card is closed, and the
|
|
26585
|
+
* plugin has to follow. Only local reads - the exchange itself is throttled to one per ten seconds.
|
|
26586
|
+
*/
|
|
26525
26587
|
async settingsView() {
|
|
26588
|
+
await this.reconcileWithDeepSeek();
|
|
26526
26589
|
const config = this.settings === void 0 ? editableConfig(this.config) : editableConfig(resolveConfig(this.settings.get()));
|
|
26527
26590
|
const associations = await this.associations(config);
|
|
26528
26591
|
const association = associations.host;
|