@elizaos/plugin-wifi 2.0.3-beta.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @elizaos/plugin-wifi
2
+
3
+ Wi-Fi overlay app for the elizaOS Android agent. Scan, inspect, and connect to nearby Wi-Fi networks from within the elizaOS mobile interface.
4
+
5
+ ## What it does
6
+
7
+ - Displays the currently connected Wi-Fi network (SSID, signal strength, frequency).
8
+ - Scans for nearby networks and lists them sorted by signal strength.
9
+ - Lets the user tap a network, enter a password if required, and connect.
10
+ - Surfaces nearby network data (SSID, BSSID, RSSI, frequency, security) to the agent planner as the `wifiNetworks` provider.
11
+
12
+ ## Android-only
13
+
14
+ This plugin is only functional on Android. The overlay app is registered in the elizaOS app catalog exclusively when running inside the elizaOS Android host. On other platforms (iOS, desktop, web) the side-effect registration leaves the app catalog unchanged. `@elizaos/capacitor-wifi` uses Android's `WifiManager` API directly.
15
+
16
+ ## Capabilities added to an Eliza agent
17
+
18
+ | Surface | Name | Description |
19
+ |---------|------|-------------|
20
+ | Provider | `wifiNetworks` | Dynamic provider gated to the `system` context (`contextGate: { anyOf: ["system"] }`); injects up to 25 nearby Wi-Fi networks when that context is selected for a turn. Fields per network: `ssid`, `bssid`, `rssi` (dBm), `frequency` (MHz), `secured` (boolean). |
21
+ | Overlay UI | WiFi | Full-screen app accessible from the elizaOS app catalog. Scan, view connected network, connect/disconnect. |
22
+
23
+ ## Required permissions
24
+
25
+ Android `ACCESS_FINE_LOCATION` must be granted at the OS level before Wi-Fi scans can return results. The plugin does not prompt for this permission itself — it relies on the host app's permission flow.
26
+
27
+ ## Enabling the plugin
28
+
29
+ Register it in your elizaOS agent configuration by importing from the `/plugin` export:
30
+
31
+ ```ts
32
+ import wifiPlugin from "@elizaos/plugin-wifi/plugin";
33
+ // or
34
+ import { appWifiPlugin } from "@elizaos/plugin-wifi/plugin";
35
+ ```
36
+
37
+ The overlay UI registers itself automatically when the package is loaded on an elizaOS Android host (via the `register.ts` side-effect entry). No additional setup is required.
38
+
39
+ ## Package exports
40
+
41
+ | Export path | Contents |
42
+ |-------------|----------|
43
+ | `@elizaos/plugin-wifi` | Full barrel: plugin, UI components, registration helpers |
44
+ | `@elizaos/plugin-wifi/plugin` | `appWifiPlugin` (the `Plugin` object with the `wifiNetworks` provider) |
45
+
46
+ ## Dependencies
47
+
48
+ - `@elizaos/capacitor-wifi` — Capacitor plugin wrapping Android WifiManager.
49
+ - `@elizaos/capacitor-system` — Used by the UI to open Android network settings.
50
+ - `@elizaos/ui` — Overlay app registry + shared UI primitives.
51
+ - `@elizaos/core` — elizaOS plugin and provider types.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * WifiAppView — full-screen overlay for the WiFi app.
3
+ *
4
+ * Calls into `@elizaos/capacitor-wifi` to read the active connection, scan
5
+ * for nearby networks, and (on press) attempt a connect. The component owns
6
+ * all of its own data; there is no server-side route. Permissions
7
+ * (`ACCESS_FINE_LOCATION` in particular) are expected to be granted
8
+ * already; if scans return a permission rejection we surface the message
9
+ * inline rather than retrying silently.
10
+ */
11
+ import { type OverlayAppContext } from "@elizaos/ui";
12
+ export declare function WifiAppView(props: OverlayAppContext): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=WifiAppView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WifiAppView.d.ts","sourceRoot":"","sources":["../../src/components/WifiAppView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,EAAU,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAwK7D,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,2CAyOnD"}
@@ -0,0 +1,364 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { System } from "@elizaos/capacitor-system";
3
+ import { WiFi } from "@elizaos/capacitor-wifi";
4
+ import { Button } from "@elizaos/ui";
5
+ import {
6
+ CheckCircle2,
7
+ ChevronLeft,
8
+ Lock,
9
+ RefreshCw,
10
+ Settings,
11
+ Wifi as WifiIcon,
12
+ WifiOff
13
+ } from "lucide-react";
14
+ import { useCallback, useEffect, useMemo, useState } from "react";
15
+ const VISIBLE_NETWORK_LIMIT = 12;
16
+ function signalBars(rssi) {
17
+ if (rssi >= -50) return 4;
18
+ if (rssi >= -60) return 3;
19
+ if (rssi >= -70) return 2;
20
+ if (rssi >= -80) return 1;
21
+ return 0;
22
+ }
23
+ function SignalBars({ rssi }) {
24
+ const bars = signalBars(rssi);
25
+ return /* @__PURE__ */ jsx(
26
+ "div",
27
+ {
28
+ role: "img",
29
+ "aria-label": `Signal ${bars} of 4`,
30
+ className: "flex items-end gap-0.5",
31
+ children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx(
32
+ "div",
33
+ {
34
+ className: `w-1 rounded-sm ${i < bars ? "bg-txt" : "bg-muted/30"}`,
35
+ style: { height: `${4 + i * 3}px` }
36
+ },
37
+ i
38
+ ))
39
+ }
40
+ );
41
+ }
42
+ function ConnectedCard({
43
+ state,
44
+ network,
45
+ onDisconnect,
46
+ onOpenSettings,
47
+ busy
48
+ }) {
49
+ if (!state?.enabled) {
50
+ return /* @__PURE__ */ jsx("div", { className: "px-1 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
51
+ /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx(WifiOff, { className: "h-5 w-5 text-muted-strong" }) }),
52
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
53
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-txt", children: "Wi-Fi is off" }),
54
+ /* @__PURE__ */ jsx("div", { className: "sr-only", children: "Enable it in Android settings." }),
55
+ /* @__PURE__ */ jsxs(
56
+ Button,
57
+ {
58
+ variant: "outline",
59
+ size: "sm",
60
+ className: "mt-3",
61
+ onClick: onOpenSettings,
62
+ children: [
63
+ /* @__PURE__ */ jsx(Settings, { className: "mr-2 h-4 w-4" }),
64
+ "Network settings"
65
+ ]
66
+ }
67
+ )
68
+ ] })
69
+ ] }) });
70
+ }
71
+ if (!network) {
72
+ return /* @__PURE__ */ jsx("div", { className: "px-1 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
73
+ /* @__PURE__ */ jsx(WifiIcon, { className: "h-5 w-5 text-muted-strong" }),
74
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-muted", children: "Not connected" })
75
+ ] }) });
76
+ }
77
+ return /* @__PURE__ */ jsx("div", { className: "px-1 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
78
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
79
+ /* @__PURE__ */ jsx(CheckCircle2, { className: "h-5 w-5 text-ok" }),
80
+ /* @__PURE__ */ jsxs("div", { children: [
81
+ /* @__PURE__ */ jsx("div", { className: "text-2xs font-semibold uppercase text-muted/70", children: "Connected" }),
82
+ /* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-txt", children: network.ssid || "(hidden)" }),
83
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-xs text-muted", children: [
84
+ network.rssi,
85
+ " dBm \xB7 ",
86
+ network.frequency,
87
+ " MHz"
88
+ ] })
89
+ ] })
90
+ ] }),
91
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
92
+ /* @__PURE__ */ jsx(SignalBars, { rssi: network.rssi }),
93
+ /* @__PURE__ */ jsx(
94
+ Button,
95
+ {
96
+ variant: "outline",
97
+ size: "sm",
98
+ onClick: onDisconnect,
99
+ disabled: busy,
100
+ children: "Disconnect"
101
+ }
102
+ )
103
+ ] })
104
+ ] }) });
105
+ }
106
+ function NetworkRow({ network, onSelect }) {
107
+ return /* @__PURE__ */ jsxs(
108
+ "button",
109
+ {
110
+ type: "button",
111
+ onClick: () => onSelect(network),
112
+ className: "flex w-full items-center justify-between gap-3 px-2 py-2 text-left transition-colors hover:bg-bg-accent/50",
113
+ "data-testid": `wifi-network-${network.bssid || network.ssid || "hidden"}`,
114
+ children: [
115
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
116
+ network.secured ? /* @__PURE__ */ jsx(Lock, { className: "h-4 w-4 shrink-0 text-muted-strong" }) : /* @__PURE__ */ jsx(WifiIcon, { className: "h-4 w-4 shrink-0 text-muted-strong" }),
117
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
118
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium text-txt", children: network.ssid || "(hidden)" }),
119
+ /* @__PURE__ */ jsxs("div", { className: "truncate font-mono text-2xs text-muted", children: [
120
+ network.bssid,
121
+ " \xB7 ",
122
+ network.rssi,
123
+ " dBm"
124
+ ] })
125
+ ] })
126
+ ] }),
127
+ /* @__PURE__ */ jsx(SignalBars, { rssi: network.rssi })
128
+ ]
129
+ }
130
+ );
131
+ }
132
+ function WifiAppView(props) {
133
+ const { exitToApps } = props;
134
+ const [state, setState] = useState(null);
135
+ const [connected, setConnected] = useState(null);
136
+ const [networks, setNetworks] = useState([]);
137
+ const [scanning, setScanning] = useState(false);
138
+ const [busy, setBusy] = useState(false);
139
+ const [error, setError] = useState(null);
140
+ const [selected, setSelected] = useState(null);
141
+ const [password, setPassword] = useState("");
142
+ const refreshState = useCallback(async () => {
143
+ const [stateResult, connectedResult] = await Promise.all([
144
+ WiFi.getWifiState(),
145
+ WiFi.getConnectedNetwork()
146
+ ]);
147
+ setState(stateResult);
148
+ setConnected(connectedResult.network);
149
+ }, []);
150
+ const scan = useCallback(async () => {
151
+ setScanning(true);
152
+ setError(null);
153
+ try {
154
+ const result = await WiFi.listAvailableNetworks({ limit: 50 });
155
+ setNetworks(result.networks);
156
+ await refreshState();
157
+ } catch (err) {
158
+ setError(err instanceof Error ? err.message : String(err));
159
+ } finally {
160
+ setScanning(false);
161
+ }
162
+ }, [refreshState]);
163
+ useEffect(() => {
164
+ void scan();
165
+ }, [scan]);
166
+ const handleSelect = useCallback((network) => {
167
+ setSelected(network);
168
+ setPassword("");
169
+ }, []);
170
+ const handleConnect = useCallback(async () => {
171
+ if (!selected) return;
172
+ setBusy(true);
173
+ setError(null);
174
+ try {
175
+ const result = await WiFi.connectToNetwork({
176
+ ssid: selected.ssid,
177
+ password: selected.secured ? password : void 0
178
+ });
179
+ if (!result.success) {
180
+ setError(result.message ?? "Failed to connect");
181
+ } else {
182
+ setSelected(null);
183
+ setPassword("");
184
+ await refreshState();
185
+ }
186
+ } catch (err) {
187
+ setError(err instanceof Error ? err.message : String(err));
188
+ } finally {
189
+ setBusy(false);
190
+ }
191
+ }, [password, refreshState, selected]);
192
+ const handleDisconnect = useCallback(async () => {
193
+ setBusy(true);
194
+ setError(null);
195
+ try {
196
+ await WiFi.disconnectFromNetwork();
197
+ await refreshState();
198
+ } catch (err) {
199
+ setError(err instanceof Error ? err.message : String(err));
200
+ } finally {
201
+ setBusy(false);
202
+ }
203
+ }, [refreshState]);
204
+ const openNetworkSettings = useCallback(async () => {
205
+ setError(null);
206
+ try {
207
+ await System.openNetworkSettings();
208
+ } catch (err) {
209
+ setError(err instanceof Error ? err.message : String(err));
210
+ }
211
+ }, []);
212
+ const sortedNetworks = useMemo(() => {
213
+ return [...networks].sort((a, b) => b.rssi - a.rssi);
214
+ }, [networks]);
215
+ return /* @__PURE__ */ jsxs(
216
+ "div",
217
+ {
218
+ "data-testid": "wifi-shell",
219
+ className: "fixed inset-0 z-50 flex h-[100vh] w-full flex-col overflow-hidden bg-bg pb-[var(--safe-area-bottom,0px)] pl-[var(--safe-area-left,0px)] pr-[var(--safe-area-right,0px)] pt-[var(--safe-area-top,0px)] supports-[height:100dvh]:h-[100dvh]",
220
+ children: [
221
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-3 px-3 py-2", children: [
222
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
223
+ /* @__PURE__ */ jsx(
224
+ Button,
225
+ {
226
+ variant: "ghost",
227
+ size: "sm",
228
+ onClick: exitToApps,
229
+ "aria-label": "Back to apps",
230
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
231
+ }
232
+ ),
233
+ /* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-txt", children: "WiFi" })
234
+ ] }),
235
+ /* @__PURE__ */ jsxs(
236
+ Button,
237
+ {
238
+ variant: "outline",
239
+ size: "sm",
240
+ onClick: () => {
241
+ void scan();
242
+ },
243
+ disabled: scanning,
244
+ "data-testid": "wifi-scan",
245
+ children: [
246
+ /* @__PURE__ */ jsx(
247
+ RefreshCw,
248
+ {
249
+ className: `mr-1 h-4 w-4 ${scanning ? "animate-spin" : ""}`
250
+ }
251
+ ),
252
+ "Scan"
253
+ ]
254
+ }
255
+ )
256
+ ] }),
257
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-1 flex-col gap-3 overflow-y-auto px-3 py-2", children: [
258
+ /* @__PURE__ */ jsx(
259
+ ConnectedCard,
260
+ {
261
+ state,
262
+ network: connected,
263
+ onDisconnect: handleDisconnect,
264
+ onOpenSettings: openNetworkSettings,
265
+ busy
266
+ }
267
+ ),
268
+ error ? /* @__PURE__ */ jsx("div", { className: "px-1 py-2 text-sm text-red-400", children: error }) : null,
269
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
270
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
271
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold text-txt", children: [
272
+ /* @__PURE__ */ jsx(WifiIcon, { className: "h-4 w-4 text-muted" }),
273
+ "Networks"
274
+ ] }),
275
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted", children: [
276
+ sortedNetworks.length,
277
+ sortedNetworks.length > VISIBLE_NETWORK_LIMIT ? ` / ${VISIBLE_NETWORK_LIMIT} shown` : ""
278
+ ] })
279
+ ] }),
280
+ sortedNetworks.length === 0 && !scanning ? /* @__PURE__ */ jsxs("div", { className: "px-4 py-8 text-center", children: [
281
+ /* @__PURE__ */ jsx(WifiOff, { className: "mx-auto h-9 w-9 text-muted" }),
282
+ /* @__PURE__ */ jsx("div", { className: "mt-3 text-sm font-medium text-txt", children: "None" }),
283
+ /* @__PURE__ */ jsx("div", { className: "sr-only", children: "Check Wi-Fi and location access." }),
284
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-col justify-center gap-2 sm:flex-row", children: [
285
+ /* @__PURE__ */ jsxs(
286
+ Button,
287
+ {
288
+ variant: "outline",
289
+ size: "sm",
290
+ className: "",
291
+ onClick: () => {
292
+ void scan();
293
+ },
294
+ children: [
295
+ /* @__PURE__ */ jsx(RefreshCw, { className: "mr-2 h-4 w-4" }),
296
+ "Scan again"
297
+ ]
298
+ }
299
+ ),
300
+ /* @__PURE__ */ jsxs(
301
+ Button,
302
+ {
303
+ variant: "outline",
304
+ size: "sm",
305
+ className: "",
306
+ onClick: openNetworkSettings,
307
+ children: [
308
+ /* @__PURE__ */ jsx(Settings, { className: "mr-2 h-4 w-4" }),
309
+ "Network settings"
310
+ ]
311
+ }
312
+ )
313
+ ] })
314
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: sortedNetworks.slice(0, VISIBLE_NETWORK_LIMIT).map((network) => /* @__PURE__ */ jsx(
315
+ NetworkRow,
316
+ {
317
+ network,
318
+ onSelect: handleSelect
319
+ },
320
+ `${network.bssid}-${network.ssid}`
321
+ )) })
322
+ ] })
323
+ ] }),
324
+ selected ? /* @__PURE__ */ jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
325
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-txt", children: [
326
+ "Connect to",
327
+ " ",
328
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: selected.ssid || "(hidden)" })
329
+ ] }),
330
+ selected.secured ? /* @__PURE__ */ jsx(
331
+ "input",
332
+ {
333
+ type: "password",
334
+ value: password,
335
+ onChange: (e) => setPassword(e.target.value),
336
+ placeholder: "Password",
337
+ className: "w-full rounded-md border border-border/30 bg-bg px-3 py-2 text-sm text-txt outline-none focus:border-border/60"
338
+ }
339
+ ) : null,
340
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
341
+ /* @__PURE__ */ jsx(
342
+ Button,
343
+ {
344
+ variant: "ghost",
345
+ size: "sm",
346
+ onClick: () => {
347
+ setSelected(null);
348
+ setPassword("");
349
+ },
350
+ disabled: busy,
351
+ children: "Cancel"
352
+ }
353
+ ),
354
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: handleConnect, disabled: busy, children: "Connect" })
355
+ ] })
356
+ ] }) }) : null
357
+ ]
358
+ }
359
+ );
360
+ }
361
+ export {
362
+ WifiAppView
363
+ };
364
+ //# sourceMappingURL=WifiAppView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/WifiAppView.tsx"],"sourcesContent":["/**\n * WifiAppView — full-screen overlay for the WiFi app.\n *\n * Calls into `@elizaos/capacitor-wifi` to read the active connection, scan\n * for nearby networks, and (on press) attempt a connect. The component owns\n * all of its own data; there is no server-side route. Permissions\n * (`ACCESS_FINE_LOCATION` in particular) are expected to be granted\n * already; if scans return a permission rejection we surface the message\n * inline rather than retrying silently.\n */\n\nimport { System } from \"@elizaos/capacitor-system\";\nimport type {\n ConnectResult,\n WiFiNetwork,\n WifiStateResult,\n} from \"@elizaos/capacitor-wifi\";\nimport { WiFi } from \"@elizaos/capacitor-wifi\";\nimport { Button, type OverlayAppContext } from \"@elizaos/ui\";\nimport {\n CheckCircle2,\n ChevronLeft,\n Lock,\n RefreshCw,\n Settings,\n Wifi as WifiIcon,\n WifiOff,\n} from \"lucide-react\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\ninterface SignalBarsProps {\n rssi: number;\n}\n\nconst VISIBLE_NETWORK_LIMIT = 12;\n\n/**\n * Map dBm to a 0–4 bar count. Standard Android thresholds:\n * >= -50 → 4 bars (excellent)\n * >= -60 → 3 bars\n * >= -70 → 2 bars\n * >= -80 → 1 bar\n * else → 0\n */\nfunction signalBars(rssi: number): number {\n if (rssi >= -50) return 4;\n if (rssi >= -60) return 3;\n if (rssi >= -70) return 2;\n if (rssi >= -80) return 1;\n return 0;\n}\n\nfunction SignalBars({ rssi }: SignalBarsProps) {\n const bars = signalBars(rssi);\n return (\n <div\n role=\"img\"\n aria-label={`Signal ${bars} of 4`}\n className=\"flex items-end gap-0.5\"\n >\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className={`w-1 rounded-sm ${i < bars ? \"bg-txt\" : \"bg-muted/30\"}`}\n style={{ height: `${4 + i * 3}px` }}\n />\n ))}\n </div>\n );\n}\n\ninterface ConnectedCardProps {\n state: WifiStateResult | null;\n network: WiFiNetwork | null;\n onDisconnect: () => void;\n onOpenSettings: () => void;\n busy: boolean;\n}\n\nfunction ConnectedCard({\n state,\n network,\n onDisconnect,\n onOpenSettings,\n busy,\n}: ConnectedCardProps) {\n if (!state?.enabled) {\n return (\n <div className=\"px-1 py-2\">\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center\">\n <WifiOff className=\"h-5 w-5 text-muted-strong\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-medium text-txt\">Wi-Fi is off</div>\n <div className=\"sr-only\">Enable it in Android settings.</div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={onOpenSettings}\n >\n <Settings className=\"mr-2 h-4 w-4\" />\n Network settings\n </Button>\n </div>\n </div>\n </div>\n );\n }\n if (!network) {\n return (\n <div className=\"px-1 py-2\">\n <div className=\"flex items-center gap-3\">\n <WifiIcon className=\"h-5 w-5 text-muted-strong\" />\n <div className=\"text-sm text-muted\">Not connected</div>\n </div>\n </div>\n );\n }\n return (\n <div className=\"px-1 py-2\">\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex items-center gap-3\">\n <CheckCircle2 className=\"h-5 w-5 text-ok\" />\n <div>\n <div className=\"text-2xs font-semibold uppercase text-muted/70\">\n Connected\n </div>\n <div className=\"text-base font-semibold text-txt\">\n {network.ssid || \"(hidden)\"}\n </div>\n <div className=\"font-mono text-xs text-muted\">\n {network.rssi} dBm · {network.frequency} MHz\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <SignalBars rssi={network.rssi} />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={onDisconnect}\n disabled={busy}\n >\n Disconnect\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\ninterface NetworkRowProps {\n network: WiFiNetwork;\n onSelect: (network: WiFiNetwork) => void;\n}\n\nfunction NetworkRow({ network, onSelect }: NetworkRowProps) {\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(network)}\n className=\"flex w-full items-center justify-between gap-3 px-2 py-2 text-left transition-colors hover:bg-bg-accent/50\"\n data-testid={`wifi-network-${network.bssid || network.ssid || \"hidden\"}`}\n >\n <div className=\"flex min-w-0 items-center gap-3\">\n {network.secured ? (\n <Lock className=\"h-4 w-4 shrink-0 text-muted-strong\" />\n ) : (\n <WifiIcon className=\"h-4 w-4 shrink-0 text-muted-strong\" />\n )}\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium text-txt\">\n {network.ssid || \"(hidden)\"}\n </div>\n <div className=\"truncate font-mono text-2xs text-muted\">\n {network.bssid} · {network.rssi} dBm\n </div>\n </div>\n </div>\n <SignalBars rssi={network.rssi} />\n </button>\n );\n}\n\nexport function WifiAppView(props: OverlayAppContext) {\n const { exitToApps } = props;\n\n const [state, setState] = useState<WifiStateResult | null>(null);\n const [connected, setConnected] = useState<WiFiNetwork | null>(null);\n const [networks, setNetworks] = useState<WiFiNetwork[]>([]);\n const [scanning, setScanning] = useState(false);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [selected, setSelected] = useState<WiFiNetwork | null>(null);\n const [password, setPassword] = useState(\"\");\n\n const refreshState = useCallback(async () => {\n const [stateResult, connectedResult] = await Promise.all([\n WiFi.getWifiState(),\n WiFi.getConnectedNetwork(),\n ]);\n setState(stateResult);\n setConnected(connectedResult.network);\n }, []);\n\n const scan = useCallback(async () => {\n setScanning(true);\n setError(null);\n try {\n const result = await WiFi.listAvailableNetworks({ limit: 50 });\n setNetworks(result.networks);\n await refreshState();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setScanning(false);\n }\n }, [refreshState]);\n\n useEffect(() => {\n void scan();\n }, [scan]);\n\n const handleSelect = useCallback((network: WiFiNetwork) => {\n setSelected(network);\n setPassword(\"\");\n }, []);\n\n const handleConnect = useCallback(async () => {\n if (!selected) return;\n setBusy(true);\n setError(null);\n try {\n const result: ConnectResult = await WiFi.connectToNetwork({\n ssid: selected.ssid,\n password: selected.secured ? password : undefined,\n });\n if (!result.success) {\n setError(result.message ?? \"Failed to connect\");\n } else {\n setSelected(null);\n setPassword(\"\");\n await refreshState();\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(false);\n }\n }, [password, refreshState, selected]);\n\n const handleDisconnect = useCallback(async () => {\n setBusy(true);\n setError(null);\n try {\n await WiFi.disconnectFromNetwork();\n await refreshState();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(false);\n }\n }, [refreshState]);\n\n const openNetworkSettings = useCallback(async () => {\n setError(null);\n try {\n await System.openNetworkSettings();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n }\n }, []);\n\n const sortedNetworks = useMemo(() => {\n return [...networks].sort((a, b) => b.rssi - a.rssi);\n }, [networks]);\n\n return (\n <div\n data-testid=\"wifi-shell\"\n className=\"fixed inset-0 z-50 flex h-[100vh] w-full flex-col overflow-hidden bg-bg pb-[var(--safe-area-bottom,0px)] pl-[var(--safe-area-left,0px)] pr-[var(--safe-area-right,0px)] pt-[var(--safe-area-top,0px)] supports-[height:100dvh]:h-[100dvh]\"\n >\n <header className=\"flex items-center justify-between gap-3 px-3 py-2\">\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={exitToApps}\n aria-label=\"Back to apps\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <div className=\"text-base font-semibold text-txt\">WiFi</div>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n void scan();\n }}\n disabled={scanning}\n data-testid=\"wifi-scan\"\n >\n <RefreshCw\n className={`mr-1 h-4 w-4 ${scanning ? \"animate-spin\" : \"\"}`}\n />\n Scan\n </Button>\n </header>\n\n <div className=\"mx-auto flex w-full max-w-3xl flex-1 flex-col gap-3 overflow-y-auto px-3 py-2\">\n <ConnectedCard\n state={state}\n network={connected}\n onDisconnect={handleDisconnect}\n onOpenSettings={openNetworkSettings}\n busy={busy}\n />\n\n {error ? (\n <div className=\"px-1 py-2 text-sm text-red-400\">{error}</div>\n ) : null}\n\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2 text-sm font-semibold text-txt\">\n <WifiIcon className=\"h-4 w-4 text-muted\" />\n Networks\n </div>\n <span className=\"text-xs text-muted\">\n {sortedNetworks.length}\n {sortedNetworks.length > VISIBLE_NETWORK_LIMIT\n ? ` / ${VISIBLE_NETWORK_LIMIT} shown`\n : \"\"}\n </span>\n </div>\n {sortedNetworks.length === 0 && !scanning ? (\n <div className=\"px-4 py-8 text-center\">\n <WifiOff className=\"mx-auto h-9 w-9 text-muted\" />\n <div className=\"mt-3 text-sm font-medium text-txt\">None</div>\n <div className=\"sr-only\">Check Wi-Fi and location access.</div>\n <div className=\"mt-4 flex flex-col justify-center gap-2 sm:flex-row\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"\"\n onClick={() => {\n void scan();\n }}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n Scan again\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"\"\n onClick={openNetworkSettings}\n >\n <Settings className=\"mr-2 h-4 w-4\" />\n Network settings\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {sortedNetworks.slice(0, VISIBLE_NETWORK_LIMIT).map((network) => (\n <NetworkRow\n key={`${network.bssid}-${network.ssid}`}\n network={network}\n onSelect={handleSelect}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n\n {selected ? (\n <div className=\"px-4 py-3\">\n <div className=\"flex flex-col gap-3\">\n <div className=\"text-sm text-txt\">\n Connect to{\" \"}\n <span className=\"font-semibold\">\n {selected.ssid || \"(hidden)\"}\n </span>\n </div>\n {selected.secured ? (\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"Password\"\n className=\"w-full rounded-md border border-border/30 bg-bg px-3 py-2 text-sm text-txt outline-none focus:border-border/60\"\n />\n ) : null}\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n setSelected(null);\n setPassword(\"\");\n }}\n disabled={busy}\n >\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleConnect} disabled={busy}>\n Connect\n </Button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * WiFi overlay app definition + registration.
3
+ *
4
+ * Registered by the WiFi side-effect entry only on
5
+ * Android; other platforms intentionally leave registration unchanged so the app does
6
+ * not appear in the catalog where it cannot function.
7
+ */
8
+ import { type OverlayApp } from "@elizaos/ui";
9
+ export declare const WIFI_APP_NAME = "@elizaos/plugin-wifi";
10
+ export declare const wifiApp: OverlayApp;
11
+ /** Register the WiFi app with the overlay app registry. */
12
+ export declare function registerWifiApp(): void;
13
+ //# sourceMappingURL=wifi-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wifi-app.d.ts","sourceRoot":"","sources":["../../src/components/wifi-app.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,aAAa,CAAC;AAElE,eAAO,MAAM,aAAa,yBAAyB,CAAC;AAEpD,eAAO,MAAM,OAAO,EAAE,UASrB,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,20 @@
1
+ import { registerOverlayApp } from "@elizaos/ui";
2
+ const WIFI_APP_NAME = "@elizaos/plugin-wifi";
3
+ const wifiApp = {
4
+ name: WIFI_APP_NAME,
5
+ displayName: "WiFi",
6
+ description: "Scan, inspect, and connect to nearby Wi-Fi networks",
7
+ category: "system",
8
+ icon: null,
9
+ androidOnly: true,
10
+ loader: () => import("./WifiAppView.js").then((m) => ({ default: m.WifiAppView }))
11
+ };
12
+ function registerWifiApp() {
13
+ registerOverlayApp(wifiApp);
14
+ }
15
+ export {
16
+ WIFI_APP_NAME,
17
+ registerWifiApp,
18
+ wifiApp
19
+ };
20
+ //# sourceMappingURL=wifi-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/wifi-app.ts"],"sourcesContent":["/**\n * WiFi overlay app definition + registration.\n *\n * Registered by the WiFi side-effect entry only on\n * Android; other platforms intentionally leave registration unchanged so the app does\n * not appear in the catalog where it cannot function.\n */\n\nimport { type OverlayApp, registerOverlayApp } from \"@elizaos/ui\";\n\nexport const WIFI_APP_NAME = \"@elizaos/plugin-wifi\";\n\nexport const wifiApp: OverlayApp = {\n name: WIFI_APP_NAME,\n displayName: \"WiFi\",\n description: \"Scan, inspect, and connect to nearby Wi-Fi networks\",\n category: \"system\",\n icon: null,\n androidOnly: true,\n loader: () =>\n import(\"./WifiAppView.js\").then((m) => ({ default: m.WifiAppView })),\n};\n\n/** Register the WiFi app with the overlay app registry. */\nexport function registerWifiApp(): void {\n registerOverlayApp(wifiApp);\n}\n"],"mappings":"AAQA,SAA0B,0BAA0B;AAE7C,MAAM,gBAAgB;AAEtB,MAAM,UAAsB;AAAA,EACjC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ,MACN,OAAO,kBAAkB,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE;AACvE;AAGO,SAAS,kBAAwB;AACtC,qBAAmB,OAAO;AAC5B;","names":[]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Public entry for @elizaos/plugin-wifi — Android-only Wi-Fi overlay.
3
+ *
4
+ * Wraps `@elizaos/capacitor-wifi` and exposes a simple scan + connect UI plus
5
+ * a single SCAN_WIFI agent action. The app is only registered on Android via
6
+ * the `register` subpath; other platforms intentionally leave registration unchanged so
7
+ * the app does not appear in the catalog where it cannot function.
8
+ */
9
+ export { WifiAppView } from "./components/WifiAppView";
10
+ export { registerWifiApp, WIFI_APP_NAME, wifiApp, } from "./components/wifi-app";
11
+ export { appWifiPlugin, default } from "./plugin";
12
+ export { wifiNetworksProvider } from "./providers/networks";
13
+ export * from "./register";
14
+ export * from "./ui";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACL,eAAe,EACf,aAAa,EACb,OAAO,GACR,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,cAAc,YAAY,CAAC;AAC3B,cAAc,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ import { WifiAppView } from "./components/WifiAppView.js";
2
+ import {
3
+ registerWifiApp,
4
+ WIFI_APP_NAME,
5
+ wifiApp
6
+ } from "./components/wifi-app.js";
7
+ import { appWifiPlugin, default as default2 } from "./plugin.js";
8
+ import { wifiNetworksProvider } from "./providers/networks.js";
9
+ export * from "./register.js";
10
+ export * from "./ui.js";
11
+ export {
12
+ WIFI_APP_NAME,
13
+ WifiAppView,
14
+ appWifiPlugin,
15
+ default2 as default,
16
+ registerWifiApp,
17
+ wifiApp,
18
+ wifiNetworksProvider
19
+ };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Public entry for @elizaos/plugin-wifi — Android-only Wi-Fi overlay.\n *\n * Wraps `@elizaos/capacitor-wifi` and exposes a simple scan + connect UI plus\n * a single SCAN_WIFI agent action. The app is only registered on Android via\n * the `register` subpath; other platforms intentionally leave registration unchanged so\n * the app does not appear in the catalog where it cannot function.\n */\n\nexport { WifiAppView } from \"./components/WifiAppView.js\";\nexport {\n registerWifiApp,\n WIFI_APP_NAME,\n wifiApp,\n} from \"./components/wifi-app.js\";\nexport { appWifiPlugin, default } from \"./plugin.js\";\nexport { wifiNetworksProvider } from \"./providers/networks.js\";\nexport * from \"./register.js\";\nexport * from \"./ui.js\";\n"],"mappings":"AASA,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,eAAe,WAAAA,gBAAe;AACvC,SAAS,4BAA4B;AACrC,cAAc;AACd,cAAc;","names":["default"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * elizaOS runtime plugin for the WiFi app: surfaces nearby Wi-Fi networks as
3
+ * a read-only wifiNetworks provider. Listing networks is read-only context,
4
+ * not a side-effecting action. The agent Android adapter applies hosted-app
5
+ * session gating when this package's `/plugin` export is registered.
6
+ */
7
+ import type { Plugin } from "@elizaos/core";
8
+ export declare const appWifiPlugin: Plugin;
9
+ export default appWifiPlugin;
10
+ export { wifiNetworksProvider } from "./providers/networks";
11
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,eAAO,MAAM,aAAa,EAAE,MAO3B,CAAC;AAEF,eAAe,aAAa,CAAC;AAE7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,15 @@
1
+ import { wifiNetworksProvider } from "./providers/networks.js";
2
+ const WIFI_APP_NAME = "@elizaos/plugin-wifi";
3
+ const appWifiPlugin = {
4
+ name: WIFI_APP_NAME,
5
+ description: "WiFi overlay: list nearby networks via Android WifiManager. The list is surfaced as a read-only provider; the provider only resolves while the WiFi app session is active.",
6
+ providers: [wifiNetworksProvider]
7
+ };
8
+ var plugin_default = appWifiPlugin;
9
+ import { wifiNetworksProvider as wifiNetworksProvider2 } from "./providers/networks.js";
10
+ export {
11
+ appWifiPlugin,
12
+ plugin_default as default,
13
+ wifiNetworksProvider2 as wifiNetworksProvider
14
+ };
15
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * elizaOS runtime plugin for the WiFi app: surfaces nearby Wi-Fi networks as\n * a read-only wifiNetworks provider. Listing networks is read-only context,\n * not a side-effecting action. The agent Android adapter applies hosted-app\n * session gating when this package's `/plugin` export is registered.\n */\n\nimport type { Plugin } from \"@elizaos/core\";\nimport { wifiNetworksProvider } from \"./providers/networks.js\";\n\nconst WIFI_APP_NAME = \"@elizaos/plugin-wifi\";\n\nexport const appWifiPlugin: Plugin = {\n name: WIFI_APP_NAME,\n description:\n \"WiFi overlay: list nearby networks via Android WifiManager. The list is \" +\n \"surfaced as a read-only provider; the provider only resolves while the \" +\n \"WiFi app session is active.\",\n providers: [wifiNetworksProvider],\n};\n\nexport default appWifiPlugin;\n\nexport { wifiNetworksProvider } from \"./providers/networks.js\";\n"],"mappings":"AAQA,SAAS,4BAA4B;AAErC,MAAM,gBAAgB;AAEf,MAAM,gBAAwB;AAAA,EACnC,MAAM;AAAA,EACN,aACE;AAAA,EAGF,WAAW,CAAC,oBAAoB;AAClC;AAEA,IAAO,iBAAQ;AAEf,SAAS,wBAAAA,6BAA4B;","names":["wifiNetworksProvider"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * wifiNetworks provider — read-only nearby Wi-Fi network context.
3
+ *
4
+ * Listing nearby networks is state exposure, not an agent operation with side
5
+ * effects. Surfaced as a dynamic provider so the planner can pull network
6
+ * context (signal strength, security state) when relevant.
7
+ */
8
+ import type { Provider } from "@elizaos/core";
9
+ export declare const wifiNetworksProvider: Provider;
10
+ //# sourceMappingURL=networks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"networks.d.ts","sourceRoot":"","sources":["../../src/providers/networks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAGV,QAAQ,EAGT,MAAM,eAAe,CAAC;AAYvB,eAAO,MAAM,oBAAoB,EAAE,QAgElC,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { WiFi } from "@elizaos/capacitor-wifi";
2
+ const WIFI_NETWORKS_LIMIT = 25;
3
+ const wifiNetworksProvider = {
4
+ name: "wifiNetworks",
5
+ description: "Read-only nearby Wi-Fi networks (ssid, bssid, rssi dBm, frequency MHz, secured). Source: Android WifiManager.scanResults.",
6
+ descriptionCompressed: "Wi-Fi networks: ssid, bssid, rssi, frequency, secured.",
7
+ dynamic: true,
8
+ contexts: ["system"],
9
+ contextGate: { anyOf: ["system"] },
10
+ cacheStable: false,
11
+ cacheScope: "turn",
12
+ get: async (_runtime, _message, _state) => {
13
+ try {
14
+ const { networks } = await WiFi.listAvailableNetworks({
15
+ limit: WIFI_NETWORKS_LIMIT
16
+ });
17
+ const entries = networks.map((n) => ({
18
+ ssid: n.ssid,
19
+ bssid: n.bssid,
20
+ rssi: n.rssi,
21
+ frequency: n.frequency,
22
+ secured: n.secured
23
+ }));
24
+ return {
25
+ text: JSON.stringify({
26
+ wifi_networks: {
27
+ count: entries.length,
28
+ items: entries
29
+ }
30
+ }),
31
+ values: {
32
+ wifiNetworksAvailable: entries.length > 0,
33
+ wifiNetworkCount: entries.length
34
+ },
35
+ data: {
36
+ networks: entries,
37
+ count: entries.length,
38
+ limit: WIFI_NETWORKS_LIMIT
39
+ }
40
+ };
41
+ } catch (error) {
42
+ const message = error instanceof Error ? error.message : String(error);
43
+ return {
44
+ text: "",
45
+ values: {
46
+ wifiNetworksAvailable: false,
47
+ wifiNetworkCount: 0,
48
+ wifiNetworksError: message
49
+ },
50
+ data: {
51
+ networks: [],
52
+ count: 0,
53
+ limit: WIFI_NETWORKS_LIMIT,
54
+ error: message
55
+ }
56
+ };
57
+ }
58
+ }
59
+ };
60
+ export {
61
+ wifiNetworksProvider
62
+ };
63
+ //# sourceMappingURL=networks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/networks.ts"],"sourcesContent":["/**\n * wifiNetworks provider — read-only nearby Wi-Fi network context.\n *\n * Listing nearby networks is state exposure, not an agent operation with side\n * effects. Surfaced as a dynamic provider so the planner can pull network\n * context (signal strength, security state) when relevant.\n */\n\nimport type { WiFiNetwork } from \"@elizaos/capacitor-wifi\";\nimport { WiFi } from \"@elizaos/capacitor-wifi\";\nimport type {\n IAgentRuntime,\n Memory,\n Provider,\n ProviderResult,\n State,\n} from \"@elizaos/core\";\n\nconst WIFI_NETWORKS_LIMIT = 25;\n\ninterface WifiNetworkEntry {\n ssid: string;\n bssid: string;\n rssi: number;\n frequency: number;\n secured: boolean;\n}\n\nexport const wifiNetworksProvider: Provider = {\n name: \"wifiNetworks\",\n description:\n \"Read-only nearby Wi-Fi networks (ssid, bssid, rssi dBm, frequency MHz, secured). Source: Android WifiManager.scanResults.\",\n descriptionCompressed:\n \"Wi-Fi networks: ssid, bssid, rssi, frequency, secured.\",\n dynamic: true,\n contexts: [\"system\"],\n contextGate: { anyOf: [\"system\"] },\n cacheStable: false,\n cacheScope: \"turn\",\n\n get: async (\n _runtime: IAgentRuntime,\n _message: Memory,\n _state: State,\n ): Promise<ProviderResult> => {\n try {\n const { networks } = await WiFi.listAvailableNetworks({\n limit: WIFI_NETWORKS_LIMIT,\n });\n const entries: WifiNetworkEntry[] = networks.map((n: WiFiNetwork) => ({\n ssid: n.ssid,\n bssid: n.bssid,\n rssi: n.rssi,\n frequency: n.frequency,\n secured: n.secured,\n }));\n\n return {\n text: JSON.stringify({\n wifi_networks: {\n count: entries.length,\n items: entries,\n },\n }),\n values: {\n wifiNetworksAvailable: entries.length > 0,\n wifiNetworkCount: entries.length,\n },\n data: {\n networks: entries,\n count: entries.length,\n limit: WIFI_NETWORKS_LIMIT,\n },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n text: \"\",\n values: {\n wifiNetworksAvailable: false,\n wifiNetworkCount: 0,\n wifiNetworksError: message,\n },\n data: {\n networks: [],\n count: 0,\n limit: WIFI_NETWORKS_LIMIT,\n error: message,\n },\n };\n }\n },\n};\n"],"mappings":"AASA,SAAS,YAAY;AASrB,MAAM,sBAAsB;AAUrB,MAAM,uBAAiC;AAAA,EAC5C,MAAM;AAAA,EACN,aACE;AAAA,EACF,uBACE;AAAA,EACF,SAAS;AAAA,EACT,UAAU,CAAC,QAAQ;AAAA,EACnB,aAAa,EAAE,OAAO,CAAC,QAAQ,EAAE;AAAA,EACjC,aAAa;AAAA,EACb,YAAY;AAAA,EAEZ,KAAK,OACH,UACA,UACA,WAC4B;AAC5B,QAAI;AACF,YAAM,EAAE,SAAS,IAAI,MAAM,KAAK,sBAAsB;AAAA,QACpD,OAAO;AAAA,MACT,CAAC;AACD,YAAM,UAA8B,SAAS,IAAI,CAAC,OAAoB;AAAA,QACpE,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,WAAW,EAAE;AAAA,QACb,SAAS,EAAE;AAAA,MACb,EAAE;AAEF,aAAO;AAAA,QACL,MAAM,KAAK,UAAU;AAAA,UACnB,eAAe;AAAA,YACb,OAAO,QAAQ;AAAA,YACf,OAAO;AAAA,UACT;AAAA,QACF,CAAC;AAAA,QACD,QAAQ;AAAA,UACN,uBAAuB,QAAQ,SAAS;AAAA,UACxC,kBAAkB,QAAQ;AAAA,QAC5B;AAAA,QACA,MAAM;AAAA,UACJ,UAAU;AAAA,UACV,OAAO,QAAQ;AAAA,UACf,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,uBAAuB;AAAA,UACvB,kBAAkB;AAAA,UAClB,mBAAmB;AAAA,QACrB;AAAA,QACA,MAAM;AAAA,UACJ,UAAU,CAAC;AAAA,UACX,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Side-effect entry point — registers the WiFi overlay app on ElizaOS only.
3
+ *
4
+ * Stock Android, web, iOS, and desktop do not register the overlay app, so
5
+ * loading this module remains safe on those platforms.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,6 @@
1
+ import { isElizaOS } from "@elizaos/ui";
2
+ import { registerWifiApp } from "./components/wifi-app.js";
3
+ if (isElizaOS()) {
4
+ registerWifiApp();
5
+ }
6
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/register.ts"],"sourcesContent":["/**\n * Side-effect entry point — registers the WiFi overlay app on ElizaOS only.\n *\n * Stock Android, web, iOS, and desktop do not register the overlay app, so\n * loading this module remains safe on those platforms.\n */\n\nimport { isElizaOS } from \"@elizaos/ui\";\nimport { registerWifiApp } from \"./components/wifi-app.js\";\n\nif (isElizaOS()) {\n registerWifiApp();\n}\n"],"mappings":"AAOA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEhC,IAAI,UAAU,GAAG;AACf,kBAAgB;AAClB;","names":[]}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { WifiAppView } from "./components/WifiAppView.tsx";
2
+ export { registerWifiApp, WIFI_APP_NAME, wifiApp, } from "./components/wifi-app.ts";
3
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,aAAa,EACb,OAAO,GACR,MAAM,0BAA0B,CAAC"}
package/dist/ui.js ADDED
@@ -0,0 +1,13 @@
1
+ import { WifiAppView } from "./components/WifiAppView.js";
2
+ import {
3
+ registerWifiApp,
4
+ WIFI_APP_NAME,
5
+ wifiApp
6
+ } from "./components/wifi-app.js";
7
+ export {
8
+ WIFI_APP_NAME,
9
+ WifiAppView,
10
+ registerWifiApp,
11
+ wifiApp
12
+ };
13
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui.ts"],"sourcesContent":["export { WifiAppView } from \"./components/WifiAppView.js\";\nexport {\n registerWifiApp,\n WIFI_APP_NAME,\n wifiApp,\n} from \"./components/wifi-app.js\";\n"],"mappings":"AAAA,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@elizaos/plugin-wifi",
3
+ "version": "2.0.3-beta.5",
4
+ "type": "module",
5
+ "description": "Wi-Fi overlay app for the Eliza Android build — scan, inspect, and connect to nearby networks via @elizaos/capacitor-wifi.",
6
+ "main": "./dist/index.js",
7
+ "exports": {
8
+ "./package.json": "./package.json",
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./plugin": {
15
+ "types": "./dist/plugin.d.ts",
16
+ "import": "./dist/plugin.js",
17
+ "default": "./dist/plugin.js"
18
+ },
19
+ "./*.css": "./dist/*.css",
20
+ "./*": {
21
+ "types": "./dist/*.d.ts",
22
+ "import": "./dist/*.js",
23
+ "default": "./dist/*.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "typecheck": "tsgo --noEmit -p tsconfig.json",
28
+ "lint": "bunx @biomejs/biome check src",
29
+ "test": "bunx vitest run --config ./vitest.config.ts",
30
+ "build": "bun run build:js && bun run build:types",
31
+ "clean": "node ../../packages/scripts/rm-path-recursive.mjs dist",
32
+ "build:js": "tsup --config ../tsup.plugin-packages.shared.ts",
33
+ "build:types": "tsc --noCheck -p tsconfig.build.json"
34
+ },
35
+ "dependencies": {
36
+ "@elizaos/capacitor-system": "2.0.3-beta.5",
37
+ "@elizaos/capacitor-wifi": "2.0.3-beta.5",
38
+ "@elizaos/core": "2.0.3-beta.5",
39
+ "@elizaos/shared": "2.0.3-beta.5",
40
+ "@elizaos/ui": "2.0.3-beta.5",
41
+ "lucide-react": "^1.0.0"
42
+ },
43
+ "peerDependencies": {
44
+ "react": "^19.0.0",
45
+ "react-dom": "^19.0.0"
46
+ },
47
+ "elizaos": {
48
+ "app": {
49
+ "displayName": "WiFi",
50
+ "category": "system",
51
+ "androidOnly": true,
52
+ "heroImage": "assets/hero.png"
53
+ },
54
+ "appRegister": "register"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "types": "./dist/index.d.ts",
60
+ "files": [
61
+ "dist"
62
+ ],
63
+ "devDependencies": {
64
+ "tsup": "^8.5.1",
65
+ "typescript": "^6.0.3",
66
+ "vitest": "^4.0.17"
67
+ },
68
+ "gitHead": "ff6157011c9459670021cc28a6797592a78b8817"
69
+ }