@alfe.ai/openclaw-remote 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # `@alfe.ai/openclaw-remote`
2
+
3
+ OpenClaw plugin for Alfe's interactive remote-control relay. One outbound
4
+ WebSocket carries browser co-browse and web-terminal sessions; the package also
5
+ registers bounded browser automation and human-takeover tools.
6
+
7
+ OpenClaw loads the default-only `./plugin` entry. The package root exposes named
8
+ runtime factories and types for tests and other library consumers.
9
+
10
+ ## Configuration
11
+
12
+ The plugin reads its optional entry from
13
+ `plugins.entries["@alfe.ai/openclaw-remote"].config`:
14
+
15
+ | Key | Default | Boundary |
16
+ | --- | --- | --- |
17
+ | `remoteWsUrl` | Derived from the agent API URL | Credential-free `wss:`; `ws:` only on loopback |
18
+ | `browserExecutablePath` | `/usr/bin/google-chrome-stable` | Absolute path, at most 4096 characters |
19
+ | `browserHeadless` | `true` | Boolean |
20
+ | `browserNoSandbox` | `true` | Boolean |
21
+ | `handoffTimeoutMs` | 600000 | Integer from 1000 through 1800000 |
22
+
23
+ The shared `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` escape hatch is
24
+ off by default. With the default policy, BrowserSession request interception
25
+ blocks credential-bearing URLs and private, loopback, link-local, multicast,
26
+ benchmark, documentation, and reserved literal addresses. DNS rebinding still
27
+ requires a resolving policy upstream.
28
+
29
+ ## Tools
30
+
31
+ - `browser_navigate`
32
+ - `browser_click`
33
+ - `browser_type`
34
+ - `browser_wait_for`
35
+ - `browser_screenshot`
36
+ - `browser_evaluate`
37
+ - `request_browser_takeover`
38
+
39
+ Validation failures deliberately safe for the model are returned as structured
40
+ tool errors. Unexpected browser, relay, and API diagnostics are redacted.
41
+ Screenshots use OpenClaw image content and keep base64 out of JSON details.
42
+
43
+ ## Development
44
+
45
+ ```bash
46
+ pnpm --filter @alfe.ai/openclaw-remote lint
47
+ pnpm --filter @alfe.ai/openclaw-remote typecheck
48
+ pnpm --filter @alfe.ai/openclaw-remote test
49
+ pnpm --filter @alfe.ai/openclaw-remote build
50
+ ```
51
+
52
+ See [DEVELOPING.md](./DEVELOPING.md) for lifecycle and security invariants.
package/dist/index.cjs CHANGED
@@ -1,7 +1,11 @@
1
- Object.defineProperties(exports, {
2
- __esModule: { value: true },
3
- [Symbol.toStringTag]: { value: "Module" }
4
- });
5
- const require_plugin = require("./plugin2.cjs");
6
- exports.buildIsNavigationAllowed = require_plugin.buildIsNavigationAllowed;
7
- exports.default = require_plugin.plugin;
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("./runtime.cjs");
3
+ exports.PLUGIN_VERSION = require_runtime.PLUGIN_VERSION;
4
+ exports.REMOTE_ACTIVATION_KEY = require_runtime.REMOTE_ACTIVATION_KEY;
5
+ exports.buildControlUrl = require_runtime.buildControlUrl;
6
+ exports.buildIsNavigationAllowed = require_runtime.buildIsNavigationAllowed;
7
+ exports.createRemotePlugin = require_runtime.createRemotePlugin;
8
+ exports.createRemotePluginRuntimeState = require_runtime.createRemotePluginRuntimeState;
9
+ exports.deriveDashboardBaseUrl = require_runtime.deriveDashboardBaseUrl;
10
+ exports.deriveRemoteWsUrl = require_runtime.deriveRemoteWsUrl;
11
+ exports.parseRemotePluginConfig = require_runtime.parseRemotePluginConfig;
package/dist/index.d.cts CHANGED
@@ -1,28 +1,384 @@
1
- import { i as RemotePluginConfig, r as plugin } from "./plugin.cjs";
1
+ import { n as RemotePluginConfig, t as OpenClawPluginApi } from "./types.cjs";
2
2
 
