@elizaos/plugin-screenshare 2.0.3-beta.5 → 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.
Files changed (47) hide show
  1. package/dist/components/ScreenshareSpatialView.d.ts +61 -0
  2. package/dist/components/ScreenshareSpatialView.d.ts.map +1 -0
  3. package/dist/components/ScreenshareSpatialView.js +206 -0
  4. package/dist/components/ScreenshareSpatialView.js.map +1 -0
  5. package/dist/components/ScreenshareView.d.ts +13 -0
  6. package/dist/components/ScreenshareView.d.ts.map +1 -0
  7. package/dist/components/ScreenshareView.js +263 -0
  8. package/dist/components/ScreenshareView.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +58 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/register-terminal-view.d.ts +15 -0
  14. package/dist/register-terminal-view.d.ts.map +1 -0
  15. package/dist/register-terminal-view.js +27 -0
  16. package/dist/register-terminal-view.js.map +1 -0
  17. package/dist/routes.d.ts +8 -0
  18. package/dist/routes.d.ts.map +1 -0
  19. package/dist/routes.js +639 -0
  20. package/dist/routes.js.map +1 -0
  21. package/dist/session-store.d.ts +44 -0
  22. package/dist/session-store.d.ts.map +1 -0
  23. package/dist/session-store.js +200 -0
  24. package/dist/session-store.js.map +1 -0
  25. package/dist/ui/ScreenshareOperatorSurface.d.ts +5 -0
  26. package/dist/ui/ScreenshareOperatorSurface.d.ts.map +1 -0
  27. package/dist/ui/ScreenshareOperatorSurface.helpers.d.ts +40 -0
  28. package/dist/ui/ScreenshareOperatorSurface.helpers.d.ts.map +1 -0
  29. package/dist/ui/ScreenshareOperatorSurface.helpers.js +47 -0
  30. package/dist/ui/ScreenshareOperatorSurface.helpers.js.map +1 -0
  31. package/dist/ui/ScreenshareOperatorSurface.interact.d.ts +2 -0
  32. package/dist/ui/ScreenshareOperatorSurface.interact.d.ts.map +1 -0
  33. package/dist/ui/ScreenshareOperatorSurface.interact.js +100 -0
  34. package/dist/ui/ScreenshareOperatorSurface.interact.js.map +1 -0
  35. package/dist/ui/ScreenshareOperatorSurface.js +746 -0
  36. package/dist/ui/ScreenshareOperatorSurface.js.map +1 -0
  37. package/dist/ui/index.d.ts +3 -0
  38. package/dist/ui/index.d.ts.map +1 -0
  39. package/dist/ui/index.js +10 -0
  40. package/dist/ui/index.js.map +1 -0
  41. package/dist/ui/screenshare-view-bundle.d.ts +3 -0
  42. package/dist/ui/screenshare-view-bundle.d.ts.map +1 -0
  43. package/dist/ui/screenshare-view-bundle.js +7 -0
  44. package/dist/ui/screenshare-view-bundle.js.map +1 -0
  45. package/dist/views/bundle.js +507 -0
  46. package/dist/views/bundle.js.map +1 -0
  47. package/package.json +8 -8
