@alfe.ai/openclaw-remote 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +7 -1
- package/dist/plugin.d.cts +17 -1
- package/dist/plugin.d.ts +17 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin2.cjs +56 -1
- package/dist/plugin2.d.cts +2 -2
- package/dist/plugin2.d.ts +2 -2
- package/dist/plugin2.js +45 -2
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as buildIsNavigationAllowed, r as plugin } from "./plugin2.js";
|
|
2
2
|
export { buildIsNavigationAllowed, plugin as default };
|
package/dist/plugin.cjs
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
1
5
|
const require_plugin = require("./plugin2.cjs");
|
|
2
|
-
|
|
6
|
+
exports.buildControlUrl = require_plugin.buildControlUrl;
|
|
7
|
+
exports.default = require_plugin.plugin;
|
|
8
|
+
exports.deriveDashboardBaseUrl = require_plugin.deriveDashboardBaseUrl;
|
package/dist/plugin.d.cts
CHANGED
|
@@ -64,6 +64,22 @@ interface OpenClawPluginApi {
|
|
|
64
64
|
}
|
|
65
65
|
//#endregion
|
|
66
66
|
//#region src/plugin.d.ts
|
|
67
|
+
/**
|
|
68
|
+
* Derive the dashboard (control-plane) base URL from the agent's cloud apiUrl,
|
|
69
|
+
* mirroring `deriveRemoteWsUrl` so it's per-stage automatically:
|
|
70
|
+
* https://api.dev.alfe.ai → https://app.dev.alfe.ai
|
|
71
|
+
* https://api.alfe.ai → https://app.alfe.ai (prod)
|
|
72
|
+
* The `api.` → `app.` swap matches config.*.ts `dashboardDomain` for every
|
|
73
|
+
* stage. Returns undefined for a non-`api.` host (e.g. localhost/dev override)
|
|
74
|
+
* so the caller can fall back to a session-only link.
|
|
75
|
+
*/
|
|
76
|
+
declare function deriveDashboardBaseUrl(apiUrl: string): string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Build the dashboard deep-link ("control URL") the human opens to take over.
|
|
79
|
+
* Prefers the full agent-scoped path; if the dashboard host or agentId is
|
|
80
|
+
* unavailable, degrades gracefully (session-only path, then null).
|
|
81
|
+
*/
|
|
82
|
+
declare function buildControlUrl(dashboardBaseUrl: string | undefined, agentId: string | undefined, sessionId: string): string | undefined;
|
|
67
83
|
declare const plugin: {
|
|
68
84
|
id: string;
|
|
69
85
|
name: string;
|
|
@@ -73,4 +89,4 @@ declare const plugin: {
|
|
|
73
89
|
deactivate(api: OpenClawPluginApi): void;
|
|
74
90
|
};
|
|
75
91
|
//#endregion
|
|
76
|
-
export { RemotePluginConfig as n, plugin as t };
|
|
92
|
+
export { RemotePluginConfig as i, deriveDashboardBaseUrl as n, plugin as r, buildControlUrl as t };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -64,6 +64,22 @@ interface OpenClawPluginApi {
|
|
|
64
64
|
}
|
|
65
65
|
//#endregion
|
|
66
66
|
//#region src/plugin.d.ts
|
|
67
|
+
/**
|
|
68
|
+
* Derive the dashboard (control-plane) base URL from the agent's cloud apiUrl,
|
|
69
|
+
* mirroring `deriveRemoteWsUrl` so it's per-stage automatically:
|
|
70
|
+
* https://api.dev.alfe.ai → https://app.dev.alfe.ai
|
|
71
|
+
* https://api.alfe.ai → https://app.alfe.ai (prod)
|
|
72
|
+
* The `api.` → `app.` swap matches config.*.ts `dashboardDomain` for every
|
|
73
|
+
* stage. Returns undefined for a non-`api.` host (e.g. localhost/dev override)
|
|
74
|
+
* so the caller can fall back to a session-only link.
|
|
75
|
+
*/
|
|
76
|
+
declare function deriveDashboardBaseUrl(apiUrl: string): string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Build the dashboard deep-link ("control URL") the human opens to take over.
|
|
79
|
+
* Prefers the full agent-scoped path; if the dashboard host or agentId is
|
|
80
|
+
* unavailable, degrades gracefully (session-only path, then null).
|
|
81
|
+
*/
|
|
82
|
+
declare function buildControlUrl(dashboardBaseUrl: string | undefined, agentId: string | undefined, sessionId: string): string | undefined;
|
|
67
83
|
declare const plugin: {
|
|
68
84
|
id: string;
|
|
69
85
|
name: string;
|
|
@@ -73,4 +89,4 @@ declare const plugin: {
|
|
|
73
89
|
deactivate(api: OpenClawPluginApi): void;
|
|
74
90
|
};
|
|
75
91
|
//#endregion
|
|
76
|
-
export { RemotePluginConfig as n, plugin as t };
|
|
92
|
+
export { RemotePluginConfig as i, deriveDashboardBaseUrl as n, plugin as r, buildControlUrl as t };
|
package/dist/plugin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { plugin as default };
|
|
1
|
+
import { n as deriveDashboardBaseUrl, r as plugin, t as buildControlUrl } from "./plugin2.js";
|
|
2
|
+
export { buildControlUrl, plugin as default, deriveDashboardBaseUrl };
|
package/dist/plugin2.cjs
CHANGED
|
@@ -125,11 +125,42 @@ function deriveRemoteWsUrl(apiUrl) {
|
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Derive the dashboard (control-plane) base URL from the agent's cloud apiUrl,
|
|
130
|
+
* mirroring `deriveRemoteWsUrl` so it's per-stage automatically:
|
|
131
|
+
* https://api.dev.alfe.ai → https://app.dev.alfe.ai
|
|
132
|
+
* https://api.alfe.ai → https://app.alfe.ai (prod)
|
|
133
|
+
* The `api.` → `app.` swap matches config.*.ts `dashboardDomain` for every
|
|
134
|
+
* stage. Returns undefined for a non-`api.` host (e.g. localhost/dev override)
|
|
135
|
+
* so the caller can fall back to a session-only link.
|
|
136
|
+
*/
|
|
137
|
+
function deriveDashboardBaseUrl(apiUrl) {
|
|
138
|
+
try {
|
|
139
|
+
const url = new URL(apiUrl);
|
|
140
|
+
if (!url.hostname.startsWith("api.")) return void 0;
|
|
141
|
+
return `https://${url.hostname.replace("api.", "app.")}`;
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build the dashboard deep-link ("control URL") the human opens to take over.
|
|
148
|
+
* Prefers the full agent-scoped path; if the dashboard host or agentId is
|
|
149
|
+
* unavailable, degrades gracefully (session-only path, then null).
|
|
150
|
+
*/
|
|
151
|
+
function buildControlUrl(dashboardBaseUrl, agentId, sessionId) {
|
|
152
|
+
if (!dashboardBaseUrl) return void 0;
|
|
153
|
+
const session = encodeURIComponent(sessionId);
|
|
154
|
+
if (agentId) return `${dashboardBaseUrl}/agents/${encodeURIComponent(agentId)}?tab=browser&session=${session}`;
|
|
155
|
+
return `${dashboardBaseUrl}/agents?tab=browser&session=${session}`;
|
|
156
|
+
}
|
|
128
157
|
let remoteClient = null;
|
|
129
158
|
let browserSurface = null;
|
|
130
159
|
let terminalSurface = null;
|
|
131
160
|
let apiClient = null;
|
|
132
161
|
let handoffTimeoutMs = DEFAULT_HANDOFF_TIMEOUT_MS;
|
|
162
|
+
let dashboardBaseUrl;
|
|
163
|
+
let selfAgentId;
|
|
133
164
|
const sessionSurfaces = /* @__PURE__ */ new Map();
|
|
134
165
|
function g() {
|
|
135
166
|
return globalThis;
|
|
@@ -193,6 +224,12 @@ function startService(pluginConfig, ssrfPolicy, workspaceDir, log) {
|
|
|
193
224
|
apiKey,
|
|
194
225
|
apiUrl
|
|
195
226
|
});
|
|
227
|
+
dashboardBaseUrl = deriveDashboardBaseUrl(apiUrl);
|
|
228
|
+
apiClient.whoami().then(({ agentId }) => {
|
|
229
|
+
selfAgentId = agentId;
|
|
230
|
+
}).catch((err) => {
|
|
231
|
+
log.debug(`whoami failed — takeover links will omit agentId: ${err.message}`);
|
|
232
|
+
});
|
|
196
233
|
const sendFrame = (buf) => {
|
|
197
234
|
remoteClient?.sendFrame(buf);
|
|
198
235
|
};
|
|
@@ -231,6 +268,8 @@ function stopService(log) {
|
|
|
231
268
|
terminalSurface?.shutdown();
|
|
232
269
|
terminalSurface = null;
|
|
233
270
|
apiClient = null;
|
|
271
|
+
dashboardBaseUrl = void 0;
|
|
272
|
+
selfAgentId = void 0;
|
|
234
273
|
sessionSurfaces.clear();
|
|
235
274
|
log.info("Remote plugin stopped");
|
|
236
275
|
}
|
|
@@ -341,7 +380,7 @@ function registerTools(api) {
|
|
|
341
380
|
api.registerTool({
|
|
342
381
|
name: "request_browser_takeover",
|
|
343
382
|
label: "request_browser_takeover",
|
|
344
|
-
description: "Ask a human to take over the browser you're currently looking at and complete a step you can't do yourself — logging in, solving a captcha, or clicking through a manual flow. The human sees your current live page, completes the instructions, and hands control back; you then resume on the same authenticated page. Blocks until the human is done or the request times out.",
|
|
383
|
+
description: "Ask a human to take over the browser you're currently looking at and complete a step you can't do yourself — logging in, solving a captcha, or clicking through a manual flow. The human sees your current live page, completes the instructions, and hands control back; you then resume on the same authenticated page. Returns a control URL — SHARE IT WITH THE USER so they can open the takeover. Blocks until the human is done or the request times out.",
|
|
345
384
|
parameters: {
|
|
346
385
|
type: "object",
|
|
347
386
|
properties: {
|
|
@@ -368,9 +407,13 @@ function registerTools(api) {
|
|
|
368
407
|
url: optStr(params.url),
|
|
369
408
|
conversationId: optStr(params.conversationId)
|
|
370
409
|
});
|
|
410
|
+
const controlUrl = buildControlUrl(dashboardBaseUrl, selfAgentId, sessionId);
|
|
411
|
+
const message = controlUrl ? `Browser takeover requested (session ${sessionId}). Ask the user to open this link to take control and complete: ${controlUrl} — then wait; I'll resume automatically once they hand back.` : `Browser takeover requested (session ${sessionId}). Ask the user to open the Alfe dashboard, go to this agent's Browser tab, and take control — then wait; I'll resume automatically once they hand back.`;
|
|
371
412
|
try {
|
|
372
413
|
return {
|
|
373
414
|
sessionId,
|
|
415
|
+
controlUrl,
|
|
416
|
+
message,
|
|
374
417
|
...await surface.requestHandoff(handoffTimeoutMs)
|
|
375
418
|
};
|
|
376
419
|
} finally {
|
|
@@ -409,12 +452,24 @@ const plugin = {
|
|
|
409
452
|
}
|
|
410
453
|
};
|
|
411
454
|
//#endregion
|
|
455
|
+
Object.defineProperty(exports, "buildControlUrl", {
|
|
456
|
+
enumerable: true,
|
|
457
|
+
get: function() {
|
|
458
|
+
return buildControlUrl;
|
|
459
|
+
}
|
|
460
|
+
});
|
|
412
461
|
Object.defineProperty(exports, "buildIsNavigationAllowed", {
|
|
413
462
|
enumerable: true,
|
|
414
463
|
get: function() {
|
|
415
464
|
return buildIsNavigationAllowed;
|
|
416
465
|
}
|
|
417
466
|
});
|
|
467
|
+
Object.defineProperty(exports, "deriveDashboardBaseUrl", {
|
|
468
|
+
enumerable: true,
|
|
469
|
+
get: function() {
|
|
470
|
+
return deriveDashboardBaseUrl;
|
|
471
|
+
}
|
|
472
|
+
});
|
|
418
473
|
Object.defineProperty(exports, "plugin", {
|
|
419
474
|
enumerable: true,
|
|
420
475
|
get: function() {
|
package/dist/plugin2.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { plugin as default };
|
|
1
|
+
import { n as deriveDashboardBaseUrl, r as plugin, t as buildControlUrl } from "./plugin.cjs";
|
|
2
|
+
export { buildControlUrl, plugin as default, deriveDashboardBaseUrl };
|
package/dist/plugin2.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { plugin as default };
|
|
1
|
+
import { n as deriveDashboardBaseUrl, r as plugin, t as buildControlUrl } from "./plugin.js";
|
|
2
|
+
export { buildControlUrl, plugin as default, deriveDashboardBaseUrl };
|
package/dist/plugin2.js
CHANGED
|
@@ -125,11 +125,42 @@ function deriveRemoteWsUrl(apiUrl) {
|
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Derive the dashboard (control-plane) base URL from the agent's cloud apiUrl,
|
|
130
|
+
* mirroring `deriveRemoteWsUrl` so it's per-stage automatically:
|
|
131
|
+
* https://api.dev.alfe.ai → https://app.dev.alfe.ai
|
|
132
|
+
* https://api.alfe.ai → https://app.alfe.ai (prod)
|
|
133
|
+
* The `api.` → `app.` swap matches config.*.ts `dashboardDomain` for every
|
|
134
|
+
* stage. Returns undefined for a non-`api.` host (e.g. localhost/dev override)
|
|
135
|
+
* so the caller can fall back to a session-only link.
|
|
136
|
+
*/
|
|
137
|
+
function deriveDashboardBaseUrl(apiUrl) {
|
|
138
|
+
try {
|
|
139
|
+
const url = new URL(apiUrl);
|
|
140
|
+
if (!url.hostname.startsWith("api.")) return void 0;
|
|
141
|
+
return `https://${url.hostname.replace("api.", "app.")}`;
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build the dashboard deep-link ("control URL") the human opens to take over.
|
|
148
|
+
* Prefers the full agent-scoped path; if the dashboard host or agentId is
|
|
149
|
+
* unavailable, degrades gracefully (session-only path, then null).
|
|
150
|
+
*/
|
|
151
|
+
function buildControlUrl(dashboardBaseUrl, agentId, sessionId) {
|
|
152
|
+
if (!dashboardBaseUrl) return void 0;
|
|
153
|
+
const session = encodeURIComponent(sessionId);
|
|
154
|
+
if (agentId) return `${dashboardBaseUrl}/agents/${encodeURIComponent(agentId)}?tab=browser&session=${session}`;
|
|
155
|
+
return `${dashboardBaseUrl}/agents?tab=browser&session=${session}`;
|
|
156
|
+
}
|
|
128
157
|
let remoteClient = null;
|
|
129
158
|
let browserSurface = null;
|
|
130
159
|
let terminalSurface = null;
|
|
131
160
|
let apiClient = null;
|
|
132
161
|
let handoffTimeoutMs = DEFAULT_HANDOFF_TIMEOUT_MS;
|
|
162
|
+
let dashboardBaseUrl;
|
|
163
|
+
let selfAgentId;
|
|
133
164
|
const sessionSurfaces = /* @__PURE__ */ new Map();
|
|
134
165
|
function g() {
|
|
135
166
|
return globalThis;
|
|
@@ -193,6 +224,12 @@ function startService(pluginConfig, ssrfPolicy, workspaceDir, log) {
|
|
|
193
224
|
apiKey,
|
|
194
225
|
apiUrl
|
|
195
226
|
});
|
|
227
|
+
dashboardBaseUrl = deriveDashboardBaseUrl(apiUrl);
|
|
228
|
+
apiClient.whoami().then(({ agentId }) => {
|
|
229
|
+
selfAgentId = agentId;
|
|
230
|
+
}).catch((err) => {
|
|
231
|
+
log.debug(`whoami failed — takeover links will omit agentId: ${err.message}`);
|
|
232
|
+
});
|
|
196
233
|
const sendFrame = (buf) => {
|
|
197
234
|
remoteClient?.sendFrame(buf);
|
|
198
235
|
};
|
|
@@ -231,6 +268,8 @@ function stopService(log) {
|
|
|
231
268
|
terminalSurface?.shutdown();
|
|
232
269
|
terminalSurface = null;
|
|
233
270
|
apiClient = null;
|
|
271
|
+
dashboardBaseUrl = void 0;
|
|
272
|
+
selfAgentId = void 0;
|
|
234
273
|
sessionSurfaces.clear();
|
|
235
274
|
log.info("Remote plugin stopped");
|
|
236
275
|
}
|
|
@@ -341,7 +380,7 @@ function registerTools(api) {
|
|
|
341
380
|
api.registerTool({
|
|
342
381
|
name: "request_browser_takeover",
|
|
343
382
|
label: "request_browser_takeover",
|
|
344
|
-
description: "Ask a human to take over the browser you're currently looking at and complete a step you can't do yourself — logging in, solving a captcha, or clicking through a manual flow. The human sees your current live page, completes the instructions, and hands control back; you then resume on the same authenticated page. Blocks until the human is done or the request times out.",
|
|
383
|
+
description: "Ask a human to take over the browser you're currently looking at and complete a step you can't do yourself — logging in, solving a captcha, or clicking through a manual flow. The human sees your current live page, completes the instructions, and hands control back; you then resume on the same authenticated page. Returns a control URL — SHARE IT WITH THE USER so they can open the takeover. Blocks until the human is done or the request times out.",
|
|
345
384
|
parameters: {
|
|
346
385
|
type: "object",
|
|
347
386
|
properties: {
|
|
@@ -368,9 +407,13 @@ function registerTools(api) {
|
|
|
368
407
|
url: optStr(params.url),
|
|
369
408
|
conversationId: optStr(params.conversationId)
|
|
370
409
|
});
|
|
410
|
+
const controlUrl = buildControlUrl(dashboardBaseUrl, selfAgentId, sessionId);
|
|
411
|
+
const message = controlUrl ? `Browser takeover requested (session ${sessionId}). Ask the user to open this link to take control and complete: ${controlUrl} — then wait; I'll resume automatically once they hand back.` : `Browser takeover requested (session ${sessionId}). Ask the user to open the Alfe dashboard, go to this agent's Browser tab, and take control — then wait; I'll resume automatically once they hand back.`;
|
|
371
412
|
try {
|
|
372
413
|
return {
|
|
373
414
|
sessionId,
|
|
415
|
+
controlUrl,
|
|
416
|
+
message,
|
|
374
417
|
...await surface.requestHandoff(handoffTimeoutMs)
|
|
375
418
|
};
|
|
376
419
|
} finally {
|
|
@@ -409,4 +452,4 @@ const plugin = {
|
|
|
409
452
|
}
|
|
410
453
|
};
|
|
411
454
|
//#endregion
|
|
412
|
-
export { buildIsNavigationAllowed as n, plugin as t };
|
|
455
|
+
export { buildIsNavigationAllowed as i, deriveDashboardBaseUrl as n, plugin as r, buildControlUrl as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-remote",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "OpenClaw plugin for Alfe's interactive remote-control relay — browser co-browse + web terminal surfaces over one outbound WS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"openclaw.plugin.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
30
|
+
"@alfe.ai/agent-api-client": "^0.6.1",
|
|
31
31
|
"@alfe.ai/browser": "^0.1.0",
|
|
32
32
|
"@alfe.ai/config": "0.3.0",
|
|
33
33
|
"@alfe.ai/remote": "^0.1.0",
|