replicas-computer 0.3.31 → 0.3.32
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.js +154 -6
- package/dist/stream-viewer.js +63 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1907,13 +1907,22 @@ async function computerBrowserStateCommand(path, options = {}) {
|
|
|
1907
1907
|
}));
|
|
1908
1908
|
console.log(JSON.stringify({ targetId: page.id ?? "unknown", ...observation }, null, 2));
|
|
1909
1909
|
}
|
|
1910
|
-
var
|
|
1910
|
+
var VIEWPORT_ORIGIN_JS = `
|
|
1911
|
+
const viewportOrigin = () => {
|
|
1912
|
+
const zoom = window.devicePixelRatio;
|
|
1913
|
+
const border = Math.max(0, (window.outerWidth - window.innerWidth * zoom) / 2);
|
|
1914
|
+
return {
|
|
1915
|
+
left: window.screenX + border,
|
|
1916
|
+
top: window.screenY + Math.max(0, window.outerHeight - window.innerHeight * zoom - border),
|
|
1917
|
+
zoom,
|
|
1918
|
+
};
|
|
1919
|
+
};`;
|
|
1920
|
+
var DESKTOP_POINT_JS = `${VIEWPORT_ORIGIN_JS}
|
|
1911
1921
|
const desktopPoint = (rect) => {
|
|
1912
|
-
const
|
|
1913
|
-
const topChrome = Math.max(0, window.outerHeight - window.innerHeight - borderX);
|
|
1922
|
+
const { left, top, zoom } = viewportOrigin();
|
|
1914
1923
|
return {
|
|
1915
|
-
x: Math.round(
|
|
1916
|
-
y: Math.round(
|
|
1924
|
+
x: Math.round(left + (rect.x + rect.width / 2) * zoom),
|
|
1925
|
+
y: Math.round(top + (rect.y + rect.height / 2) * zoom),
|
|
1917
1926
|
};
|
|
1918
1927
|
};`;
|
|
1919
1928
|
function parseBrowserRef(value) {
|
|
@@ -3316,7 +3325,7 @@ async function computerStatusCommand() {
|
|
|
3316
3325
|
}
|
|
3317
3326
|
|
|
3318
3327
|
// src/version.ts
|
|
3319
|
-
var COMPUTER_USE_VERSION = "0.3.
|
|
3328
|
+
var COMPUTER_USE_VERSION = "0.3.32";
|
|
3320
3329
|
var COMPUTER_USE_PROTOCOL_VERSION = 1;
|
|
3321
3330
|
|
|
3322
3331
|
// src/program.ts
|
|
@@ -3908,6 +3917,42 @@ function superviseEncoder(options) {
|
|
|
3908
3917
|
// src/ice-servers.ts
|
|
3909
3918
|
import { readFileSync as readFileSync7 } from "fs";
|
|
3910
3919
|
|
|
3920
|
+
// ../shared/src/urls.ts
|
|
3921
|
+
var DASHBOARD_PATH = "/dashboard";
|
|
3922
|
+
var WEB_APP_PATHS = {
|
|
3923
|
+
home: "/",
|
|
3924
|
+
onboarding: "/onboarding",
|
|
3925
|
+
workspaces: "/workspace",
|
|
3926
|
+
environmentSetup: "/workspace/setup",
|
|
3927
|
+
automations: "/automations",
|
|
3928
|
+
environment: "/environment",
|
|
3929
|
+
analytics: "/analytics",
|
|
3930
|
+
review: "/review",
|
|
3931
|
+
dashboard: DASHBOARD_PATH,
|
|
3932
|
+
agents: `${DASHBOARD_PATH}/agents`,
|
|
3933
|
+
integrations: `${DASHBOARD_PATH}/integrations`,
|
|
3934
|
+
integrationsGithub: `${DASHBOARD_PATH}/integrations/github`,
|
|
3935
|
+
integrationsGitlab: `${DASHBOARD_PATH}/integrations/gitlab`,
|
|
3936
|
+
integrationsSlack: `${DASHBOARD_PATH}/integrations/slack`,
|
|
3937
|
+
settings: `${DASHBOARD_PATH}/settings`,
|
|
3938
|
+
billing: `${DASHBOARD_PATH}/billing`,
|
|
3939
|
+
members: `${DASHBOARD_PATH}/members`,
|
|
3940
|
+
learnings: `${DASHBOARD_PATH}/learnings`,
|
|
3941
|
+
"audit-logs": `${DASHBOARD_PATH}/audit-logs`,
|
|
3942
|
+
accountAgents: `${DASHBOARD_PATH}/account/agents`,
|
|
3943
|
+
accountProfile: `${DASHBOARD_PATH}/account/profile`,
|
|
3944
|
+
accountConnections: `${DASHBOARD_PATH}/account/connections`,
|
|
3945
|
+
accountIntegrations: `${DASHBOARD_PATH}/account/integrations`,
|
|
3946
|
+
accountApiKeys: `${DASHBOARD_PATH}/account/api-keys`,
|
|
3947
|
+
accountPreferences: `${DASHBOARD_PATH}/account/preferences`,
|
|
3948
|
+
fullscreenWorkspaces: "/workspaces"
|
|
3949
|
+
};
|
|
3950
|
+
var LEGACY_WEB_APP_PATHS = {
|
|
3951
|
+
app: "/app",
|
|
3952
|
+
home: "/home",
|
|
3953
|
+
dashboardWorkspaces: `${DASHBOARD_PATH}/workspaces`
|
|
3954
|
+
};
|
|
3955
|
+
|
|
3911
3956
|
// ../shared/src/desktop-stream.ts
|
|
3912
3957
|
function isStreamIceServer(value) {
|
|
3913
3958
|
return isRecord(value) && typeof value.urls === "string" && (value.username === void 0 || typeof value.username === "string") && (value.credential === void 0 || typeof value.credential === "string");
|
|
@@ -3971,6 +4016,10 @@ function isDesktopWebRtcFailure(value) {
|
|
|
3971
4016
|
"codec"
|
|
3972
4017
|
].every((key) => typeof value[key] === "string" && value[key].length <= 200) && ["elapsedMs", "candidateErrors", "framesDecoded", "packetsReceived", "packetsLost", "bytesReceived", "lastFrameAgeMs", "encoderFps"].every((key) => typeof value[key] === "number" && Number.isFinite(value[key]));
|
|
3973
4018
|
}
|
|
4019
|
+
var isDesktopRect = (value) => isRecord(value) && ["x", "y", "width", "height"].every((key) => typeof value[key] === "number" && Number.isFinite(value[key]));
|
|
4020
|
+
function isDesktopElement(value) {
|
|
4021
|
+
return isRecord(value) && isDesktopRect(value.rect) && ["url", "tag", "selector"].every((key) => typeof value[key] === "string") && ["text", "label", "source"].every((key) => value[key] === void 0 || typeof value[key] === "string") && (value.components === void 0 || Array.isArray(value.components) && value.components.every((name) => typeof name === "string"));
|
|
4022
|
+
}
|
|
3974
4023
|
|
|
3975
4024
|
// ../shared/src/runtime-env.ts
|
|
3976
4025
|
var REPLICAS_RUNTIME_ENV_ALIASES = {
|
|
@@ -4935,6 +4984,92 @@ var InputBridge = class {
|
|
|
4935
4984
|
}
|
|
4936
4985
|
};
|
|
4937
4986
|
|
|
4987
|
+
// src/desktop-inspect.ts
|
|
4988
|
+
var PAGE_GEOMETRY = `(() => {${VIEWPORT_ORIGIN_JS}
|
|
4989
|
+
return { visible: document.visibilityState === 'visible', focused: document.hasFocus(), innerWidth, innerHeight, ...viewportOrigin() };
|
|
4990
|
+
})()`;
|
|
4991
|
+
var DESCRIBE_ELEMENT = `function () {
|
|
4992
|
+
let el = this.nodeType === 1 ? this : this.parentElement;
|
|
4993
|
+
if (!el) return null;
|
|
4994
|
+
while (el.ownerSVGElement) el = el.ownerSVGElement;
|
|
4995
|
+
el = el.closest('a, button, label, summary, [role="button"], [role="link"], [role="tab"], [role="menuitem"], [role="option"], [role="checkbox"], [role="switch"]') || el;
|
|
4996
|
+
const clip = (value, max) => {
|
|
4997
|
+
const text = String(value || '').replace(/\\s+/g, ' ').trim();
|
|
4998
|
+
return !text ? undefined : text.length > max ? text.slice(0, max - 1) + '\u2026' : text;
|
|
4999
|
+
};
|
|
5000
|
+
const step = (node) => {
|
|
5001
|
+
if (node.id) return '#' + CSS.escape(node.id);
|
|
5002
|
+
const same = node.parentElement ? [...node.parentElement.children].filter((child) => child.localName === node.localName) : [];
|
|
5003
|
+
return node.localName + [...node.classList].filter((name) => /^[\\w-]+$/.test(name)).slice(0, 2).map((name) => '.' + name).join('')
|
|
5004
|
+
+ (same.length > 1 ? ':nth-of-type(' + (same.indexOf(node) + 1) + ')' : '');
|
|
5005
|
+
};
|
|
5006
|
+
const steps = [];
|
|
5007
|
+
for (let node = el; node && node !== document.documentElement && steps.length < 4; node = node.parentElement) {
|
|
5008
|
+
steps.unshift(step(node));
|
|
5009
|
+
if (node.id) break;
|
|
5010
|
+
}
|
|
5011
|
+
const components = [];
|
|
5012
|
+
let source;
|
|
5013
|
+
try {
|
|
5014
|
+
const key = Object.keys(el).find((name) => name.startsWith('__reactFiber$') || name.startsWith('__reactInternalInstance$'));
|
|
5015
|
+
const typeName = (type, depth = 0) => typeof type === 'function' ? type.displayName || type.name
|
|
5016
|
+
: type && depth < 3 ? type.displayName || typeName(type.render, depth + 1) || typeName(type.type, depth + 1) : undefined;
|
|
5017
|
+
const host = key && el[key];
|
|
5018
|
+
const next = host && host._debugOwner ? (fiber) => fiber._debugOwner || fiber.owner : (fiber) => fiber.return;
|
|
5019
|
+
for (let fiber = host && next(host); fiber && components.length < 4; fiber = next(fiber)) {
|
|
5020
|
+
const name = typeof fiber.tag !== 'number' ? fiber.name : [0, 1, 11, 14, 15].includes(fiber.tag) ? typeName(fiber.type) : undefined;
|
|
5021
|
+
if (typeof name === 'string' && name.length > 1 && !/^_c\\d*$/.test(name) && components.at(-1) !== name) components.push(name);
|
|
5022
|
+
}
|
|
5023
|
+
const debugSource = host && host._debugSource;
|
|
5024
|
+
if (debugSource && debugSource.fileName) source = debugSource.fileName + ':' + debugSource.lineNumber;
|
|
5025
|
+
} catch {}
|
|
5026
|
+
const rect = el.getBoundingClientRect();
|
|
5027
|
+
let x = rect.x, y = rect.y;
|
|
5028
|
+
try {
|
|
5029
|
+
for (let view = window; view.frameElement; view = view.parent) {
|
|
5030
|
+
const frame = view.frameElement.getBoundingClientRect();
|
|
5031
|
+
x += frame.x + view.frameElement.clientLeft;
|
|
5032
|
+
y += frame.y + view.frameElement.clientTop;
|
|
5033
|
+
}
|
|
5034
|
+
} catch {}
|
|
5035
|
+
return {
|
|
5036
|
+
url: location.href,
|
|
5037
|
+
tag: el.localName,
|
|
5038
|
+
selector: steps.join(' > '),
|
|
5039
|
+
rect: { x, y, width: rect.width, height: rect.height },
|
|
5040
|
+
text: clip(el.innerText || (el.type === 'password' ? '' : el.value) || el.textContent, 120),
|
|
5041
|
+
label: clip(el.getAttribute('aria-label') || el.getAttribute('title') || el.getAttribute('alt') || el.getAttribute('placeholder'), 80),
|
|
5042
|
+
components: components.length ? components : undefined,
|
|
5043
|
+
source,
|
|
5044
|
+
};
|
|
5045
|
+
}`;
|
|
5046
|
+
async function inspectPage(session, x, y) {
|
|
5047
|
+
const page = chromeCallValue(await sendChromeSessionCommand(session, "Runtime.evaluate", { expression: PAGE_GEOMETRY, returnByValue: true }));
|
|
5048
|
+
if (!isRecord(page) || page.visible !== true) return null;
|
|
5049
|
+
const [left, top, zoom, innerWidth, innerHeight] = [page.left, page.top, page.zoom, page.innerWidth, page.innerHeight].map(Number);
|
|
5050
|
+
const pageX = (x - left) / zoom;
|
|
5051
|
+
const pageY = (y - top) / zoom;
|
|
5052
|
+
if (!(pageX >= 0 && pageY >= 0 && pageX < innerWidth && pageY < innerHeight)) return null;
|
|
5053
|
+
const focused = page.focused === true;
|
|
5054
|
+
const located = await sendChromeSessionCommand(session, "DOM.getNodeForLocation", { x: Math.floor(pageX), y: Math.floor(pageY) });
|
|
5055
|
+
const resolved = await sendChromeSessionCommand(session, "DOM.resolveNode", { backendNodeId: located.backendNodeId });
|
|
5056
|
+
const objectId = isRecord(resolved.object) ? resolved.object.objectId : void 0;
|
|
5057
|
+
if (typeof objectId !== "string") return { focused, element: null };
|
|
5058
|
+
const described = chromeCallValue(await sendChromeSessionCommand(session, "Runtime.callFunctionOn", { objectId, functionDeclaration: DESCRIBE_ELEMENT, returnByValue: true }));
|
|
5059
|
+
if (!isRecord(described) || !isRecord(described.rect)) return { focused, element: null };
|
|
5060
|
+
const { x: rectX, y: rectY, width: width2, height: height2 } = described.rect;
|
|
5061
|
+
const element = {
|
|
5062
|
+
...described,
|
|
5063
|
+
rect: { x: left + Number(rectX) * zoom, y: top + Number(rectY) * zoom, width: Number(width2) * zoom, height: Number(height2) * zoom }
|
|
5064
|
+
};
|
|
5065
|
+
return { focused, element: isDesktopElement(element) ? element : null };
|
|
5066
|
+
}
|
|
5067
|
+
async function inspectDesktopPoint(x, y) {
|
|
5068
|
+
const pages = (await getChromePages()).flatMap((page) => page.webSocketDebuggerUrl ? [page.webSocketDebuggerUrl] : []);
|
|
5069
|
+
const hits = (await Promise.all(pages.map((url) => withChromeSession(url, (session) => inspectPage(session, x, y)).catch(() => null)))).filter((hit) => hit !== null);
|
|
5070
|
+
return hits.find((hit) => hit.focused)?.element ?? null;
|
|
5071
|
+
}
|
|
5072
|
+
|
|
4938
5073
|
// src/media-server.ts
|
|
4939
5074
|
var width = Number.parseInt(process.env.REPLICAS_DESKTOP_WIDTH || String(DESKTOP_VIEWER_WIDTH), 10);
|
|
4940
5075
|
var height = Number.parseInt(process.env.REPLICAS_DESKTOP_HEIGHT || String(DESKTOP_VIEWER_HEIGHT), 10);
|
|
@@ -5842,6 +5977,19 @@ async function runMediaServer() {
|
|
|
5842
5977
|
});
|
|
5843
5978
|
return;
|
|
5844
5979
|
}
|
|
5980
|
+
if (url.pathname === "/inspect") {
|
|
5981
|
+
const x = Number(url.searchParams.get("x"));
|
|
5982
|
+
const y = Number(url.searchParams.get("y"));
|
|
5983
|
+
response.setHeader("cache-control", "no-store");
|
|
5984
|
+
if (!(x >= 0 && x < width && y >= 0 && y < height)) {
|
|
5985
|
+
response.statusCode = 400;
|
|
5986
|
+
response.end("x and y must be a point on the desktop");
|
|
5987
|
+
return;
|
|
5988
|
+
}
|
|
5989
|
+
response.setHeader("content-type", "application/json");
|
|
5990
|
+
void inspectDesktopPoint(x, y).catch(() => null).then((element) => response.end(JSON.stringify(element)));
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5845
5993
|
const requested = url.pathname === "/" ? "stream-index.html" : url.pathname.slice(1);
|
|
5846
5994
|
const path = resolve3(webroot, requested);
|
|
5847
5995
|
if (!path.startsWith(resolve3(webroot) + "/") || !existsSync8(path) || !statSync2(path).isFile()) {
|
package/dist/stream-viewer.js
CHANGED
|
@@ -3,6 +3,43 @@ function isRecord(value) {
|
|
|
3
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
// ../shared/src/urls.ts
|
|
7
|
+
var DEFAULT_WEB_APP_URL = "https://app.replicas.dev";
|
|
8
|
+
var DASHBOARD_PATH = "/dashboard";
|
|
9
|
+
var WEB_APP_PATHS = {
|
|
10
|
+
home: "/",
|
|
11
|
+
onboarding: "/onboarding",
|
|
12
|
+
workspaces: "/workspace",
|
|
13
|
+
environmentSetup: "/workspace/setup",
|
|
14
|
+
automations: "/automations",
|
|
15
|
+
environment: "/environment",
|
|
16
|
+
analytics: "/analytics",
|
|
17
|
+
review: "/review",
|
|
18
|
+
dashboard: DASHBOARD_PATH,
|
|
19
|
+
agents: `${DASHBOARD_PATH}/agents`,
|
|
20
|
+
integrations: `${DASHBOARD_PATH}/integrations`,
|
|
21
|
+
integrationsGithub: `${DASHBOARD_PATH}/integrations/github`,
|
|
22
|
+
integrationsGitlab: `${DASHBOARD_PATH}/integrations/gitlab`,
|
|
23
|
+
integrationsSlack: `${DASHBOARD_PATH}/integrations/slack`,
|
|
24
|
+
settings: `${DASHBOARD_PATH}/settings`,
|
|
25
|
+
billing: `${DASHBOARD_PATH}/billing`,
|
|
26
|
+
members: `${DASHBOARD_PATH}/members`,
|
|
27
|
+
learnings: `${DASHBOARD_PATH}/learnings`,
|
|
28
|
+
"audit-logs": `${DASHBOARD_PATH}/audit-logs`,
|
|
29
|
+
accountAgents: `${DASHBOARD_PATH}/account/agents`,
|
|
30
|
+
accountProfile: `${DASHBOARD_PATH}/account/profile`,
|
|
31
|
+
accountConnections: `${DASHBOARD_PATH}/account/connections`,
|
|
32
|
+
accountIntegrations: `${DASHBOARD_PATH}/account/integrations`,
|
|
33
|
+
accountApiKeys: `${DASHBOARD_PATH}/account/api-keys`,
|
|
34
|
+
accountPreferences: `${DASHBOARD_PATH}/account/preferences`,
|
|
35
|
+
fullscreenWorkspaces: "/workspaces"
|
|
36
|
+
};
|
|
37
|
+
var LEGACY_WEB_APP_PATHS = {
|
|
38
|
+
app: "/app",
|
|
39
|
+
home: "/home",
|
|
40
|
+
dashboardWorkspaces: `${DASHBOARD_PATH}/workspaces`
|
|
41
|
+
};
|
|
42
|
+
|
|
6
43
|
// ../shared/src/desktop-stream.ts
|
|
7
44
|
function isStreamIceServer(value) {
|
|
8
45
|
return isRecord(value) && typeof value.urls === "string" && (value.username === void 0 || typeof value.username === "string") && (value.credential === void 0 || typeof value.credential === "string");
|
|
@@ -50,6 +87,18 @@ var DESKTOP_WEBRTC_FAILURE_REASONS = {
|
|
|
50
87
|
};
|
|
51
88
|
var DESKTOP_QUALITY_MESSAGE = "replicas-desktop-quality";
|
|
52
89
|
var DESKTOP_CONNECTION_MESSAGE = "replicas-desktop-connection";
|
|
90
|
+
var DESKTOP_ANNOTATE_MESSAGE = "replicas-desktop-annotate";
|
|
91
|
+
function isDesktopAnnotateOrigin(origin, viewerHostname) {
|
|
92
|
+
if (origin === new URL(DEFAULT_WEB_APP_URL).origin) return true;
|
|
93
|
+
return viewerHostname.split(".").at(-1) === "localhost" && URL.canParse(origin) && new URL(origin).hostname === "localhost";
|
|
94
|
+
}
|
|
95
|
+
function isDesktopAnnotateRequest(value) {
|
|
96
|
+
return isRecord(value) && value.type === DESKTOP_ANNOTATE_MESSAGE && typeof value.id === "number" && (value.action === "capture" || value.action === "inspect" && Number.isFinite(value.x) && Number.isFinite(value.y));
|
|
97
|
+
}
|
|
98
|
+
var isDesktopRect = (value) => isRecord(value) && ["x", "y", "width", "height"].every((key) => typeof value[key] === "number" && Number.isFinite(value[key]));
|
|
99
|
+
function isDesktopElement(value) {
|
|
100
|
+
return isRecord(value) && isDesktopRect(value.rect) && ["url", "tag", "selector"].every((key) => typeof value[key] === "string") && ["text", "label", "source"].every((key) => value[key] === void 0 || typeof value[key] === "string") && (value.components === void 0 || Array.isArray(value.components) && value.components.every((name) => typeof name === "string"));
|
|
101
|
+
}
|
|
53
102
|
|
|
54
103
|
// src/input-validation.ts
|
|
55
104
|
var finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
@@ -280,6 +329,20 @@ var announceTransport = () => {
|
|
|
280
329
|
if (window.parent === window) return;
|
|
281
330
|
window.parent.postMessage({ type: DESKTOP_TRANSPORT_MESSAGE, transport: transport ?? "connecting", reason: transportReason, path: route.path, codec: route.codec, failure, recovery }, "*");
|
|
282
331
|
};
|
|
332
|
+
addEventListener("message", (event) => {
|
|
333
|
+
if (window.parent === window || event.source !== window.parent || !isDesktopAnnotateOrigin(event.origin, location.hostname) || !isDesktopAnnotateRequest(event.data)) return;
|
|
334
|
+
const request2 = event.data;
|
|
335
|
+
const reply = (result) => window.parent.postMessage({ type: DESKTOP_ANNOTATE_MESSAGE, id: request2.id, ...result }, event.origin);
|
|
336
|
+
if (request2.action === "capture") {
|
|
337
|
+
void fetch("/snapshot", { cache: "no-store" }).then((response) => response.ok ? response.blob() : null).catch(() => null).then((image) => reply({ image }));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
void fetch(`/inspect?x=${Math.round(request2.x)}&y=${Math.round(request2.y)}`).then((response) => response.ok ? response.json() : Promise.resolve(null)).catch(() => null).then((element) => reply({ element: isDesktopElement(element) ? element : null }));
|
|
341
|
+
});
|
|
342
|
+
var parentOrigin = URL.canParse(document.referrer) ? new URL(document.referrer).origin : null;
|
|
343
|
+
if (window.parent !== window && parentOrigin && isDesktopAnnotateOrigin(parentOrigin, location.hostname)) {
|
|
344
|
+
window.parent.postMessage({ type: DESKTOP_ANNOTATE_MESSAGE, ready: true }, parentOrigin);
|
|
345
|
+
}
|
|
283
346
|
var average = (sum, count) => count ? Math.round(sum * 10 / count) / 10 : void 0;
|
|
284
347
|
var reportConnection = (ended) => {
|
|
285
348
|
if (window.parent === window || !config) return;
|