openmausbot 0.1.78 → 0.1.80
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/assets/index-Cu8BkIfo.js +305 -0
- package/dist/assets/{index-BqDJqf2C.js → index-D6RZKWks.js} +1 -1
- package/dist/assets/index-tfpeJAIG.css +1 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +11 -5
- package/dist-server/drivers/agents-proxy.js +21 -6
- package/dist-server/enterprise/server/index.js +0 -1
- package/dist-server/index.js +15942 -6859
- package/dist-server/local-computer.js +0 -1
- package/dist-server/mcp-server.js +8 -1
- package/dist-server/openmausbot.js +9303 -786
- package/dist-server/pair-cli.js +9303 -786
- package/dist-server/proxy-paths.js +0 -1
- package/dist-server/server/box.js +98 -41
- package/dist-server/server/browser-engine.js +1 -1
- package/dist-server/server/browser-runtime.js +11 -3
- package/dist-server/server/browser-tool-shape.js +72 -0
- package/dist-server/server/claude-accounts.js +1 -0
- package/dist-server/server/cli-setup.js +1 -1
- package/dist-server/server/composio.js +18 -0
- package/dist-server/server/config.js +16 -4
- package/dist-server/server/container-computer.js +0 -12
- package/dist-server/server/drivers/acp/core.js +4 -19
- package/dist-server/server/drivers/agents-proxy.js +27 -2
- package/dist-server/server/drivers/boxagent.js +48 -4
- package/dist-server/server/drivers/chat-mcp-tools.js +368 -0
- package/dist-server/server/drivers/chat-tool-approval.js +42 -0
- package/dist-server/server/drivers/claude.js +86 -38
- package/dist-server/server/drivers/codex.js +225 -75
- package/dist-server/server/drivers/grok.js +4 -0
- package/dist-server/server/drivers/minimax.js +11 -3
- package/dist-server/server/drivers/openai-chat-protocol.js +92 -0
- package/dist-server/server/drivers/openai-chat.js +332 -88
- package/dist-server/server/drivers/openai-compat.js +4 -0
- package/dist-server/server/drivers/pi.js +1 -9
- package/dist-server/server/harness/registry.js +2 -2
- package/dist-server/server/index.js +267 -50
- package/dist-server/server/managed-desktop.js +205 -0
- package/dist-server/server/model-context-window.js +20 -0
- package/dist-server/server/proxy-paths.js +0 -1
- package/dist-server/server/redact.js +1 -0
- package/dist-server/server/room-handoffs.js +57 -9
- package/dist-server/server/store.js +13 -1
- package/dist-server/server/tts/chatterbox.js +83 -0
- package/dist-server/server/tts/index.js +45 -12
- package/dist-server/server/workspace.js +12 -2
- package/dist-server/shared/ask-question.js +28 -0
- package/dist-server/shared/computer-contention.js +17 -0
- package/dist-server/vps-container-mcp.js +11 -5
- package/enterprise/server/index.js +0 -1
- package/package.json +1 -1
- package/dist/assets/index-DjwAroIZ.js +0 -305
- package/dist/assets/index-Pbb6Ao0s.css +0 -1
- package/dist-server/computer-proxy.js +0 -1196
- package/dist-server/server/computer-proxy.js +0 -1070
- package/dist-server/server/remote-computer.js +0 -170
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
// Shared provisioning and shell contract for the cloud computer's Cua Driver.
|
|
2
|
-
// The box command API is the transport boundary: the daemon stays loopback-only
|
|
3
|
-
// inside the VM and OpenMausBot never exposes another inbound port.
|
|
4
|
-
export const REMOTE_CUA_VERSION = "0.20.0";
|
|
5
|
-
export const REMOTE_CUA_EXECUTABLE = "/opt/ogb/cua-driver";
|
|
6
|
-
export const REMOTE_CUA_SOCKET = "/opt/ogb/run/cua.sock";
|
|
7
|
-
export const REMOTE_CUA_SESSION = "openmausbot";
|
|
8
|
-
export const REMOTE_CDP_HELPER = "/opt/ogb/openmausbot-cdp.mjs";
|
|
9
|
-
const REMOTE_CUA_WHEELS = {
|
|
10
|
-
x86_64: {
|
|
11
|
-
url: "https://files.pythonhosted.org/packages/fa/d7/a43008a328a40c85e7bc706fc20235b9abedc75e28b413817655153157ff/cua_driver-0.20.0-py3-none-manylinux_2_31_x86_64.whl",
|
|
12
|
-
sha256: "f60c35696a37f37ac954935e478ae4754f220856d022036625c9400d72185961",
|
|
13
|
-
},
|
|
14
|
-
aarch64: {
|
|
15
|
-
url: "https://files.pythonhosted.org/packages/94/9d/1c1838b69067e83266c3d2aae02d74eef353a43dc8644884ccf03fe7f933/cua_driver-0.20.0-py3-none-manylinux_2_31_aarch64.whl",
|
|
16
|
-
sha256: "48833bc5e4c60e701fc9eefb57dbac36ec77ef3990f816fbbe85b4e954af2c77",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
const CDP_HELPER_SOURCE = String.raw `const [action, encoded = ""] = process.argv.slice(2);
|
|
20
|
-
const input = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8") || "{}");
|
|
21
|
-
const pages = await fetch("http://127.0.0.1:9222/json/list").then((r) => r.json());
|
|
22
|
-
const page = pages.find((item) => item.type === "page" && item.webSocketDebuggerUrl);
|
|
23
|
-
if (!page) throw new Error("no debuggable browser page");
|
|
24
|
-
if (input.url && page.url !== input.url) throw new Error("page changed; take a new browser snapshot");
|
|
25
|
-
const socket = new WebSocket(page.webSocketDebuggerUrl);
|
|
26
|
-
await new Promise((resolve, reject) => {
|
|
27
|
-
socket.addEventListener("open", resolve, { once: true });
|
|
28
|
-
socket.addEventListener("error", () => reject(new Error("DevTools connection failed")), { once: true });
|
|
29
|
-
});
|
|
30
|
-
let nextId = 0;
|
|
31
|
-
const pending = new Map();
|
|
32
|
-
socket.addEventListener("message", (event) => {
|
|
33
|
-
const message = JSON.parse(String(event.data));
|
|
34
|
-
if (!message.id) return;
|
|
35
|
-
const waiter = pending.get(message.id);
|
|
36
|
-
if (!waiter) return;
|
|
37
|
-
pending.delete(message.id);
|
|
38
|
-
if (message.error) waiter.reject(new Error(message.error.message));
|
|
39
|
-
else waiter.resolve(message.result ?? {});
|
|
40
|
-
});
|
|
41
|
-
const send = (method, params = {}) => new Promise((resolve, reject) => {
|
|
42
|
-
const id = ++nextId;
|
|
43
|
-
pending.set(id, { resolve, reject });
|
|
44
|
-
socket.send(JSON.stringify({ id, method, params }));
|
|
45
|
-
});
|
|
46
|
-
const refId = (value) => {
|
|
47
|
-
const match = /^b(\d+)$/.exec(String(value ?? ""));
|
|
48
|
-
if (!match) throw new Error("invalid or stale browser ref; take a new snapshot");
|
|
49
|
-
return Number(match[1]);
|
|
50
|
-
};
|
|
51
|
-
if (action === "snapshot") {
|
|
52
|
-
await send("Accessibility.enable");
|
|
53
|
-
const { nodes = [] } = await send("Accessibility.getFullAXTree", { depth: 14 });
|
|
54
|
-
const useful = new Set(["button", "checkbox", "combobox", "heading", "link", "menuitem", "radio", "searchbox", "slider", "spinbutton", "switch", "tab", "textbox"]);
|
|
55
|
-
const elements = [];
|
|
56
|
-
for (const node of nodes) {
|
|
57
|
-
const role = String(node.role?.value ?? "").toLowerCase();
|
|
58
|
-
const name = String(node.name?.value ?? "").replace(/\s+/g, " ").trim().slice(0, 180);
|
|
59
|
-
const backend = Number(node.backendDOMNodeId ?? 0);
|
|
60
|
-
if (!backend || !useful.has(role) || (!name && role !== "textbox" && role !== "searchbox")) continue;
|
|
61
|
-
const disabled = node.properties?.some((property) => property.name === "disabled" && property.value?.value === true) ?? false;
|
|
62
|
-
elements.push({ ref: "b" + backend, role, name: name || "unnamed", disabled });
|
|
63
|
-
if (elements.length >= 250) break;
|
|
64
|
-
}
|
|
65
|
-
process.stdout.write(JSON.stringify({ title: String(page.title ?? "").slice(0, 200), url: page.url, elements }));
|
|
66
|
-
} else if (action === "click") {
|
|
67
|
-
const backendNodeId = refId(input.ref);
|
|
68
|
-
const { model } = await send("DOM.getBoxModel", { backendNodeId });
|
|
69
|
-
const quad = model?.border ?? model?.content;
|
|
70
|
-
if (!Array.isArray(quad) || quad.length < 8) throw new Error("element is not visible; take a new snapshot");
|
|
71
|
-
const x = (quad[0] + quad[2] + quad[4] + quad[6]) / 4;
|
|
72
|
-
const y = (quad[1] + quad[3] + quad[5] + quad[7]) / 4;
|
|
73
|
-
await send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
74
|
-
await send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 });
|
|
75
|
-
process.stdout.write(JSON.stringify({ ok: true, ref: input.ref }));
|
|
76
|
-
} else if (action === "fill") {
|
|
77
|
-
const backendNodeId = refId(input.ref);
|
|
78
|
-
await send("DOM.focus", { backendNodeId });
|
|
79
|
-
await send("Input.dispatchKeyEvent", { type: "keyDown", key: "a", code: "KeyA", modifiers: 2 });
|
|
80
|
-
await send("Input.dispatchKeyEvent", { type: "keyUp", key: "a", code: "KeyA", modifiers: 2 });
|
|
81
|
-
await send("Input.dispatchKeyEvent", { type: "keyDown", key: "Backspace", code: "Backspace" });
|
|
82
|
-
await send("Input.dispatchKeyEvent", { type: "keyUp", key: "Backspace", code: "Backspace" });
|
|
83
|
-
await send("Input.insertText", { text: String(input.text ?? "") });
|
|
84
|
-
process.stdout.write(JSON.stringify({ ok: true, ref: input.ref }));
|
|
85
|
-
} else {
|
|
86
|
-
throw new Error("unknown browser action");
|
|
87
|
-
}
|
|
88
|
-
socket.close();`;
|
|
89
|
-
const shellQuote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
|
|
90
|
-
export const MAX_REMOTE_COMMAND_LENGTH = 4_000;
|
|
91
|
-
/** Run a user- or model-supplied command without inheriting provider or
|
|
92
|
-
* account credentials from an older box image. Keep this shared by the bot
|
|
93
|
-
* tool and the owner's Computer-panel console so the two boundaries cannot
|
|
94
|
-
* drift apart. */
|
|
95
|
-
export function isolatedRemoteCommand(command) {
|
|
96
|
-
return [
|
|
97
|
-
"exec env -i",
|
|
98
|
-
'HOME="$HOME"',
|
|
99
|
-
'USER="${USER:-$(id -un)}"',
|
|
100
|
-
'LOGNAME="${LOGNAME:-${USER:-$(id -un)}}"',
|
|
101
|
-
'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"',
|
|
102
|
-
'DISPLAY="${DISPLAY:-:0}"',
|
|
103
|
-
'XAUTHORITY="${XAUTHORITY:-$HOME/.Xauthority}"',
|
|
104
|
-
'XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"',
|
|
105
|
-
'DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-}"',
|
|
106
|
-
"/bin/bash -c",
|
|
107
|
-
shellQuote(command),
|
|
108
|
-
].join(" ");
|
|
109
|
-
}
|
|
110
|
-
/** Start the already-installed daemon after a box resume. This is cheap when
|
|
111
|
-
* it is healthy and intentionally does not install anything on the hot path. */
|
|
112
|
-
export function ensureRemoteCuaCommand() {
|
|
113
|
-
return [
|
|
114
|
-
`if [ -x ${REMOTE_CUA_EXECUTABLE} ]; then`,
|
|
115
|
-
` mkdir -p ${REMOTE_CUA_SOCKET.slice(0, REMOTE_CUA_SOCKET.lastIndexOf("/"))}`,
|
|
116
|
-
` if ! ${REMOTE_CUA_EXECUTABLE} status --socket ${REMOTE_CUA_SOCKET} >/dev/null 2>&1; then`,
|
|
117
|
-
` rm -f ${REMOTE_CUA_SOCKET}`,
|
|
118
|
-
' display=${DISPLAY:-$(find /tmp/.X11-unix -maxdepth 1 -name "X*" -printf ":%f\\n" 2>/dev/null | sed "s/:X/:/" | head -1)}',
|
|
119
|
-
' display=${display:-:0}',
|
|
120
|
-
` nohup env HOME="$HOME" DISPLAY="$display" CUA_DRIVER_INSTALL_CHANNEL=python_package CUA_DRIVER_RS_TELEMETRY_ENABLED=0 ${REMOTE_CUA_EXECUTABLE} serve --socket ${REMOTE_CUA_SOCKET} --permission-mode standard > /tmp/ogb-cua-driver.log 2>&1 &`,
|
|
121
|
-
` for i in 1 2 3 4 5 6 7 8 9 10; do ${REMOTE_CUA_EXECUTABLE} status --socket ${REMOTE_CUA_SOCKET} >/dev/null 2>&1 && break; sleep 0.2; done`,
|
|
122
|
-
" fi",
|
|
123
|
-
"fi",
|
|
124
|
-
].join("\n");
|
|
125
|
-
}
|
|
126
|
-
/** Idempotent setup. The exact wheel is verified before its bundled native
|
|
127
|
-
* executable is installed; installation remains asynchronous so first-time
|
|
128
|
-
* provisioning does not block the desktop for several minutes. */
|
|
129
|
-
export function remoteComputerBootstrapCommand(botName) {
|
|
130
|
-
const helper = Buffer.from(CDP_HELPER_SOURCE).toString("base64");
|
|
131
|
-
const installer = [
|
|
132
|
-
"set -eu",
|
|
133
|
-
"trap 'rm -f /tmp/ogb-cua-installing' EXIT",
|
|
134
|
-
"sudo mkdir -p /opt/ogb/run",
|
|
135
|
-
'sudo chown -R "$(id -u):$(id -g)" /opt/ogb',
|
|
136
|
-
'arch="$(uname -m)"',
|
|
137
|
-
`case "$arch" in x86_64) url=${shellQuote(REMOTE_CUA_WHEELS.x86_64.url)}; sha=${REMOTE_CUA_WHEELS.x86_64.sha256} ;; aarch64|arm64) url=${shellQuote(REMOTE_CUA_WHEELS.aarch64.url)}; sha=${REMOTE_CUA_WHEELS.aarch64.sha256} ;; *) echo "unsupported architecture: $arch" >&2; exit 1 ;; esac`,
|
|
138
|
-
'wheel="/tmp/cua-driver-${sha}.whl"',
|
|
139
|
-
'curl -fsSL "$url" -o "$wheel"',
|
|
140
|
-
'echo "$sha $wheel" | sha256sum -c -',
|
|
141
|
-
'python3 - "$wheel" <<\'PY\'\nimport os, sys, zipfile\nwheel = sys.argv[1]\nwith zipfile.ZipFile(wheel) as archive:\n names = [name for name in archive.namelist() if name == "cua_driver/bin/cua-driver" or name.endswith("/cua_driver/bin/cua-driver")]\n if len(names) != 1:\n raise SystemExit("cua-driver executable missing from wheel")\n with archive.open(names[0]) as source, open("/opt/ogb/cua-driver", "wb") as target:\n target.write(source.read())\nos.chmod("/opt/ogb/cua-driver", 0o755)\nPY',
|
|
142
|
-
`test "$(${REMOTE_CUA_EXECUTABLE} --version)" = "cua-driver ${REMOTE_CUA_VERSION}"`,
|
|
143
|
-
`touch /opt/ogb/cua-${REMOTE_CUA_VERSION}-ready`,
|
|
144
|
-
'rm -f "$wheel"',
|
|
145
|
-
].join("\n");
|
|
146
|
-
// The display name is untrusted. Encode the banner before composing the
|
|
147
|
-
// nested tmux shell so substitutions/backticks can never become syntax.
|
|
148
|
-
const banner = Buffer.from(` ▦ ${botName}'s computer — OpenMausBot`).toString("base64");
|
|
149
|
-
const tmuxSessionCommand = [
|
|
150
|
-
"echo",
|
|
151
|
-
`printf %s ${shellQuote(banner)} | base64 -d`,
|
|
152
|
-
"echo",
|
|
153
|
-
"exec bash -i",
|
|
154
|
-
].join("; ");
|
|
155
|
-
return [
|
|
156
|
-
"if ! command -v xdotool >/dev/null || ! command -v convert >/dev/null || ! command -v curl >/dev/null || ! command -v python3 >/dev/null; then sudo apt-get update -qq || true; sudo apt-get install -y -qq ca-certificates curl python3 gnome-screenshot xclip wmctrl xdotool imagemagick scrot >/dev/null 2>&1 || true; fi",
|
|
157
|
-
"sudo mkdir -p /opt/ogb/run",
|
|
158
|
-
`printf %s ${shellQuote(helper)} | base64 -d | sudo tee ${REMOTE_CDP_HELPER} >/dev/null`,
|
|
159
|
-
`sudo chmod 0755 ${REMOTE_CDP_HELPER}`,
|
|
160
|
-
'pkill -f "^/opt/ogb/venv/bin/python -m computer_server( |$)" >/dev/null 2>&1 || true',
|
|
161
|
-
`[ -f /opt/ogb/cua-${REMOTE_CUA_VERSION}-ready ] || [ -f /tmp/ogb-cua-installing ] || { touch /tmp/ogb-cua-installing; nohup bash -c ${shellQuote(installer)} > /tmp/ogb-cua-install.log 2>&1 & }`,
|
|
162
|
-
ensureRemoteCuaCommand(),
|
|
163
|
-
`tmux has-session -t work 2>/dev/null || tmux new-session -d -s work ${shellQuote(tmuxSessionCommand)}`,
|
|
164
|
-
"echo bootstrapped",
|
|
165
|
-
].join("\n");
|
|
166
|
-
}
|
|
167
|
-
export function semanticBrowserCommand(action, input) {
|
|
168
|
-
const encoded = Buffer.from(JSON.stringify(input ?? {})).toString("base64url");
|
|
169
|
-
return `node ${REMOTE_CDP_HELPER} ${action} ${shellQuote(encoded)}`;
|
|
170
|
-
}
|