3
- //#region src/ssrf.d.ts
3
+ //#region ../agent-api-client/dist/index.d.ts
4
+
5
+ //#region src/tool-error-capture.d.ts
6
+ /**
7
+ * Tool-error capture for Alfe OpenClaw plugins.
8
+ *
9
+ * OpenClaw converts a thrown tool handler into a model-facing `tool_result`
10
+ * WITHOUT logging, and most Alfe plugins catch-and-return an error result the
11
+ * same silent way — so tool failures never appear in the runtime's output and
12
+ * therefore never reach Sentry (the gateway daemon supervises the OpenClaw
13
+ * process and reports error-looking output lines to the `agent-runtime`
14
+ * project — see packages/gateway/src/runtime-output-monitor.ts).
15
+ *
16
+ * `installToolErrorCapture(api, { plugin })` closes that gap at the ONE choke
17
+ * point every plugin already has: it wraps `api.registerTool` so every tool's
18
+ * `execute` emits a deterministic, detector-matched line on failure:
19
+ *
20
+ * [ERROR] alfe-tool plugin=<plugin> tool=<name> <thrown|result-error>: <msg> (at <first-frame>)
21
+ *
22
+ * The `[ERROR]` prefix at line start is exactly what the daemon's
23
+ * `ErrorLineDetector` classifies as an error-log block, so the failure lands
24
+ * in Sentry fingerprinted by its normalized message — no Sentry SDK inside
25
+ * the plugin process, no new dependency. Behavior toward OpenClaw and the
26
+ * model is UNCHANGED: throws are rethrown, results returned as-is.
27
+ */
28
+ /**
29
+ * Minimal shape of the OpenClaw plugin api this helper relies on. Method
30
+ * syntax on purpose — TS checks method signatures bivariantly, so each
31
+ * plugin's own concretely-typed `registerTool(tool: ToolDef): void` is
32
+ * accepted without casts.
33
+ */
34
+ interface ToolCaptureApi {
35
+ registerTool(...args: never[]): unknown;
36
+ }
37
+ interface InstallToolErrorCaptureOptions {
38
+ /** Plugin package short-name for attribution (e.g. "openclaw-secrets"). */
39
+ plugin: string;
40
+ /**
41
+ * Line sink — defaults to writing `process.stderr` directly (the plugin
42
+ * runs in-process in OpenClaw, so this lands on the runtime's stderr, which
43
+ * the daemon supervises — and a console patch can't reformat it away).
44
+ * Injectable for tests.
45
+ */
46
+ emit?: (line: string) => void;
47
+ }
48
+ /**
49
+ * Wrap `api.registerTool` so every tool registered AFTER this call gets
50
+ * failure capture. Handles both OpenClaw registration signatures:
51
+ * `registerTool(toolDef)` and `registerTool((ctx) => toolDef, opts)`.
52
+ * Call once, first thing in the plugin's `activate`/`register` entry.
53
+ * Never throws.
54
+ */
55
+ declare function installToolErrorCapture(api: ToolCaptureApi, options: InstallToolErrorCaptureOptions): void;
56
+ //# sourceMappingURL=tool-error-capture.d.ts.map
57
+ //#endregion
58
+ //#region src/transport.d.ts
59
+ /**
60
+ * Shared HTTP transport for the Agent API client — request core, retry
61
+ * policy, error formatting, and the `ApiBase` class the domain method
62
+ * groups under `./domains/` build on.
63
+ */
64
+
65
+ //#endregion
66
+ //#region ../browser/dist/index.d.ts
67
+
68
+ //#endregion
69
+ //#region src/types.d.ts
70
+ interface Logger$2 {
71
+ info(msg: string, ...args: unknown[]): void;
72
+ warn(msg: string, ...args: unknown[]): void;
73
+ error(msg: string, ...args: unknown[]): void;
74
+ debug(msg: string, ...args: unknown[]): void;
75
+ }
76
+ //#endregion
77
+ //#region src/turn-controller.d.ts
78
+ /**
79
+ * TurnController — the write-mutex between agent automation and a human during
80
+ * a browser co-browse handoff. The plugin owns the single CDP session, so this
81
+ * lives plugin-side; the relay only forwards the control frames.
82
+ *
83
+ * Only *writes* are gated — screencast reads always flow so the human sees the
84
+ * live page regardless of who holds the token. Agent automation ops call
85
+ * `acquireAgent()` and park while the human is in control; the human's input is
86
+ * injected only while `owner === 'human'`.
87
+ */
88
+
89
+ //#endregion
90
+ //#endregion
91
+ //#region src/types.d.ts
92
+ interface BrowserSessionOptions {
93
+ /** Path to the Chrome/Chromium binary (from the headless-browser integration). */
94
+ executablePath: string;
95
+ /** Persistent profile dir so cookies/login survive process restarts. */
96
+ userDataDir: string;
97
+ /** Headless mode (default true). */
98
+ headless?: boolean;
99
+ /** Pass --no-sandbox (needed on most managed Linux VMs). */
100
+ noSandbox?: boolean;
101
+ /** Shut Chrome down after this many ms with no holds/activity (default 5 min). */
102
+ idleShutdownMs?: number;
103
+ /** Extra Chrome args. */
104
+ extraArgs?: string[];
105
+ /** Guard applied to every intercepted HTTP(S) page request. */
106
+ isNavigationAllowed?: (url: string) => boolean;
107
+ logger?: Logger$2;
108
+ }
109
+ type BrowserSurfaceOptions = BrowserSessionOptions;
110
+ //#endregion
111
+ //#region src/browser-session.d.ts
112
+
113
+ //#endregion
114
+ //#region src/browser-surface.d.ts
115
+ interface HandoffResult {
116
+ released: boolean;
117
+ timedOut: boolean;
118
+ url: string;
119
+ title: string;
120
+ }
121
+ //#endregion
122
+ //#region ../config/dist/index.d.ts
4
123
 
