@elizaos/plugin-screenshare 2.0.3-beta.6 → 2.0.3-beta.7
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/components/ScreenshareSpatialView.d.ts +61 -0
- package/dist/components/ScreenshareSpatialView.d.ts.map +1 -0
- package/dist/components/ScreenshareSpatialView.js +206 -0
- package/dist/components/ScreenshareSpatialView.js.map +1 -0
- package/dist/components/ScreenshareView.d.ts +13 -0
- package/dist/components/ScreenshareView.d.ts.map +1 -0
- package/dist/components/ScreenshareView.js +263 -0
- package/dist/components/ScreenshareView.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +27 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/routes.d.ts +8 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +639 -0
- package/dist/routes.js.map +1 -0
- package/dist/session-store.d.ts +44 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +200 -0
- package/dist/session-store.js.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.d.ts +5 -0
- package/dist/ui/ScreenshareOperatorSurface.d.ts.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.helpers.d.ts +40 -0
- package/dist/ui/ScreenshareOperatorSurface.helpers.d.ts.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.helpers.js +47 -0
- package/dist/ui/ScreenshareOperatorSurface.helpers.js.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.interact.d.ts +2 -0
- package/dist/ui/ScreenshareOperatorSurface.interact.d.ts.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.interact.js +100 -0
- package/dist/ui/ScreenshareOperatorSurface.interact.js.map +1 -0
- package/dist/ui/ScreenshareOperatorSurface.js +746 -0
- package/dist/ui/ScreenshareOperatorSurface.js.map +1 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +10 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/screenshare-view-bundle.d.ts +3 -0
- package/dist/ui/screenshare-view-bundle.d.ts.map +1 -0
- package/dist/ui/screenshare-view-bundle.js +7 -0
- package/dist/ui/screenshare-view-bundle.js.map +1 -0
- package/dist/views/bundle.js +507 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
client,
|
|
5
|
+
Input,
|
|
6
|
+
SurfaceEmptyState,
|
|
7
|
+
SurfaceSection,
|
|
8
|
+
selectLatestRunForApp,
|
|
9
|
+
useAppSelector
|
|
10
|
+
} from "@elizaos/ui";
|
|
11
|
+
import { useAgentElement } from "@elizaos/ui/agent-surface";
|
|
12
|
+
import {
|
|
13
|
+
CheckCircle2,
|
|
14
|
+
Copy,
|
|
15
|
+
ExternalLink,
|
|
16
|
+
MonitorUp,
|
|
17
|
+
PlugZap,
|
|
18
|
+
Power,
|
|
19
|
+
RefreshCw,
|
|
20
|
+
XCircle
|
|
21
|
+
} from "lucide-react";
|
|
22
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
23
|
+
import {
|
|
24
|
+
buildViewerUrl,
|
|
25
|
+
fetchJson,
|
|
26
|
+
loadScreenshareTuiState
|
|
27
|
+
} from "./ScreenshareOperatorSurface.helpers";
|
|
28
|
+
const APP_NAME = "@elizaos/plugin-screenshare";
|
|
29
|
+
function parseViewerSession(viewerUrl) {
|
|
30
|
+
if (!viewerUrl) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const url = new URL(viewerUrl, window.location.origin);
|
|
35
|
+
const sessionId = url.searchParams.get("sessionId")?.trim();
|
|
36
|
+
const token = url.searchParams.get("token")?.trim();
|
|
37
|
+
return sessionId && token ? { sessionId, token } : null;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function formatTime(value) {
|
|
43
|
+
if (!value) {
|
|
44
|
+
return "Not yet";
|
|
45
|
+
}
|
|
46
|
+
const date = new Date(value);
|
|
47
|
+
return Number.isNaN(date.getTime()) ? "Not yet" : date.toLocaleTimeString();
|
|
48
|
+
}
|
|
49
|
+
function ScreenshareMetric({
|
|
50
|
+
icon: Icon,
|
|
51
|
+
label,
|
|
52
|
+
value,
|
|
53
|
+
active
|
|
54
|
+
}) {
|
|
55
|
+
return /* @__PURE__ */ jsxs(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
className: "flex min-h-16 flex-col items-center justify-center gap-1.5 px-3 py-2",
|
|
59
|
+
title: label,
|
|
60
|
+
role: "status",
|
|
61
|
+
"aria-label": `${label}: ${value}`,
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
64
|
+
/* @__PURE__ */ jsx(
|
|
65
|
+
"span",
|
|
66
|
+
{
|
|
67
|
+
className: `h-1.5 w-1.5 shrink-0 rounded-full ${active ? "bg-accent" : "bg-muted/40"}`,
|
|
68
|
+
"aria-hidden": true
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
Icon,
|
|
73
|
+
{
|
|
74
|
+
className: `h-3.5 w-3.5 ${active ? "text-accent" : "text-muted"}`
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
] }),
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"span",
|
|
80
|
+
{
|
|
81
|
+
className: `truncate text-sm font-semibold ${active ? "text-txt" : "text-muted-strong"}`,
|
|
82
|
+
children: value
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function ScreenshareActionButton({
|
|
90
|
+
agentId,
|
|
91
|
+
label,
|
|
92
|
+
group,
|
|
93
|
+
description,
|
|
94
|
+
status,
|
|
95
|
+
...buttonProps
|
|
96
|
+
}) {
|
|
97
|
+
const { ref, agentProps } = useAgentElement({
|
|
98
|
+
id: agentId,
|
|
99
|
+
role: "button",
|
|
100
|
+
label,
|
|
101
|
+
group,
|
|
102
|
+
description,
|
|
103
|
+
...status ? { status } : {}
|
|
104
|
+
});
|
|
105
|
+
return /* @__PURE__ */ jsx(Button, { ref, "aria-label": label, ...agentProps, ...buttonProps });
|
|
106
|
+
}
|
|
107
|
+
function ScreenshareField({
|
|
108
|
+
agentId,
|
|
109
|
+
label,
|
|
110
|
+
group,
|
|
111
|
+
description,
|
|
112
|
+
role = "text-input",
|
|
113
|
+
...inputProps
|
|
114
|
+
}) {
|
|
115
|
+
const { ref, agentProps } = useAgentElement({
|
|
116
|
+
id: agentId,
|
|
117
|
+
role,
|
|
118
|
+
label,
|
|
119
|
+
group,
|
|
120
|
+
description,
|
|
121
|
+
fillable: !inputProps.readOnly
|
|
122
|
+
});
|
|
123
|
+
return /* @__PURE__ */ jsx(Input, { ref, "aria-label": label, ...agentProps, ...inputProps });
|
|
124
|
+
}
|
|
125
|
+
function ScreenshareOperatorSurface({
|
|
126
|
+
appName,
|
|
127
|
+
focus = "all"
|
|
128
|
+
}) {
|
|
129
|
+
const appRuns = useAppSelector((s) => s.appRuns);
|
|
130
|
+
const setActionNotice = useAppSelector((s) => s.setActionNotice);
|
|
131
|
+
const { run } = useMemo(
|
|
132
|
+
() => selectLatestRunForApp(appName || APP_NAME, appRuns),
|
|
133
|
+
[appName, appRuns]
|
|
134
|
+
);
|
|
135
|
+
const launchedSession = useMemo(
|
|
136
|
+
() => parseViewerSession(run?.viewer?.url),
|
|
137
|
+
[run?.viewer?.url]
|
|
138
|
+
);
|
|
139
|
+
const [capabilities, setCapabilities] = useState(
|
|
140
|
+
null
|
|
141
|
+
);
|
|
142
|
+
const [hostSession, setHostSession] = useState(null);
|
|
143
|
+
const [hostToken, setHostToken] = useState(
|
|
144
|
+
launchedSession?.token ?? ""
|
|
145
|
+
);
|
|
146
|
+
const [remoteBase, setRemoteBase] = useState("");
|
|
147
|
+
const [remoteSessionId, setRemoteSessionId] = useState("");
|
|
148
|
+
const [remoteToken, setRemoteToken] = useState("");
|
|
149
|
+
const [busy, setBusy] = useState(null);
|
|
150
|
+
const loadCapabilities = useCallback(async () => {
|
|
151
|
+
const next = await fetchJson(
|
|
152
|
+
"/api/apps/screenshare/capabilities"
|
|
153
|
+
);
|
|
154
|
+
setCapabilities(next);
|
|
155
|
+
}, []);
|
|
156
|
+
const loadLaunchedSession = useCallback(async () => {
|
|
157
|
+
if (!launchedSession) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
setHostToken(launchedSession.token);
|
|
161
|
+
const next = await fetchJson(
|
|
162
|
+
`/api/apps/screenshare/session/${encodeURIComponent(
|
|
163
|
+
launchedSession.sessionId
|
|
164
|
+
)}?token=${encodeURIComponent(launchedSession.token)}`
|
|
165
|
+
);
|
|
166
|
+
setHostSession(next.session);
|
|
167
|
+
}, [launchedSession]);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
void loadCapabilities().catch((error) => {
|
|
170
|
+
setActionNotice(
|
|
171
|
+
error instanceof Error ? error.message : "Failed to load capabilities.",
|
|
172
|
+
"error",
|
|
173
|
+
3200
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
}, [loadCapabilities, setActionNotice]);
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
void loadLaunchedSession().catch((error) => {
|
|
179
|
+
setActionNotice(
|
|
180
|
+
error instanceof Error ? error.message : "Failed to load screen share session.",
|
|
181
|
+
"error",
|
|
182
|
+
3200
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
}, [loadLaunchedSession, setActionNotice]);
|
|
186
|
+
const startHostSession = useCallback(async () => {
|
|
187
|
+
setBusy("start");
|
|
188
|
+
try {
|
|
189
|
+
const response = await fetchJson(
|
|
190
|
+
"/api/apps/screenshare/session",
|
|
191
|
+
{
|
|
192
|
+
method: "POST",
|
|
193
|
+
body: JSON.stringify({ label: "This machine" })
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
setHostSession(response.session);
|
|
197
|
+
setHostToken(response.token);
|
|
198
|
+
setActionNotice("Screen share session started.", "success", 2400);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
setActionNotice(
|
|
201
|
+
error instanceof Error ? error.message : "Failed to start session.",
|
|
202
|
+
"error",
|
|
203
|
+
3600
|
|
204
|
+
);
|
|
205
|
+
} finally {
|
|
206
|
+
setBusy(null);
|
|
207
|
+
}
|
|
208
|
+
}, [setActionNotice]);
|
|
209
|
+
const stopHostSession = useCallback(async () => {
|
|
210
|
+
if (!hostSession || !hostToken) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
setBusy("stop");
|
|
214
|
+
try {
|
|
215
|
+
const response = await fetchJson(
|
|
216
|
+
`/api/apps/screenshare/session/${encodeURIComponent(hostSession.id)}/stop`,
|
|
217
|
+
{
|
|
218
|
+
method: "POST",
|
|
219
|
+
body: JSON.stringify({ token: hostToken }),
|
|
220
|
+
headers: { "X-Screenshare-Token": hostToken }
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
setHostSession(response.session);
|
|
224
|
+
setActionNotice("Screen share session stopped.", "success", 2400);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
setActionNotice(
|
|
227
|
+
error instanceof Error ? error.message : "Failed to stop session.",
|
|
228
|
+
"error",
|
|
229
|
+
3600
|
|
230
|
+
);
|
|
231
|
+
} finally {
|
|
232
|
+
setBusy(null);
|
|
233
|
+
}
|
|
234
|
+
}, [hostSession, hostToken, setActionNotice]);
|
|
235
|
+
const copyHostDetails = useCallback(async () => {
|
|
236
|
+
if (!hostSession || !hostToken) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const url = buildViewerUrl({
|
|
240
|
+
sessionId: hostSession.id,
|
|
241
|
+
token: hostToken
|
|
242
|
+
});
|
|
243
|
+
try {
|
|
244
|
+
await navigator.clipboard.writeText(
|
|
245
|
+
JSON.stringify(
|
|
246
|
+
{
|
|
247
|
+
serverUrl: client.getBaseUrl() || window.location.origin,
|
|
248
|
+
sessionId: hostSession.id,
|
|
249
|
+
token: hostToken,
|
|
250
|
+
viewerUrl: url
|
|
251
|
+
},
|
|
252
|
+
null,
|
|
253
|
+
2
|
|
254
|
+
)
|
|
255
|
+
);
|
|
256
|
+
setActionNotice("Screen share details copied.", "success", 1800);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
setActionNotice(
|
|
259
|
+
error instanceof Error ? error.message : "Clipboard write failed.",
|
|
260
|
+
"error",
|
|
261
|
+
3200
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}, [hostSession, hostToken, setActionNotice]);
|
|
265
|
+
const openViewer = useCallback((url) => {
|
|
266
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
267
|
+
}, []);
|
|
268
|
+
const hostViewerUrl = hostSession && hostToken ? buildViewerUrl({ sessionId: hostSession.id, token: hostToken }) : null;
|
|
269
|
+
const remoteViewerUrl = remoteSessionId.trim() && remoteToken.trim() ? buildViewerUrl({
|
|
270
|
+
baseUrl: remoteBase,
|
|
271
|
+
sessionId: remoteSessionId.trim(),
|
|
272
|
+
token: remoteToken.trim()
|
|
273
|
+
}) : null;
|
|
274
|
+
if (focus === "chat") {
|
|
275
|
+
return /* @__PURE__ */ jsx(SurfaceEmptyState, { title: "Screen Share", body: "" });
|
|
276
|
+
}
|
|
277
|
+
return /* @__PURE__ */ jsxs("section", { className: "flex min-h-0 flex-col gap-3 p-3", children: [
|
|
278
|
+
/* @__PURE__ */ jsxs(SurfaceSection, { title: "Host", children: [
|
|
279
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
280
|
+
/* @__PURE__ */ jsx(
|
|
281
|
+
ScreenshareMetric,
|
|
282
|
+
{
|
|
283
|
+
icon: MonitorUp,
|
|
284
|
+
label: "Session",
|
|
285
|
+
value: hostSession?.status ?? "idle",
|
|
286
|
+
active: hostSession?.status === "active"
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsx(
|
|
290
|
+
ScreenshareMetric,
|
|
291
|
+
{
|
|
292
|
+
icon: PlugZap,
|
|
293
|
+
label: "Platform",
|
|
294
|
+
value: capabilities?.platform ?? hostSession?.platform ?? "desktop",
|
|
295
|
+
active: Boolean(capabilities?.platform || hostSession?.platform)
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
/* @__PURE__ */ jsx(
|
|
299
|
+
ScreenshareMetric,
|
|
300
|
+
{
|
|
301
|
+
icon: capabilities?.capabilities.headfulGui?.available ? CheckCircle2 : XCircle,
|
|
302
|
+
label: "GUI",
|
|
303
|
+
value: "GUI",
|
|
304
|
+
active: capabilities?.capabilities.headfulGui?.available
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
] }),
|
|
308
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-col gap-2", children: [
|
|
309
|
+
/* @__PURE__ */ jsxs(
|
|
310
|
+
ScreenshareActionButton,
|
|
311
|
+
{
|
|
312
|
+
agentId: "action-start-host",
|
|
313
|
+
label: hostSession?.status === "active" ? "Rotate host session" : "Start host session",
|
|
314
|
+
group: "host",
|
|
315
|
+
description: "Start or rotate the screen share session for this machine",
|
|
316
|
+
type: "button",
|
|
317
|
+
size: "sm",
|
|
318
|
+
variant: "default",
|
|
319
|
+
className: "h-10 w-full justify-center gap-2",
|
|
320
|
+
onClick: () => void startHostSession(),
|
|
321
|
+
disabled: busy === "start",
|
|
322
|
+
children: [
|
|
323
|
+
/* @__PURE__ */ jsx(MonitorUp, { className: "h-4 w-4" }),
|
|
324
|
+
hostSession?.status === "active" ? "Rotate session" : "Start session"
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
329
|
+
/* @__PURE__ */ jsxs(
|
|
330
|
+
ScreenshareActionButton,
|
|
331
|
+
{
|
|
332
|
+
agentId: "action-open-host-viewer",
|
|
333
|
+
label: "Open host viewer",
|
|
334
|
+
group: "host",
|
|
335
|
+
description: "Open the viewer for the host screen share session",
|
|
336
|
+
type: "button",
|
|
337
|
+
size: "sm",
|
|
338
|
+
variant: "outline",
|
|
339
|
+
className: "h-9 justify-center gap-1.5",
|
|
340
|
+
onClick: () => hostViewerUrl && openViewer(hostViewerUrl),
|
|
341
|
+
disabled: !hostViewerUrl,
|
|
342
|
+
children: [
|
|
343
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" }),
|
|
344
|
+
"Open"
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
),
|
|
348
|
+
/* @__PURE__ */ jsxs(
|
|
349
|
+
ScreenshareActionButton,
|
|
350
|
+
{
|
|
351
|
+
agentId: "action-copy-host-details",
|
|
352
|
+
label: "Copy host details",
|
|
353
|
+
group: "host",
|
|
354
|
+
description: "Copy the host session connection details to the clipboard",
|
|
355
|
+
type: "button",
|
|
356
|
+
size: "sm",
|
|
357
|
+
variant: "outline",
|
|
358
|
+
className: "h-9 justify-center gap-1.5",
|
|
359
|
+
onClick: () => void copyHostDetails(),
|
|
360
|
+
disabled: !hostSession || !hostToken,
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
|
|
363
|
+
"Copy"
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
),
|
|
367
|
+
/* @__PURE__ */ jsxs(
|
|
368
|
+
ScreenshareActionButton,
|
|
369
|
+
{
|
|
370
|
+
agentId: "action-stop-host",
|
|
371
|
+
label: "Stop host session",
|
|
372
|
+
group: "host",
|
|
373
|
+
description: "Stop the active host screen share session",
|
|
374
|
+
type: "button",
|
|
375
|
+
size: "sm",
|
|
376
|
+
variant: "outline",
|
|
377
|
+
className: "h-9 justify-center gap-1.5",
|
|
378
|
+
onClick: () => void stopHostSession(),
|
|
379
|
+
disabled: hostSession?.status !== "active",
|
|
380
|
+
children: [
|
|
381
|
+
/* @__PURE__ */ jsx(Power, { className: "h-4 w-4" }),
|
|
382
|
+
"Stop"
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
] })
|
|
387
|
+
] }),
|
|
388
|
+
hostSession ? /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-2 gap-2", children: [
|
|
389
|
+
/* @__PURE__ */ jsx(
|
|
390
|
+
ScreenshareMetric,
|
|
391
|
+
{
|
|
392
|
+
icon: MonitorUp,
|
|
393
|
+
label: "Frames",
|
|
394
|
+
value: hostSession.frameCount,
|
|
395
|
+
active: hostSession.frameCount > 0
|
|
396
|
+
}
|
|
397
|
+
),
|
|
398
|
+
/* @__PURE__ */ jsx(
|
|
399
|
+
ScreenshareMetric,
|
|
400
|
+
{
|
|
401
|
+
icon: PlugZap,
|
|
402
|
+
label: "Inputs",
|
|
403
|
+
value: hostSession.inputCount,
|
|
404
|
+
active: hostSession.inputCount > 0
|
|
405
|
+
}
|
|
406
|
+
),
|
|
407
|
+
/* @__PURE__ */ jsx(
|
|
408
|
+
ScreenshareMetric,
|
|
409
|
+
{
|
|
410
|
+
icon: RefreshCw,
|
|
411
|
+
label: "Last frame",
|
|
412
|
+
value: formatTime(hostSession.lastFrameAt),
|
|
413
|
+
active: hostSession.lastFrameAt !== null
|
|
414
|
+
}
|
|
415
|
+
),
|
|
416
|
+
/* @__PURE__ */ jsx(
|
|
417
|
+
ScreenshareMetric,
|
|
418
|
+
{
|
|
419
|
+
icon: Power,
|
|
420
|
+
label: "Last input",
|
|
421
|
+
value: formatTime(hostSession.lastInputAt),
|
|
422
|
+
active: hostSession.lastInputAt !== null
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
] }) : null
|
|
426
|
+
] }),
|
|
427
|
+
/* @__PURE__ */ jsxs(SurfaceSection, { title: "Connect", children: [
|
|
428
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
|
|
429
|
+
/* @__PURE__ */ jsx(
|
|
430
|
+
ScreenshareField,
|
|
431
|
+
{
|
|
432
|
+
agentId: "input-remote-base",
|
|
433
|
+
label: "Remote server URL",
|
|
434
|
+
group: "connect",
|
|
435
|
+
description: "Server URL of the remote machine to connect to",
|
|
436
|
+
value: remoteBase,
|
|
437
|
+
onChange: (event) => setRemoteBase(event.target.value),
|
|
438
|
+
placeholder: "Server URL",
|
|
439
|
+
className: "h-9 border-0 bg-transparent text-xs"
|
|
440
|
+
}
|
|
441
|
+
),
|
|
442
|
+
/* @__PURE__ */ jsx(
|
|
443
|
+
ScreenshareField,
|
|
444
|
+
{
|
|
445
|
+
agentId: "input-remote-session",
|
|
446
|
+
label: "Remote session id",
|
|
447
|
+
group: "connect",
|
|
448
|
+
description: "Session id of the remote screen share to connect to",
|
|
449
|
+
value: remoteSessionId,
|
|
450
|
+
onChange: (event) => setRemoteSessionId(event.target.value),
|
|
451
|
+
placeholder: "Session",
|
|
452
|
+
className: "h-9 border-0 bg-transparent text-xs"
|
|
453
|
+
}
|
|
454
|
+
),
|
|
455
|
+
/* @__PURE__ */ jsx(
|
|
456
|
+
ScreenshareField,
|
|
457
|
+
{
|
|
458
|
+
agentId: "input-remote-token",
|
|
459
|
+
label: "Remote session token",
|
|
460
|
+
group: "connect",
|
|
461
|
+
description: "Token of the remote screen share to connect to",
|
|
462
|
+
value: remoteToken,
|
|
463
|
+
onChange: (event) => setRemoteToken(event.target.value),
|
|
464
|
+
placeholder: "Token",
|
|
465
|
+
className: "h-9 border-0 bg-transparent text-xs"
|
|
466
|
+
}
|
|
467
|
+
)
|
|
468
|
+
] }),
|
|
469
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex gap-2", children: [
|
|
470
|
+
/* @__PURE__ */ jsxs(
|
|
471
|
+
ScreenshareActionButton,
|
|
472
|
+
{
|
|
473
|
+
agentId: "action-connect-remote",
|
|
474
|
+
label: "Connect to remote",
|
|
475
|
+
group: "connect",
|
|
476
|
+
description: "Open the viewer for the entered remote screen share",
|
|
477
|
+
type: "button",
|
|
478
|
+
size: "sm",
|
|
479
|
+
variant: remoteViewerUrl ? "default" : "outline",
|
|
480
|
+
className: "h-10 flex-1 justify-center gap-2",
|
|
481
|
+
onClick: () => remoteViewerUrl && openViewer(remoteViewerUrl),
|
|
482
|
+
disabled: !remoteViewerUrl,
|
|
483
|
+
children: [
|
|
484
|
+
/* @__PURE__ */ jsx(PlugZap, { className: "h-4 w-4" }),
|
|
485
|
+
"Connect"
|
|
486
|
+
]
|
|
487
|
+
}
|
|
488
|
+
),
|
|
489
|
+
/* @__PURE__ */ jsx(
|
|
490
|
+
ScreenshareActionButton,
|
|
491
|
+
{
|
|
492
|
+
agentId: "action-refresh-capabilities",
|
|
493
|
+
label: "Refresh capabilities",
|
|
494
|
+
group: "connect",
|
|
495
|
+
description: "Reload the host screen share capabilities",
|
|
496
|
+
type: "button",
|
|
497
|
+
size: "sm",
|
|
498
|
+
variant: "outline",
|
|
499
|
+
className: "h-10 w-10 justify-center gap-2 px-0",
|
|
500
|
+
onClick: () => void loadCapabilities(),
|
|
501
|
+
title: "Refresh capabilities",
|
|
502
|
+
children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" })
|
|
503
|
+
}
|
|
504
|
+
)
|
|
505
|
+
] })
|
|
506
|
+
] }),
|
|
507
|
+
capabilities ? /* @__PURE__ */ jsx(SurfaceSection, { title: "Capabilities", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: Object.entries(capabilities.capabilities).map(
|
|
508
|
+
([name, capability]) => /* @__PURE__ */ jsxs(
|
|
509
|
+
"div",
|
|
510
|
+
{
|
|
511
|
+
className: "flex min-h-14 items-center justify-center gap-2 px-3 py-2",
|
|
512
|
+
title: `${name}: ${capability.tool}`,
|
|
513
|
+
children: [
|
|
514
|
+
capability.available ? /* @__PURE__ */ jsx(CheckCircle2, { className: "h-4 w-4 text-accent" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-muted" }),
|
|
515
|
+
/* @__PURE__ */ jsx(
|
|
516
|
+
"span",
|
|
517
|
+
{
|
|
518
|
+
className: capability.available ? "truncate text-xs font-semibold text-txt" : "truncate text-xs font-semibold text-muted-strong",
|
|
519
|
+
children: name
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
name
|
|
525
|
+
)
|
|
526
|
+
) }) }) : null
|
|
527
|
+
] });
|
|
528
|
+
}
|
|
529
|
+
function ScreenshareTuiView() {
|
|
530
|
+
const [state, setState] = useState(null);
|
|
531
|
+
const [loading, setLoading] = useState(true);
|
|
532
|
+
const [lastAction, setLastAction] = useState("boot");
|
|
533
|
+
const [error, setError] = useState(null);
|
|
534
|
+
const refreshElement = useAgentElement({
|
|
535
|
+
id: "tui-refresh-sessions",
|
|
536
|
+
role: "button",
|
|
537
|
+
label: "Refresh sessions",
|
|
538
|
+
group: "tui-sessions",
|
|
539
|
+
description: "Reload the screen share sessions and capabilities",
|
|
540
|
+
status: loading ? "loading" : "idle"
|
|
541
|
+
});
|
|
542
|
+
const refresh = useCallback(async () => {
|
|
543
|
+
setLoading(true);
|
|
544
|
+
setError(null);
|
|
545
|
+
try {
|
|
546
|
+
const next = await loadScreenshareTuiState();
|
|
547
|
+
setState(next);
|
|
548
|
+
setLastAction("refresh");
|
|
549
|
+
} catch (caught) {
|
|
550
|
+
setState(null);
|
|
551
|
+
setError(
|
|
552
|
+
caught instanceof Error ? caught.message : "Screen share refresh failed"
|
|
553
|
+
);
|
|
554
|
+
} finally {
|
|
555
|
+
setLoading(false);
|
|
556
|
+
}
|
|
557
|
+
}, []);
|
|
558
|
+
useEffect(() => {
|
|
559
|
+
void refresh();
|
|
560
|
+
}, [refresh]);
|
|
561
|
+
const activeSessions = state?.sessions.sessions.filter((session) => session.status === "active") ?? [];
|
|
562
|
+
const viewState = {
|
|
563
|
+
viewType: "tui",
|
|
564
|
+
viewId: "screenshare",
|
|
565
|
+
platform: state?.capabilities.platform ?? null,
|
|
566
|
+
sessionCount: state?.sessions.sessions.length ?? 0,
|
|
567
|
+
activeSessionCount: activeSessions.length,
|
|
568
|
+
capabilities: state ? Object.fromEntries(
|
|
569
|
+
Object.entries(state.capabilities.capabilities).map(
|
|
570
|
+
([name, capability]) => [name, capability.available]
|
|
571
|
+
)
|
|
572
|
+
) : {},
|
|
573
|
+
loading,
|
|
574
|
+
lastAction,
|
|
575
|
+
error
|
|
576
|
+
};
|
|
577
|
+
return /* @__PURE__ */ jsxs(
|
|
578
|
+
"div",
|
|
579
|
+
{
|
|
580
|
+
"data-view-state": JSON.stringify(viewState),
|
|
581
|
+
style: {
|
|
582
|
+
minHeight: "100vh",
|
|
583
|
+
background: "#020617",
|
|
584
|
+
color: "#cbd5e1",
|
|
585
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
|
|
586
|
+
padding: 20
|
|
587
|
+
},
|
|
588
|
+
children: [
|
|
589
|
+
/* @__PURE__ */ jsxs(
|
|
590
|
+
"div",
|
|
591
|
+
{
|
|
592
|
+
"data-status": loading ? "loading" : "ready",
|
|
593
|
+
style: { color: "#94a3b8", marginBottom: 16 },
|
|
594
|
+
children: [
|
|
595
|
+
loading ? "loading" : state?.capabilities.platform ?? "unknown",
|
|
596
|
+
" |",
|
|
597
|
+
" ",
|
|
598
|
+
activeSessions.length,
|
|
599
|
+
" active sessions | ",
|
|
600
|
+
lastAction
|
|
601
|
+
]
|
|
602
|
+
}
|
|
603
|
+
),
|
|
604
|
+
/* @__PURE__ */ jsxs(
|
|
605
|
+
"div",
|
|
606
|
+
{
|
|
607
|
+
style: {
|
|
608
|
+
display: "grid",
|
|
609
|
+
gridTemplateColumns: "1fr",
|
|
610
|
+
gap: 16
|
|
611
|
+
},
|
|
612
|
+
children: [
|
|
613
|
+
/* @__PURE__ */ jsxs(
|
|
614
|
+
"section",
|
|
615
|
+
{
|
|
616
|
+
"aria-label": "Screen share sessions",
|
|
617
|
+
style: {
|
|
618
|
+
padding: "8px 0"
|
|
619
|
+
},
|
|
620
|
+
children: [
|
|
621
|
+
/* @__PURE__ */ jsxs(
|
|
622
|
+
"div",
|
|
623
|
+
{
|
|
624
|
+
style: {
|
|
625
|
+
display: "flex",
|
|
626
|
+
alignItems: "center",
|
|
627
|
+
justifyContent: "space-between",
|
|
628
|
+
marginBottom: 10
|
|
629
|
+
},
|
|
630
|
+
children: [
|
|
631
|
+
/* @__PURE__ */ jsx("strong", { style: { color: "#e2e8f0" }, children: "sessions" }),
|
|
632
|
+
/* @__PURE__ */ jsx(
|
|
633
|
+
"button",
|
|
634
|
+
{
|
|
635
|
+
ref: refreshElement.ref,
|
|
636
|
+
type: "button",
|
|
637
|
+
"aria-label": "Refresh sessions",
|
|
638
|
+
onClick: () => void refresh(),
|
|
639
|
+
disabled: loading,
|
|
640
|
+
style: {
|
|
641
|
+
background: "transparent",
|
|
642
|
+
color: "#a7f3d0",
|
|
643
|
+
border: 0,
|
|
644
|
+
padding: "4px 8px",
|
|
645
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
646
|
+
fontFamily: "inherit"
|
|
647
|
+
},
|
|
648
|
+
...refreshElement.agentProps,
|
|
649
|
+
children: "refresh"
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
),
|
|
655
|
+
error && /* @__PURE__ */ jsx("div", { style: { color: "#fca5a5" }, children: error }),
|
|
656
|
+
(state?.sessions.sessions ?? []).map((session) => /* @__PURE__ */ jsxs(
|
|
657
|
+
"div",
|
|
658
|
+
{
|
|
659
|
+
style: {
|
|
660
|
+
padding: "8px 0"
|
|
661
|
+
},
|
|
662
|
+
children: [
|
|
663
|
+
/* @__PURE__ */ jsxs("div", { style: { color: "#e2e8f0" }, children: [
|
|
664
|
+
session.id,
|
|
665
|
+
" / ",
|
|
666
|
+
session.status
|
|
667
|
+
] }),
|
|
668
|
+
/* @__PURE__ */ jsxs("div", { style: { color: "#94a3b8" }, children: [
|
|
669
|
+
session.label,
|
|
670
|
+
" frames ",
|
|
671
|
+
session.frameCount,
|
|
672
|
+
" inputs",
|
|
673
|
+
" ",
|
|
674
|
+
session.inputCount
|
|
675
|
+
] }),
|
|
676
|
+
/* @__PURE__ */ jsxs("div", { style: { color: "#64748b" }, children: [
|
|
677
|
+
"last frame ",
|
|
678
|
+
formatTime(session.lastFrameAt),
|
|
679
|
+
" / last input",
|
|
680
|
+
" ",
|
|
681
|
+
formatTime(session.lastInputAt)
|
|
682
|
+
] })
|
|
683
|
+
]
|
|
684
|
+
},
|
|
685
|
+
session.id
|
|
686
|
+
))
|
|
687
|
+
]
|
|
688
|
+
}
|
|
689
|
+
),
|
|
690
|
+
/* @__PURE__ */ jsxs(
|
|
691
|
+
"section",
|
|
692
|
+
{
|
|
693
|
+
"aria-label": "Screen share capabilities",
|
|
694
|
+
style: {
|
|
695
|
+
padding: "8px 0"
|
|
696
|
+
},
|
|
697
|
+
children: [
|
|
698
|
+
/* @__PURE__ */ jsx("strong", { style: { color: "#e2e8f0" }, children: "capabilities" }),
|
|
699
|
+
/* @__PURE__ */ jsxs("div", { style: { color: "#64748b", margin: "6px 0 14px" }, children: [
|
|
700
|
+
Object.values(state?.capabilities.capabilities ?? {}).filter(
|
|
701
|
+
(capability) => capability.available
|
|
702
|
+
).length,
|
|
703
|
+
" ",
|
|
704
|
+
"live / ",
|
|
705
|
+
state?.sessions.sessions.length ?? 0,
|
|
706
|
+
" sessions"
|
|
707
|
+
] }),
|
|
708
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
709
|
+
/* @__PURE__ */ jsx("span", { style: { color: "#64748b" }, children: "platform" }),
|
|
710
|
+
" ",
|
|
711
|
+
state?.capabilities.platform ?? "unknown"
|
|
712
|
+
] }),
|
|
713
|
+
Object.entries(state?.capabilities.capabilities ?? {}).map(
|
|
714
|
+
([name, capability]) => /* @__PURE__ */ jsxs("div", { style: { padding: "6px 0" }, children: [
|
|
715
|
+
/* @__PURE__ */ jsx(
|
|
716
|
+
"span",
|
|
717
|
+
{
|
|
718
|
+
style: {
|
|
719
|
+
color: capability.available ? "#a7f3d0" : "#fca5a5"
|
|
720
|
+
},
|
|
721
|
+
children: capability.available ? "ok" : "off"
|
|
722
|
+
}
|
|
723
|
+
),
|
|
724
|
+
" ",
|
|
725
|
+
name,
|
|
726
|
+
" via ",
|
|
727
|
+
capability.tool
|
|
728
|
+
] }, name)
|
|
729
|
+
)
|
|
730
|
+
]
|
|
731
|
+
}
|
|
732
|
+
)
|
|
733
|
+
]
|
|
734
|
+
}
|
|
735
|
+
)
|
|
736
|
+
]
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
import { ScreenshareView } from "../components/ScreenshareView.js";
|
|
741
|
+
export {
|
|
742
|
+
ScreenshareOperatorSurface,
|
|
743
|
+
ScreenshareTuiView,
|
|
744
|
+
ScreenshareView
|
|
745
|
+
};
|
|
746
|
+
//# sourceMappingURL=ScreenshareOperatorSurface.js.map
|