@@ -0,0 +1,61 @@
1
+ /**
2
+ * ScreenshareSpatialView - the screen-share operator surface authored once with
3
+ * the spatial vocabulary, so it renders correctly wherever it is displayed:
4
+ *
5
+ * - GUI / XR - mounted in `<SpatialSurface>` (DOM; XR scales up).
6
+ * - TUI - rendered to real terminal lines by the agent terminal, via
7
+ * `registerSpatialTerminalView` (see `register-terminal-view.tsx`).
8
+ *
9
+ * It is purely presentational (a snapshot + an action callback in, primitives
10
+ * out) and imports only the cross-modality primitives, so it is safe to render
11
+ * in the Node agent process where the terminal lives (no DOM/browser import).
12
+ *
13
+ * The actual screen pixels are streamed in the external viewer page; this view
14
+ * is the session manager + capability dashboard (status, platform, frame/input
15
+ * counters, capabilities, connection details, and operator actions).
16
+ */
17
+ export type ScreenshareSessionStatus = "active" | "stopped" | "idle";
18
+ export interface ScreenshareSessionSnapshot {
19
+ id: string;
20
+ label: string;
21
+ status: ScreenshareSessionStatus;
22
+ platform: string;
23
+ frameCount: number;
24
+ inputCount: number;
25
+ /** Pre-formatted clock/relative time, or null when never. */
26
+ lastFrameAt: string | null;
27
+ lastInputAt: string | null;
28
+ }
29
+ export interface ScreenshareCapabilitySnapshot {
30
+ name: string;
31
+ available: boolean;
32
+ /** Backing tool/primitive name (e.g. the computeruse provider). */
33
+ tool: string;
34
+ }
35
+ export interface ScreenshareConnectionSnapshot {
36
+ /** Session token (already redacted to a short prefix by the host). */
37
+ token: string;
38
+ sessionId: string;
39
+ baseUrl: string;
40
+ }
41
+ export interface ScreenshareSnapshot {
42
+ platform: string;
43
+ session: ScreenshareSessionSnapshot | null;
44
+ capabilities: ScreenshareCapabilitySnapshot[];
45
+ host: ScreenshareConnectionSnapshot | null;
46
+ remote: ScreenshareConnectionSnapshot | null;
47
+ loading?: boolean;
48
+ busy?: string | null;
49
+ error?: string | null;
50
+ }
51
+ export interface ScreenshareSpatialViewProps {
52
+ snapshot: ScreenshareSnapshot;
53
+ /**
54
+ * Dispatch by action id: `start`, `stop`, `rotate`, `copy`, `open-viewer`,
55
+ * `connect`, `refresh`, plus the editable remote-connection fields
56
+ * `remote-base:<value>`, `remote-session:<value>`, `remote-token:<value>`.
57
+ */
58
+ onAction?: (action: string) => void;
59
+ }
60
+ export declare function ScreenshareSpatialView({ snapshot, onAction, }: ScreenshareSpatialViewProps): import("react/jsx-runtime").JSX.Element;
61
+ //# sourceMappingURL=ScreenshareSpatialView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScreenshareSpatialView.d.ts","sourceRoot":"","sources":["../../src/components/ScreenshareSpatialView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAcH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAErE,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,wBAAwB,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,6BAA6B;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC3C,YAAY,EAAE,6BAA6B,EAAE,CAAC;IAC9C,IAAI,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC3C,MAAM,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAiBD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,mBAAmB,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,QAAQ,GACT,EAAE,2BAA2B,2CAyL7B"}
@@ -0,0 +1,206 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import {
3
+ Button,
4
+ Card,
5
+ Divider,
6
+ Field,
7
+ HStack,
8
+ List,
9
+ Text,
10
+ VStack
11
+ } from "@elizaos/ui/spatial";
12
+ function statusTone(status) {
13
+ switch (status) {
14
+ case "active":
15
+ return "success";
16
+ case "stopped":
17
+ return "danger";
18
+ default:
19
+ return "muted";
20
+ }
21
+ }
22
+ function capabilityMark(available) {
23
+ return available ? "ok" : "off";
24
+ }
25
+ function ScreenshareSpatialView({
26
+ snapshot,
27
+ onAction
28
+ }) {
29
+ const dispatch = (action) => () => onAction?.(action);
30
+ const session = snapshot.session;
31
+ const isActive = session?.status === "active";
32
+ const liveCaps = snapshot.capabilities.filter((cap) => cap.available).length;
33
+ const remoteReady = Boolean(
34
+ snapshot.remote?.sessionId.trim() && snapshot.remote?.token.trim()
35
+ );
36
+ return /* @__PURE__ */ jsxs(Card, { gap: 1, padding: 1, children: [
37
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, align: "center", children: [
38
+ /* @__PURE__ */ jsx(
39
+ Text,
40
+ {
41
+ style: "caption",
42
+ tone: isActive ? "success" : statusTone(session?.status ?? "idle"),
43
+ grow: 1,
44
+ children: snapshot.loading ? "loading" : session?.status ?? "idle"
45
+ }
46
+ ),
47
+ /* @__PURE__ */ jsx(Text, { style: "caption", tone: "muted", children: snapshot.platform || "desktop" })
48
+ ] }),
49
+ snapshot.error ? /* @__PURE__ */ jsx(Text, { tone: "danger", style: "caption", children: snapshot.error }) : null,
50
+ /* @__PURE__ */ jsx(Divider, { label: "session" }),
51
+ session ? /* @__PURE__ */ jsxs(VStack, { gap: 0, children: [
52
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, align: "center", children: [
53
+ /* @__PURE__ */ jsx(Text, { tone: statusTone(session.status), children: session.status === "active" ? ">" : "." }),
54
+ /* @__PURE__ */ jsx(Text, { bold: true, wrap: false, grow: 1, children: session.label || session.id }),
55
+ /* @__PURE__ */ jsx(Text, { style: "caption", tone: "muted", children: session.platform })
56
+ ] }),
57
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, children: [
58
+ /* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", grow: 1, children: [
59
+ "frames ",
60
+ session.frameCount
61
+ ] }),
62
+ /* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", grow: 1, children: [
63
+ "inputs ",
64
+ session.inputCount
65
+ ] })
66
+ ] }),
67
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, children: [
68
+ /* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", grow: 1, children: [
69
+ "last frame ",
70
+ session.lastFrameAt ?? "never"
71
+ ] }),
72
+ /* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", grow: 1, children: [
73
+ "last input ",
74
+ session.lastInputAt ?? "never"
75
+ ] })
76
+ ] })
77
+ ] }) : /* @__PURE__ */ jsx(Text, { tone: "muted", align: "center", style: "caption", children: "Idle" }),
78
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, wrap: true, children: [
79
+ /* @__PURE__ */ jsx(
80
+ Button,
81
+ {
82
+ grow: 1,
83
+ agent: "start",
84
+ disabled: snapshot.busy === "start",
85
+ onPress: dispatch(isActive ? "rotate" : "start"),
86
+ children: isActive ? "Rotate" : "Start"
87
+ }
88
+ ),
89
+ /* @__PURE__ */ jsx(
90
+ Button,
91
+ {
92
+ variant: "outline",
93
+ tone: "default",
94
+ grow: 1,
95
+ agent: "open-viewer",
96
+ disabled: !snapshot.host,
97
+ onPress: dispatch("open-viewer"),
98
+ children: "Open"
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsx(
102
+ Button,
103
+ {
104
+ variant: "outline",
105
+ tone: "default",
106
+ agent: "copy",
107
+ disabled: !snapshot.host,
108
+ onPress: dispatch("copy"),
109
+ children: "Copy"
110
+ }
111
+ ),
112
+ /* @__PURE__ */ jsx(
113
+ Button,
114
+ {
115
+ variant: "ghost",
116
+ tone: "danger",
117
+ agent: "stop",
118
+ disabled: !isActive,
119
+ onPress: dispatch("stop"),
120
+ children: "Stop"
121
+ }
122
+ )
123
+ ] }),
124
+ /* @__PURE__ */ jsx(Divider, { label: "capabilities" }),
125
+ /* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", children: [
126
+ liveCaps,
127
+ " live / ",
128
+ snapshot.capabilities.length
129
+ ] }),
130
+ snapshot.capabilities.length === 0 ? /* @__PURE__ */ jsx(Text, { tone: "muted", align: "center", style: "caption", children: "None" }) : /* @__PURE__ */ jsx(List, { gap: 0, children: snapshot.capabilities.map((cap) => /* @__PURE__ */ jsxs(
131
+ HStack,
132
+ {
133
+ gap: 1,
134
+ align: "center",
135
+ agent: `cap-${cap.name}`,
136
+ children: [
137
+ /* @__PURE__ */ jsx(Text, { tone: cap.available ? "success" : "danger", children: capabilityMark(cap.available) }),
138
+ /* @__PURE__ */ jsx(Text, { bold: true, wrap: false, grow: 1, children: cap.name }),
139
+ /* @__PURE__ */ jsx(Text, { style: "caption", tone: "muted", wrap: false, children: cap.tool })
140
+ ]
141
+ },
142
+ cap.name
143
+ )) }),
144
+ /* @__PURE__ */ jsx(Divider, { label: "connect" }),
145
+ /* @__PURE__ */ jsx(
146
+ Field,
147
+ {
148
+ label: "Remote server URL",
149
+ value: snapshot.remote?.baseUrl ?? "",
150
+ placeholder: "Server URL",
151
+ agent: "input-remote-base",
152
+ onChange: (value) => onAction?.(`remote-base:${value}`)
153
+ }
154
+ ),
155
+ /* @__PURE__ */ jsx(
156
+ Field,
157
+ {
158
+ label: "Remote session id",
159
+ value: snapshot.remote?.sessionId ?? "",
160
+ placeholder: "Session",
161
+ agent: "input-remote-session",
162
+ onChange: (value) => onAction?.(`remote-session:${value}`)
163
+ }
164
+ ),
165
+ /* @__PURE__ */ jsx(
166
+ Field,
167
+ {
168
+ label: "Remote session token",
169
+ value: snapshot.remote?.token ?? "",
170
+ placeholder: "Token",
171
+ kind: "password",
172
+ agent: "input-remote-token",
173
+ onChange: (value) => onAction?.(`remote-token:${value}`)
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsxs(HStack, { gap: 1, children: [
177
+ /* @__PURE__ */ jsx(
178
+ Button,
179
+ {
180
+ grow: 1,
181
+ variant: remoteReady ? "solid" : "outline",
182
+ tone: remoteReady ? "primary" : "default",
183
+ agent: "connect",
184
+ disabled: !remoteReady,
185
+ onPress: dispatch("connect"),
186
+ children: "Connect"
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsx(
190
+ Button,
191
+ {
192
+ variant: "outline",
193
+ tone: "default",
194
+ agent: "refresh",
195
+ disabled: snapshot.loading,
196
+ onPress: dispatch("refresh"),
197
+ children: "Refresh"
198
+ }
199
+ )
200
+ ] })
201
+ ] });
202
+ }
203
+ export {
204
+ ScreenshareSpatialView
205
+ };
206
+ //# sourceMappingURL=ScreenshareSpatialView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/ScreenshareSpatialView.tsx"],"sourcesContent":["/**\n * ScreenshareSpatialView - the screen-share operator surface authored once with\n * the spatial vocabulary, so it renders correctly wherever it is displayed:\n *\n * - GUI / XR - mounted in `<SpatialSurface>` (DOM; XR scales up).\n * - TUI - rendered to real terminal lines by the agent terminal, via\n * `registerSpatialTerminalView` (see `register-terminal-view.tsx`).\n *\n * It is purely presentational (a snapshot + an action callback in, primitives\n * out) and imports only the cross-modality primitives, so it is safe to render\n * in the Node agent process where the terminal lives (no DOM/browser import).\n *\n * The actual screen pixels are streamed in the external viewer page; this view\n * is the session manager + capability dashboard (status, platform, frame/input\n * counters, capabilities, connection details, and operator actions).\n */\n\nimport {\n Button,\n Card,\n Divider,\n Field,\n HStack,\n List,\n type SpatialTone,\n Text,\n VStack,\n} from \"@elizaos/ui/spatial\";\n\nexport type ScreenshareSessionStatus = \"active\" | \"stopped\" | \"idle\";\n\nexport interface ScreenshareSessionSnapshot {\n id: string;\n label: string;\n status: ScreenshareSessionStatus;\n platform: string;\n frameCount: number;\n inputCount: number;\n /** Pre-formatted clock/relative time, or null when never. */\n lastFrameAt: string | null;\n lastInputAt: string | null;\n}\n\nexport interface ScreenshareCapabilitySnapshot {\n name: string;\n available: boolean;\n /** Backing tool/primitive name (e.g. the computeruse provider). */\n tool: string;\n}\n\nexport interface ScreenshareConnectionSnapshot {\n /** Session token (already redacted to a short prefix by the host). */\n token: string;\n sessionId: string;\n baseUrl: string;\n}\n\nexport interface ScreenshareSnapshot {\n platform: string;\n session: ScreenshareSessionSnapshot | null;\n capabilities: ScreenshareCapabilitySnapshot[];\n host: ScreenshareConnectionSnapshot | null;\n remote: ScreenshareConnectionSnapshot | null;\n loading?: boolean;\n busy?: string | null;\n error?: string | null;\n}\n\nfunction statusTone(status: ScreenshareSessionStatus): SpatialTone {\n switch (status) {\n case \"active\":\n return \"success\";\n case \"stopped\":\n return \"danger\";\n default:\n return \"muted\";\n }\n}\n\nfunction capabilityMark(available: boolean): string {\n return available ? \"ok\" : \"off\";\n}\n\nexport interface ScreenshareSpatialViewProps {\n snapshot: ScreenshareSnapshot;\n /**\n * Dispatch by action id: `start`, `stop`, `rotate`, `copy`, `open-viewer`,\n * `connect`, `refresh`, plus the editable remote-connection fields\n * `remote-base:<value>`, `remote-session:<value>`, `remote-token:<value>`.\n */\n onAction?: (action: string) => void;\n}\n\nexport function ScreenshareSpatialView({\n snapshot,\n onAction,\n}: ScreenshareSpatialViewProps) {\n const dispatch = (action: string) => () => onAction?.(action);\n const session = snapshot.session;\n const isActive = session?.status === \"active\";\n const liveCaps = snapshot.capabilities.filter((cap) => cap.available).length;\n // Connect is reachable once the draft has both a session id and a token; the\n // base URL is optional (defaults to this host).\n const remoteReady = Boolean(\n snapshot.remote?.sessionId.trim() && snapshot.remote?.token.trim(),\n );\n\n return (\n <Card gap={1} padding={1}>\n <HStack gap={1} align=\"center\">\n <Text\n style=\"caption\"\n tone={isActive ? \"success\" : statusTone(session?.status ?? \"idle\")}\n grow={1}\n >\n {snapshot.loading ? \"loading\" : (session?.status ?? \"idle\")}\n </Text>\n <Text style=\"caption\" tone=\"muted\">\n {snapshot.platform || \"desktop\"}\n </Text>\n </HStack>\n\n {snapshot.error ? (\n <Text tone=\"danger\" style=\"caption\">\n {snapshot.error}\n </Text>\n ) : null}\n\n <Divider label=\"session\" />\n {session ? (\n <VStack gap={0}>\n <HStack gap={1} align=\"center\">\n <Text tone={statusTone(session.status)}>\n {session.status === \"active\" ? \">\" : \".\"}\n </Text>\n <Text bold wrap={false} grow={1}>\n {session.label || session.id}\n </Text>\n <Text style=\"caption\" tone=\"muted\">\n {session.platform}\n </Text>\n </HStack>\n <HStack gap={1}>\n <Text style=\"caption\" tone=\"muted\" grow={1}>\n frames {session.frameCount}\n </Text>\n <Text style=\"caption\" tone=\"muted\" grow={1}>\n inputs {session.inputCount}\n </Text>\n </HStack>\n <HStack gap={1}>\n <Text style=\"caption\" tone=\"muted\" grow={1}>\n last frame {session.lastFrameAt ?? \"never\"}\n </Text>\n <Text style=\"caption\" tone=\"muted\" grow={1}>\n last input {session.lastInputAt ?? \"never\"}\n </Text>\n </HStack>\n </VStack>\n ) : (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n Idle\n </Text>\n )}\n\n <HStack gap={1} wrap>\n <Button\n grow={1}\n agent=\"start\"\n disabled={snapshot.busy === \"start\"}\n onPress={dispatch(isActive ? \"rotate\" : \"start\")}\n >\n {isActive ? \"Rotate\" : \"Start\"}\n </Button>\n <Button\n variant=\"outline\"\n tone=\"default\"\n grow={1}\n agent=\"open-viewer\"\n disabled={!snapshot.host}\n onPress={dispatch(\"open-viewer\")}\n >\n Open\n </Button>\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent=\"copy\"\n disabled={!snapshot.host}\n onPress={dispatch(\"copy\")}\n >\n Copy\n </Button>\n <Button\n variant=\"ghost\"\n tone=\"danger\"\n agent=\"stop\"\n disabled={!isActive}\n onPress={dispatch(\"stop\")}\n >\n Stop\n </Button>\n </HStack>\n\n <Divider label=\"capabilities\" />\n <Text style=\"caption\" tone=\"muted\">\n {liveCaps} live / {snapshot.capabilities.length}\n </Text>\n {snapshot.capabilities.length === 0 ? (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n None\n </Text>\n ) : (\n <List gap={0}>\n {snapshot.capabilities.map((cap) => (\n <HStack\n key={cap.name}\n gap={1}\n align=\"center\"\n agent={`cap-${cap.name}`}\n >\n <Text tone={cap.available ? \"success\" : \"danger\"}>\n {capabilityMark(cap.available)}\n </Text>\n <Text bold wrap={false} grow={1}>\n {cap.name}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {cap.tool}\n </Text>\n </HStack>\n ))}\n </List>\n )}\n\n <Divider label=\"connect\" />\n <Field\n label=\"Remote server URL\"\n value={snapshot.remote?.baseUrl ?? \"\"}\n placeholder=\"Server URL\"\n agent=\"input-remote-base\"\n onChange={(value) => onAction?.(`remote-base:${value}`)}\n />\n <Field\n label=\"Remote session id\"\n value={snapshot.remote?.sessionId ?? \"\"}\n placeholder=\"Session\"\n agent=\"input-remote-session\"\n onChange={(value) => onAction?.(`remote-session:${value}`)}\n />\n <Field\n label=\"Remote session token\"\n value={snapshot.remote?.token ?? \"\"}\n placeholder=\"Token\"\n kind=\"password\"\n agent=\"input-remote-token\"\n onChange={(value) => onAction?.(`remote-token:${value}`)}\n />\n <HStack gap={1}>\n <Button\n grow={1}\n variant={remoteReady ? \"solid\" : \"outline\"}\n tone={remoteReady ? \"primary\" : \"default\"}\n agent=\"connect\"\n disabled={!remoteReady}\n onPress={dispatch(\"connect\")}\n >\n Connect\n </Button>\n <Button\n variant=\"outline\"\n tone=\"default\"\n agent=\"refresh\"\n disabled={snapshot.loading}\n onPress={dispatch(\"refresh\")}\n >\n Refresh\n </Button>\n </HStack>\n </Card>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ScreenshareView — the single GUI/XR data wrapper for the Screen Share surface.
3
+ *
4
+ * It owns the live operator data (capability fetch + poll, launched-session
5
+ * load, host start/stop/rotate, copy/open-viewer, remote connect, refresh) and
6
+ * renders the one presentational {@link ScreenshareSpatialView} inside a
7
+ * {@link SpatialSurface}. Omitting the `modality` prop lets `SpatialSurface`
8
+ * auto-detect GUI vs XR via `window.__elizaXRContext`, so the SAME component
9
+ * serves both surfaces. The TUI surface renders the same `ScreenshareSpatialView`
10
+ * through the terminal registry (see `register-terminal-view.tsx`).
11
+ */
12
+ export declare function ScreenshareView(): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=ScreenshareView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScreenshareView.d.ts","sourceRoot":"","sources":["../../src/components/ScreenshareView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAyDH,wBAAgB,eAAe,4CA8P9B"}
@@ -0,0 +1,263 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import {
3
+ client,
4
+ selectLatestRunForApp,
5
+ useAppSelector
6
+ } from "@elizaos/ui";
7
+ import { SpatialSurface } from "@elizaos/ui/spatial";
8
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
9
+ import {
10
+ buildViewerUrl,
11
+ fetchJson
12
+ } from "../ui/ScreenshareOperatorSurface.helpers.js";
13
+ import {
14
+ ScreenshareSpatialView
15
+ } from "./ScreenshareSpatialView.js";
16
+ const APP_NAME = "@elizaos/plugin-screenshare";
17
+ function formatTime(value) {
18
+ if (!value) return null;
19
+ const date = new Date(value);
20
+ return Number.isNaN(date.getTime()) ? null : date.toLocaleTimeString();
21
+ }
22
+ function parseViewerSession(viewerUrl) {
23
+ if (!viewerUrl) return null;
24
+ try {
25
+ const url = new URL(viewerUrl, window.location.origin);
26
+ const sessionId = url.searchParams.get("sessionId")?.trim();
27
+ const token = url.searchParams.get("token")?.trim();
28
+ return sessionId && token ? { sessionId, token } : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function toCapabilitySnapshots(capabilities) {
34
+ if (!capabilities) return [];
35
+ return Object.entries(capabilities.capabilities).map(([name, capability]) => ({
36
+ name,
37
+ available: capability.available,
38
+ tool: capability.tool
39
+ }));
40
+ }
41
+ function ScreenshareView() {
42
+ const appRuns = useAppSelector((s) => s.appRuns);
43
+ const { run } = useMemo(
44
+ () => selectLatestRunForApp(APP_NAME, appRuns),
45
+ [appRuns]
46
+ );
47
+ const launchedSession = useMemo(
48
+ () => parseViewerSession(run?.viewer?.url),
49
+ [run?.viewer?.url]
50
+ );
51
+ const [capabilities, setCapabilities] = useState(
52
+ null
53
+ );
54
+ const [hostSession, setHostSession] = useState(null);
55
+ const [hostToken, setHostToken] = useState(
56
+ launchedSession?.token ?? ""
57
+ );
58
+ const [remoteBase, setRemoteBase] = useState("");
59
+ const [remoteSessionId, setRemoteSessionId] = useState("");
60
+ const [remoteToken, setRemoteToken] = useState("");
61
+ const [busy, setBusy] = useState(null);
62
+ const [loading, setLoading] = useState(false);
63
+ const [error, setError] = useState(null);
64
+ const loadCapabilities = useCallback(async () => {
65
+ setLoading(true);
66
+ setError(null);
67
+ try {
68
+ const next = await fetchJson(
69
+ "/api/apps/screenshare/capabilities"
70
+ );
71
+ setCapabilities(next);
72
+ } catch (caught) {
73
+ setError(
74
+ caught instanceof Error ? caught.message : "Failed to load capabilities."
75
+ );
76
+ } finally {
77
+ setLoading(false);
78
+ }
79
+ }, []);
80
+ const autoLoadedRef = useRef(false);
81
+ useEffect(() => {
82
+ if (!autoLoadedRef.current) {
83
+ autoLoadedRef.current = true;
84
+ void loadCapabilities();
85
+ }
86
+ const interval = setInterval(() => {
87
+ void loadCapabilities();
88
+ }, 2e4);
89
+ return () => clearInterval(interval);
90
+ }, [loadCapabilities]);
91
+ useEffect(() => {
92
+ if (!launchedSession) return;
93
+ setHostToken(launchedSession.token);
94
+ void fetchJson(
95
+ `/api/apps/screenshare/session/${encodeURIComponent(
96
+ launchedSession.sessionId
97
+ )}?token=${encodeURIComponent(launchedSession.token)}`
98
+ ).then((next) => setHostSession(next.session)).catch(
99
+ (caught) => setError(
100
+ caught instanceof Error ? caught.message : "Failed to load screen share session."
101
+ )
102
+ );
103
+ }, [launchedSession]);
104
+ const startHostSession = useCallback(async () => {
105
+ setBusy("start");
106
+ setError(null);
107
+ try {
108
+ const response = await fetchJson(
109
+ "/api/apps/screenshare/session",
110
+ {
111
+ method: "POST",
112
+ body: JSON.stringify({ label: "This machine" })
113
+ }
114
+ );
115
+ setHostSession(response.session);
116
+ setHostToken(response.token);
117
+ } catch (caught) {
118
+ setError(
119
+ caught instanceof Error ? caught.message : "Failed to start session."
120
+ );
121
+ } finally {
122
+ setBusy(null);
123
+ }
124
+ }, []);
125
+ const stopHostSession = useCallback(async () => {
126
+ if (!hostSession || !hostToken) return;
127
+ setBusy("stop");
128
+ setError(null);
129
+ try {
130
+ const response = await fetchJson(
131
+ `/api/apps/screenshare/session/${encodeURIComponent(
132
+ hostSession.id
133
+ )}/stop`,
134
+ {
135
+ method: "POST",
136
+ body: JSON.stringify({ token: hostToken }),
137
+ headers: { "X-Screenshare-Token": hostToken }
138
+ }
139
+ );
140
+ setHostSession(response.session);
141
+ } catch (caught) {
142
+ setError(
143
+ caught instanceof Error ? caught.message : "Failed to stop session."
144
+ );
145
+ } finally {
146
+ setBusy(null);
147
+ }
148
+ }, [hostSession, hostToken]);
149
+ const copyHostDetails = useCallback(async () => {
150
+ if (!hostSession || !hostToken) return;
151
+ const viewerUrl = buildViewerUrl({
152
+ sessionId: hostSession.id,
153
+ token: hostToken
154
+ });
155
+ try {
156
+ await navigator.clipboard.writeText(
157
+ JSON.stringify(
158
+ {
159
+ serverUrl: client.getBaseUrl() || window.location.origin,
160
+ sessionId: hostSession.id,
161
+ token: hostToken,
162
+ viewerUrl
163
+ },
164
+ null,
165
+ 2
166
+ )
167
+ );
168
+ } catch (caught) {
169
+ setError(
170
+ caught instanceof Error ? caught.message : "Clipboard write failed."
171
+ );
172
+ }
173
+ }, [hostSession, hostToken]);
174
+ const hostViewerUrl = hostSession && hostToken ? buildViewerUrl({ sessionId: hostSession.id, token: hostToken }) : null;
175
+ const remoteViewerUrl = remoteSessionId.trim() && remoteToken.trim() ? buildViewerUrl({
176
+ baseUrl: remoteBase,
177
+ sessionId: remoteSessionId.trim(),
178
+ token: remoteToken.trim()
179
+ }) : null;
180
+ const onAction = useCallback(
181
+ (action) => {
182
+ if (action.startsWith("remote-base:")) {
183
+ setRemoteBase(action.slice("remote-base:".length));
184
+ return;
185
+ }
186
+ if (action.startsWith("remote-session:")) {
187
+ setRemoteSessionId(action.slice("remote-session:".length));
188
+ return;
189
+ }
190
+ if (action.startsWith("remote-token:")) {
191
+ setRemoteToken(action.slice("remote-token:".length));
192
+ return;
193
+ }
194
+ switch (action) {
195
+ case "start":
196
+ case "rotate":
197
+ void startHostSession();
198
+ return;
199
+ case "stop":
200
+ void stopHostSession();
201
+ return;
202
+ case "copy":
203
+ void copyHostDetails();
204
+ return;
205
+ case "open-viewer":
206
+ if (hostViewerUrl) {
207
+ window.open(hostViewerUrl, "_blank", "noopener,noreferrer");
208
+ }
209
+ return;
210
+ case "connect":
211
+ if (remoteViewerUrl) {
212
+ window.open(remoteViewerUrl, "_blank", "noopener,noreferrer");
213
+ }
214
+ return;
215
+ case "refresh":
216
+ void loadCapabilities();
217
+ return;
218
+ }
219
+ },
220
+ [
221
+ copyHostDetails,
222
+ hostViewerUrl,
223
+ loadCapabilities,
224
+ remoteViewerUrl,
225
+ startHostSession,
226
+ stopHostSession
227
+ ]
228
+ );
229
+ const snapshot = {
230
+ platform: capabilities?.platform ?? hostSession?.platform ?? "desktop",
231
+ session: hostSession ? {
232
+ id: hostSession.id,
233
+ label: hostSession.label,
234
+ status: hostSession.status,
235
+ platform: hostSession.platform,
236
+ frameCount: hostSession.frameCount,
237
+ inputCount: hostSession.inputCount,
238
+ lastFrameAt: formatTime(hostSession.lastFrameAt),
239
+ lastInputAt: formatTime(hostSession.lastInputAt)
240
+ } : null,
241
+ capabilities: toCapabilitySnapshots(capabilities),
242
+ host: hostViewerUrl ? {
243
+ token: hostToken,
244
+ sessionId: hostSession?.id ?? "",
245
+ baseUrl: client.getBaseUrl() || ""
246
+ } : null,
247
+ // Always reflect the live draft so the connect fields render what the user
248
+ // typed; the spatial view derives Connect-enablement from session + token.
249
+ remote: remoteBase || remoteSessionId || remoteToken ? {
250
+ token: remoteToken,
251
+ sessionId: remoteSessionId,
252
+ baseUrl: remoteBase
253
+ } : null,
254
+ loading,
255
+ busy,
256
+ error
257
+ };
258
+ return /* @__PURE__ */ jsx(SpatialSurface, { children: /* @__PURE__ */ jsx(ScreenshareSpatialView, { snapshot, onAction }) });
259
+ }
260
+ export {
261
+ ScreenshareView
262
+ };
263
+ //# sourceMappingURL=ScreenshareView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/ScreenshareView.tsx"],"sourcesContent":["/**\n * ScreenshareView — the single GUI/XR data wrapper for the Screen Share surface.\n *\n * It owns the live operator data (capability fetch + poll, launched-session\n * load, host start/stop/rotate, copy/open-viewer, remote connect, refresh) and\n * renders the one presentational {@link ScreenshareSpatialView} inside a\n * {@link SpatialSurface}. Omitting the `modality` prop lets `SpatialSurface`\n * auto-detect GUI vs XR via `window.__elizaXRContext`, so the SAME component\n * serves both surfaces. The TUI surface renders the same `ScreenshareSpatialView`\n * through the terminal registry (see `register-terminal-view.tsx`).\n */\n\nimport {\n client,\n selectLatestRunForApp,\n useAppSelector,\n} from \"@elizaos/ui\";\nimport { SpatialSurface } from \"@elizaos/ui/spatial\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n buildViewerUrl,\n type CapabilitiesResponse,\n fetchJson,\n type PublicSession,\n type StartSessionResponse,\n} from \"../ui/ScreenshareOperatorSurface.helpers.js\";\nimport {\n type ScreenshareCapabilitySnapshot,\n type ScreenshareSnapshot,\n ScreenshareSpatialView,\n} from \"./ScreenshareSpatialView.js\";\n\nconst APP_NAME = \"@elizaos/plugin-screenshare\";\n\n/** Short clock time, or null when the underlying timestamp is absent. */\nfunction formatTime(value: string | null): string | null {\n if (!value) return null;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date.toLocaleTimeString();\n}\n\n/** Pull the launched session id + token out of a run's viewer URL. */\nfunction parseViewerSession(\n viewerUrl: string | null | undefined,\n): { sessionId: string; token: string } | null {\n if (!viewerUrl) return null;\n try {\n const url = new URL(viewerUrl, window.location.origin);\n const sessionId = url.searchParams.get(\"sessionId\")?.trim();\n const token = url.searchParams.get(\"token\")?.trim();\n return sessionId && token ? { sessionId, token } : null;\n } catch {\n return null;\n }\n}\n\nfunction toCapabilitySnapshots(\n capabilities: CapabilitiesResponse | null,\n): ScreenshareCapabilitySnapshot[] {\n if (!capabilities) return [];\n return Object.entries(capabilities.capabilities).map(([name, capability]) => ({\n name,\n available: capability.available,\n tool: capability.tool,\n }));\n}\n\nexport function ScreenshareView() {\n const appRuns = useAppSelector((s) => s.appRuns);\n const { run } = useMemo(\n () => selectLatestRunForApp(APP_NAME, appRuns),\n [appRuns],\n );\n const launchedSession = useMemo(\n () => parseViewerSession(run?.viewer?.url),\n [run?.viewer?.url],\n );\n\n const [capabilities, setCapabilities] = useState<CapabilitiesResponse | null>(\n null,\n );\n const [hostSession, setHostSession] = useState<PublicSession | null>(null);\n const [hostToken, setHostToken] = useState<string>(\n launchedSession?.token ?? \"\",\n );\n const [remoteBase, setRemoteBase] = useState(\"\");\n const [remoteSessionId, setRemoteSessionId] = useState(\"\");\n const [remoteToken, setRemoteToken] = useState(\"\");\n const [busy, setBusy] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const loadCapabilities = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const next = await fetchJson<CapabilitiesResponse>(\n \"/api/apps/screenshare/capabilities\",\n );\n setCapabilities(next);\n } catch (caught) {\n setError(\n caught instanceof Error\n ? caught.message\n : \"Failed to load capabilities.\",\n );\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Load capabilities on mount, then keep them fresh with a quiet poll.\n const autoLoadedRef = useRef(false);\n useEffect(() => {\n if (!autoLoadedRef.current) {\n autoLoadedRef.current = true;\n void loadCapabilities();\n }\n const interval = setInterval(() => {\n void loadCapabilities();\n }, 20_000);\n return () => clearInterval(interval);\n }, [loadCapabilities]);\n\n // When launched with a viewer URL, hydrate the host session it points at.\n useEffect(() => {\n if (!launchedSession) return;\n setHostToken(launchedSession.token);\n void fetchJson<{ session: PublicSession }>(\n `/api/apps/screenshare/session/${encodeURIComponent(\n launchedSession.sessionId,\n )}?token=${encodeURIComponent(launchedSession.token)}`,\n )\n .then((next) => setHostSession(next.session))\n .catch((caught) =>\n setError(\n caught instanceof Error\n ? caught.message\n : \"Failed to load screen share session.\",\n ),\n );\n }, [launchedSession]);\n\n const startHostSession = useCallback(async () => {\n setBusy(\"start\");\n setError(null);\n try {\n const response = await fetchJson<StartSessionResponse>(\n \"/api/apps/screenshare/session\",\n {\n method: \"POST\",\n body: JSON.stringify({ label: \"This machine\" }),\n },\n );\n setHostSession(response.session);\n setHostToken(response.token);\n } catch (caught) {\n setError(\n caught instanceof Error ? caught.message : \"Failed to start session.\",\n );\n } finally {\n setBusy(null);\n }\n }, []);\n\n const stopHostSession = useCallback(async () => {\n if (!hostSession || !hostToken) return;\n setBusy(\"stop\");\n setError(null);\n try {\n const response = await fetchJson<{ session: PublicSession }>(\n `/api/apps/screenshare/session/${encodeURIComponent(\n hostSession.id,\n )}/stop`,\n {\n method: \"POST\",\n body: JSON.stringify({ token: hostToken }),\n headers: { \"X-Screenshare-Token\": hostToken },\n },\n );\n setHostSession(response.session);\n } catch (caught) {\n setError(\n caught instanceof Error ? caught.message : \"Failed to stop session.\",\n );\n } finally {\n setBusy(null);\n }\n }, [hostSession, hostToken]);\n\n const copyHostDetails = useCallback(async () => {\n if (!hostSession || !hostToken) return;\n const viewerUrl = buildViewerUrl({\n sessionId: hostSession.id,\n token: hostToken,\n });\n try {\n await navigator.clipboard.writeText(\n JSON.stringify(\n {\n serverUrl: client.getBaseUrl() || window.location.origin,\n sessionId: hostSession.id,\n token: hostToken,\n viewerUrl,\n },\n null,\n 2,\n ),\n );\n } catch (caught) {\n setError(\n caught instanceof Error ? caught.message : \"Clipboard write failed.\",\n );\n }\n }, [hostSession, hostToken]);\n\n const hostViewerUrl =\n hostSession && hostToken\n ? buildViewerUrl({ sessionId: hostSession.id, token: hostToken })\n : null;\n const remoteViewerUrl =\n remoteSessionId.trim() && remoteToken.trim()\n ? buildViewerUrl({\n baseUrl: remoteBase,\n sessionId: remoteSessionId.trim(),\n token: remoteToken.trim(),\n })\n : null;\n\n const onAction = useCallback(\n (action: string) => {\n if (action.startsWith(\"remote-base:\")) {\n setRemoteBase(action.slice(\"remote-base:\".length));\n return;\n }\n if (action.startsWith(\"remote-session:\")) {\n setRemoteSessionId(action.slice(\"remote-session:\".length));\n return;\n }\n if (action.startsWith(\"remote-token:\")) {\n setRemoteToken(action.slice(\"remote-token:\".length));\n return;\n }\n switch (action) {\n case \"start\":\n case \"rotate\":\n void startHostSession();\n return;\n case \"stop\":\n void stopHostSession();\n return;\n case \"copy\":\n void copyHostDetails();\n return;\n case \"open-viewer\":\n if (hostViewerUrl) {\n window.open(hostViewerUrl, \"_blank\", \"noopener,noreferrer\");\n }\n return;\n case \"connect\":\n if (remoteViewerUrl) {\n window.open(remoteViewerUrl, \"_blank\", \"noopener,noreferrer\");\n }\n return;\n case \"refresh\":\n void loadCapabilities();\n return;\n }\n },\n [\n copyHostDetails,\n hostViewerUrl,\n loadCapabilities,\n remoteViewerUrl,\n startHostSession,\n stopHostSession,\n ],\n );\n\n const snapshot: ScreenshareSnapshot = {\n platform: capabilities?.platform ?? hostSession?.platform ?? \"desktop\",\n session: hostSession\n ? {\n id: hostSession.id,\n label: hostSession.label,\n status: hostSession.status,\n platform: hostSession.platform,\n frameCount: hostSession.frameCount,\n inputCount: hostSession.inputCount,\n lastFrameAt: formatTime(hostSession.lastFrameAt),\n lastInputAt: formatTime(hostSession.lastInputAt),\n }\n : null,\n capabilities: toCapabilitySnapshots(capabilities),\n host: hostViewerUrl\n ? {\n token: hostToken,\n sessionId: hostSession?.id ?? \"\",\n baseUrl: client.getBaseUrl() || \"\",\n }\n : null,\n // Always reflect the live draft so the connect fields render what the user\n // typed; the spatial view derives Connect-enablement from session + token.\n remote:\n remoteBase || remoteSessionId || remoteToken\n ? {\n token: remoteToken,\n sessionId: remoteSessionId,\n baseUrl: remoteBase,\n }\n : null,\n loading,\n busy,\n error,\n };\n\n return (\n <SpatialSurface>\n <ScreenshareSpatialView snapshot={snapshot} onAction={onAction} />\n </SpatialSurface>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ import type { Plugin } from "@elizaos/core";
2
+ import { handleAppRoutes, prepareLaunch, refreshRunSession, resolveLaunchSession, stopRun } from "./routes.js";
3
+ import { SCREENSHARE_APP_NAME, SCREENSHARE_DISPLAY_NAME } from "./session-store.js";
4
+ export declare const screensharePlugin: Plugin;
5
+ export { handleAppRoutes, prepareLaunch, refreshRunSession, resolveLaunchSession, SCREENSHARE_APP_NAME, SCREENSHARE_DISPLAY_NAME, stopRun, };
6
+ export default screensharePlugin;
7
+ export * from "./routes.js";
8
+ export * from "./ui/index.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,OAAO,EACR,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,oBAAoB,CAAC;AA2B5B,eAAO,MAAM,iBAAiB,QAG7B,CAAC;AAEF,OAAO,EACL,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,OAAO,GACR,CAAC;AAEF,eAAe,iBAAiB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}