124
+ /**
125
+ * Resolved runtime config — env vars override config file values.
126
+ *
127
+ * Hierarchy (highest priority first):
128
+ * 1. Environment variables (ALFE_API_KEY, ALFE_API_URL)
129
+ * 2. Config file (~/.alfe/config.toml)
130
+ *
131
+ * Consumers call resolveConfig() and get the resolved values —
132
+ * they don't need to know where the values came from.
133
+ */
134
+ interface ResolvedConfig {
135
+ apiKey: string;
136
+ apiUrl: string;
137
+ /**
138
+ * Base URL for the voice service's agent-authed one-shot endpoints
139
+ * (`/voice/tts`, `/voice/stt`). Derived from the token via
140
+ * {@link getVoiceServiceUrlFromToken}; currently equals `apiUrl` (the
141
+ * endpoints are co-located on the shared api gateway), but kept as its own
142
+ * field so the voice plugin has a stable seam if voice ever moves hosts.
143
+ */
144
+ voiceServiceUrl: string;
145
+ socketPath: string;
146
+ workspacePath: string;
147
+ /**
148
+ * The active agent runtime — `"openclaw"` (default) or `"hermes"`. Read from
149
+ * the top-level `runtime` key of the config. Consumers that behave
150
+ * differently per runtime (e.g. AlfeSync's per-runtime default ignore set)
151
+ * read this rather than re-parsing the TOML.
152
+ */
153
+ runtime: string;
154
+ }
155
+ //#endregion
156
+ //#region ../remote/dist/index.d.ts
157
+
158
+ declare const RemoteFrameType: {
159
+ /** viewer→plugin: a viewer attached. Payload: SessionOpenPayload. */
160
+ readonly SESSION_OPEN: 1;
161
+ /** either direction: a viewer detached / session torn down. */
162
+ readonly SESSION_CLOSE: 2;
163
+ /** plugin→viewer: current surface state. Payload: SessionStatePayload. */
164
+ readonly SESSION_STATE: 3;
165
+ /** plugin→viewer (browser): the page navigated. Payload: { url }. */
166
+ readonly NAVIGATION: 4;
167
+ /** plugin→viewer: [metaLen:u16BE][meta JSON][raw JPEG]. */
168
+ readonly SCREENCAST_FRAME: 16;
169
+ /** viewer→plugin: { frameSeq } — drives ack-gated backpressure. */
170
+ readonly SCREENCAST_ACK: 17;
171
+ readonly INPUT_MOUSE: 32;
172
+ readonly INPUT_WHEEL: 33;
173
+ readonly INPUT_KEY: 34;
174
+ /** viewer→plugin: { width, height, dpr }. */
175
+ readonly RESIZE: 35;
176
+ readonly TAKEOVER_REQUEST: 48;
177
+ readonly TAKEOVER_GRANTED: 49;
178
+ readonly TAKEOVER_DENIED: 50;
179
+ readonly RELEASE_CONTROL: 51;
180
+ readonly CONTROL_REVOKED: 52;
181
+ /** plugin→viewer: raw PTY output bytes. */
182
+ readonly TERMINAL_DATA: 64;
183
+ /** viewer→plugin: raw keystroke bytes. */
184
+ readonly TERMINAL_INPUT: 65;
185
+ /** viewer→plugin: { cols, rows }. */
186
+ readonly TERMINAL_RESIZE: 66;
187
+ };
188
+ type RemoteFrameType = (typeof RemoteFrameType)[keyof typeof RemoteFrameType];
189
+ type RemoteSurface = "browser" | "terminal";
190
+ interface RemoteFrame {
191
+ type: RemoteFrameType;
192
+ sessionId: number;
193
+ payload: Buffer;
194
+ }
195
+ interface SessionOpenPayload {
196
+ surface: RemoteSurface;
197
+ /** Browser: initial viewport in device pixels. */
198
+ width?: number;
199
+ height?: number;
200
+ dpr?: number;
201
+ /** Terminal: initial PTY dimensions. */
202
+ cols?: number;
203
+ rows?: number;
204
+ }
205
+ //#endregion
206
+ //#region src/types.d.ts
207
+ interface Logger$1 {
208
+ info(msg: string, ...args: unknown[]): void;
209
+ warn(msg: string, ...args: unknown[]): void;
210
+ error(msg: string, ...args: unknown[]): void;
211
+ debug(msg: string, ...args: unknown[]): void;
212
+ }
213
+ interface RemoteServiceClientOptions {
214
+ /** Relay WebSocket URL (e.g. wss://remote.dev.alfe.ai/ws). */
215
+ wsUrl: string;
216
+ /** Agent API key for Bearer auth on the WS upgrade. */
217
+ apiKey: string;
218
+ /**
219
+ * Handler for every well-formed inbound frame from the relay. The plugin
220
+ * dispatches by `frame.sessionId` to the owning surface handler. Kept on the
221
+ * transport as a single callback so this package stays surface-agnostic.
222
+ */
223
+ onFrame: (frame: RemoteFrame) => void | Promise<void>;
224
+ /** Called when the WS connection state changes. */
225
+ onConnectionChange?: (connected: boolean) => void | Promise<void>;
226
+ /** Optional logger (defaults to console). */
227
+ logger?: Logger$1;
228
+ }
229
+ //#endregion
230
+ //#region src/client.d.ts
231
+ //#endregion
232
+ //#region ../terminal/dist/index.d.ts
233
+
234
+ //#endregion
235
+ //#region src/types.d.ts
236
+ interface Logger {
237
+ info(msg: string, ...args: unknown[]): void;
238
+ warn(msg: string, ...args: unknown[]): void;
239
+ error(msg: string, ...args: unknown[]): void;
240
+ debug(msg: string, ...args: unknown[]): void;
241
+ }
242
+ //#endregion
243
+ //#region src/types.d.ts
244
+ interface TerminalSurfaceOptions {
245
+ /** Shell to spawn. Defaults to $SHELL or /bin/bash. */
246
+ shell?: string;
247
+ /** Working directory for the shell (the agent workspace). Defaults to cwd. */
248
+ cwd?: string;
249
+ /** Extra env for the shell. Merged over process.env. */
250
+ env?: Record<string, string>;
251
+ /** Max concurrent terminal sessions (default 8). */
252
+ maxSessions?: number;
253
+ logger?: Logger;
254
+ }
255
+ //#endregion
256
+ //#region src/terminal-surface.d.ts
257
+ //#endregion
258
+ //#region src/runtime.d.ts
259
+ declare const REMOTE_ACTIVATION_KEY: string;
260
+ declare const PLUGIN_VERSION: string;
261
+ interface RemoteApiClient {
262
+ whoami(): Promise<{
263
+ agentId: string;
264
+ }>;
265
+ requestBrowserTakeover(args: {
266
+ instructions: string;
267
+ url?: string;
268
+ conversationId?: string;
269
+ }): Promise<{
270
+ sessionId: string;
271
+ status: string;
272
+ }>;
273
+ completeRemoteSession(sessionId: string): Promise<unknown>;
274
+ }
275
+ interface BrowserSurfaceLike {
276
+ automation: {
277
+ navigate(url: string): Promise<unknown>;
278
+ click(selector: string): Promise<void>;
279
+ type(selector: string, text: string): Promise<void>;
280
+ waitFor(options: {
281
+ selector?: string;
282
+ urlPattern?: string;
283
+ ms?: number;
284
+ }): Promise<void>;
285
+ screenshot(): Promise<string>;
286
+ evaluate(expression: string): Promise<unknown>;
287
+ };
288
+ openSession(sessionId: number, open: SessionOpenPayload): void | Promise<void>;
289
+ closeSession(sessionId: number): void;
290
+ handleFrame(frame: RemoteFrame): void;
291
+ requestHandoff(timeoutMs: number): Promise<HandoffResult>;
292
+ addHold(): void;
293
+ removeHold(): void;
294
+ shutdown(): Promise<void>;
295
+ }
296
+ interface TerminalSurfaceLike {
297
+ openSession(sessionId: number, open: SessionOpenPayload): void | Promise<void>;
298
+ closeSession(sessionId: number): void;
299
+ handleFrame(frame: RemoteFrame): void;
300
+ shutdown(): void;
301
+ }
302
+ interface RemoteClientLike {
303
+ readonly bufferedAmount?: number;
304
+ start(): void;
305
+ stop(): void;
306
+ sendFrame(frame: Buffer): void;
307
+ }
308
+ interface RemotePluginRuntimeState {
309
+ generation: number;
310
+ remoteClient: RemoteClientLike | null;
311
+ browserSurface: BrowserSurfaceLike | null;
312
+ terminalSurface: TerminalSurfaceLike | null;
313
+ apiClient: RemoteApiClient | null;
314
+ handoffTimeoutMs: number;
315
+ dashboardBaseUrl?: string;
316
+ selfAgentId?: string;
317
+ sessionSurfaces: Map<number, RemoteSurface>;
318
+ stopPromise: Promise<void> | null;
319
+ }
320
+ interface RemotePluginDependencies {
321
+ resolveConfig?: () => ResolvedConfig;
322
+ createApiClient?: (config: {
323
+ apiKey: string;
324
+ apiUrl: string;
325
+ }) => RemoteApiClient;
326
+ createRemoteClient?: (options: RemoteServiceClientOptions) => RemoteClientLike;
327
+ createBrowserSurface?: (options: BrowserSurfaceOptions, sendFrame: (frame: Buffer) => void) => BrowserSurfaceLike;
328
+ createTerminalSurface?: (options: TerminalSurfaceOptions, sendFrame: (frame: Buffer) => void) => TerminalSurfaceLike;
329
+ installErrorCapture?: typeof installToolErrorCapture;
330
+ runtimeState?: RemotePluginRuntimeState;
331
+ }
332
+ declare function createRemotePluginRuntimeState(): RemotePluginRuntimeState;
333
+ /**
334
+ * Derive the relay WebSocket URL from the agent's cloud apiUrl when the
335
+ * manifest doesn't provide one — mirrors @alfe.ai/console-client's
336
+ * `deriveConsoleWsUrl` so the URL is per-stage automatically:
337
+ * https://api.dev.alfe.ai → wss://remote.dev.alfe.ai/ws
338
+ * (matches config.flyDomains.remote per stage). This is why the
339
+ * headless-browser integration manifest carries no hardcoded, prod-pinned
340
+ * `remoteWsUrl`: the plugin resolves it from the agent's own endpoint.
341
+ */
342
+ declare function deriveRemoteWsUrl(apiUrl: string): string | undefined;
343
+ /**
344
+ * Derive the dashboard (control-plane) base URL from the agent's cloud apiUrl,
345
+ * mirroring `deriveRemoteWsUrl` so it's per-stage automatically:
346
+ * https://api.dev.alfe.ai → https://app.dev.alfe.ai
347
+ * https://api.alfe.ai → https://app.alfe.ai (prod)
348
+ * The `api.` → `app.` swap matches config.*.ts `dashboardDomain` for every
349
+ * stage. Returns undefined for a non-`api.` host (e.g. localhost/dev override)
350
+ * so the caller can fall back to a session-only link.
351
+ */
352
+ declare function deriveDashboardBaseUrl(apiUrl: string): string | undefined;
353
+ /**
354
+ * Build the dashboard deep-link ("control URL") the human opens to take over.
355
+ * Prefers the full agent-scoped path; if the dashboard host or agentId is
356
+ * unavailable, degrades gracefully (session-only path, then null).
357
+ */
358
+ declare function buildControlUrl(dashboardBaseUrl: string | undefined, agentId: string | undefined, sessionId: string): string | undefined;
359
+ declare function createRemotePlugin(dependencies?: RemotePluginDependencies): {
360
+ id: string;
361
+ name: string;
362
+ description: string;
363
+ version: string;
364
+ activate(api: OpenClawPluginApi): void;
365
+ deactivate(api: OpenClawPluginApi): Promise<void>;
366
+ };
367
+ declare function parseRemotePluginConfig(value: unknown, browserFallback: unknown): RemotePluginConfig;
368
+ //#endregion
369
+ //#region src/ssrf.d.ts
5
370
  /**
6
371
  * SSRF navigation guard for the shared co-browse surface.
7
372
  *
8
- * Builds the `isNavigationAllowed` predicate that `BrowserSurface` consults
9
- * before the AGENT's `browser_navigate` tool drives a `page.goto` (see
10
- * @alfe.ai/browser `BrowserAutomation.navigate`). v1 is a synchronous
11
- * hostname / IP-literal check: it blocks navigation to private, loopback,
12
- * link-local, `.internal`, and cloud-metadata (169.254.169.254) hosts UNLESS
13
- * the integration's SSRF policy explicitly allows the private network
14
- * (`dangerouslyAllowPrivateNetwork`). The policy is the same one the `alfe`
15
- * integration exposes under `browser.ssrfPolicy` and threads into runtime
16
- * config.
373
+ * Builds the `isNavigationAllowed` predicate that `BrowserSurface` applies to
374
+ * explicit agent navigation and to every prepared page's request interception.
375
+ * It blocks non-web schemes, credential-bearing URLs, private, loopback,
376
+ * link-local, multicast, documentation, benchmark, and other reserved literal
377
+ * hosts unless the integration explicitly opts into private-network access.
17
378
  *
18
379
  * SCOPE — what this guard does and does NOT cover:
19
- * - GATES the AGENT's `browser_navigate` tool (the only path through
20
- * `automation.navigate`).
21
- * - Does NOT gate HUMAN navigation during a takeover: the human types URLs
22
- * into the live browser and those never pass through this predicate.
23
- * Blocking that requires CDP-level request interception
24
- * (`Fetch.enable` / `Network.requestIntercept`) inside the surface —
25
- * deferred (follow-up).
380
+ * - Gates agent `page.goto`, redirects, page subresources, popups, page-JS
381
+ * fetches, and human navigation after a page is prepared by BrowserSession.
26
382
  * - Does NOT defend against DNS rebinding: we deliberately do not resolve
27
383
  * hostnames to IPs here (no async DNS in a sync predicate). A public
28
384
  * hostname that resolves to a private IP at goto-time is NOT caught in v1
@@ -35,11 +391,10 @@ interface SsrfPolicy {
35
391
  /**
36
392
  * Build the navigation predicate for a given SSRF policy. When
37
393
  * `dangerouslyAllowPrivateNetwork` is true the predicate is allow-all
38
- * (matching the `alfe` integration's current default); otherwise it blocks
39
- * the reserved ranges above and any non-http(s) scheme.
394
+ * otherwise it blocks the reserved ranges above and any non-http(s) scheme.
40
395
  */
41
396
  declare function buildIsNavigationAllowed(policy: SsrfPolicy | undefined, log?: {
42
397
  warn(msg: string): void;
43
398
  }): (url: string) => boolean;
44
399
  //#endregion
45
- export { type RemotePluginConfig, type SsrfPolicy, buildIsNavigationAllowed, plugin as default };
400
+ export { type BrowserSurfaceLike, PLUGIN_VERSION, REMOTE_ACTIVATION_KEY, type RemoteApiClient, type RemoteClientLike, type RemotePluginConfig, type RemotePluginDependencies, type RemotePluginRuntimeState, type SsrfPolicy, type TerminalSurfaceLike, buildControlUrl, buildIsNavigationAllowed, createRemotePlugin, createRemotePluginRuntimeState, deriveDashboardBaseUrl, deriveRemoteWsUrl, parseRemotePluginConfig };