@omercnet/paseo-shared-browser 1.0.1 → 1.0.2-next.179.1
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 +5 -5
- package/index.server.ts +2 -1
- package/package.json +2 -1
- package/scripts/prepare-runtime.mjs +6 -15
- package/scripts/replace-runtime.mjs +15 -0
- package/server/browser.ts +2 -7
- package/server/runtime-owner.ts +6 -4
- package/server/runtime-path.ts +21 -0
package/README.md
CHANGED
|
@@ -77,9 +77,9 @@ paseo plugin ls
|
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
When Paseo acquires the npm package, it runs the `npm run prepare:runtime` build hook automatically. The
|
|
80
|
-
hook installs the pinned browser runtime
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
hook installs the pinned browser runtime, builds both `supervisor.cjs` and `shared-browser-mcp.cjs`
|
|
81
|
+
under a versioned directory in `$PASEO_HOME/plugin-data/shared-browser`, then atomically updates the
|
|
82
|
+
`runtime-current` pointer. Existing processes keep using their immutable runtime during an update.
|
|
83
83
|
|
|
84
84
|
The build requires Node.js 24 or newer and npm on the daemon host. On Linux x64, macOS, and
|
|
85
85
|
Windows, runtime preparation installs and stages the platform's Chrome for Testing distribution. On
|
|
@@ -125,8 +125,8 @@ The plugin recognizes only these deployment overrides:
|
|
|
125
125
|
| Variable | Meaning |
|
|
126
126
|
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
127
127
|
| `PASEO_HOME` | Paseo data root. Defaults to `~/.paseo`; browser runtime, supervisor IPC, and profiles live below `plugin-data/shared-browser`. |
|
|
128
|
-
| `PASEO_SHARED_BROWSER_AGENT_BROWSER_BINARY` | Absolute path to the pinned `agent-browser` executable. Defaults to
|
|
129
|
-
| `PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE` | Absolute path to Chromium. Defaults to
|
|
128
|
+
| `PASEO_SHARED_BROWSER_AGENT_BROWSER_BINARY` | Absolute path to the pinned `agent-browser` executable. Defaults to the active runtime's `node_modules/.bin/agent-browser` (`agent-browser.exe` on Windows). |
|
|
129
|
+
| `PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE` | Absolute path to Chromium. Defaults to the active runtime's `chromium/chrome` (`chrome.exe` on Windows). On Linux ARM64, installation automatically links `/usr/bin/chromium`; use this override for another compatible, non-Snap location. |
|
|
130
130
|
| `PASEO_SHARED_BROWSER_CHROMIUM_ARGS` | Optional Chromium arguments passed through the managed runtime. Intended for host requirements such as `--no-sandbox` in an already-isolated CI runner; do not disable the browser sandbox on a general-purpose host. |
|
|
131
131
|
|
|
132
132
|
User-supplied `AGENT_BROWSER_*` variables are deliberately ignored.
|
package/index.server.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
issueAgentTicket,
|
|
20
20
|
revokeAgentBrowserAccess,
|
|
21
21
|
} from "./server/browser";
|
|
22
|
+
import { resolveBrowserRuntimeRoot } from "./server/runtime-path";
|
|
22
23
|
import {
|
|
23
24
|
acquireControlRpc,
|
|
24
25
|
applyDevicePresetRpc,
|
|
@@ -62,7 +63,7 @@ function paseoHome(): string {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function mcpBundlePath(): string {
|
|
65
|
-
return join(paseoHome(), "
|
|
66
|
+
return join(resolveBrowserRuntimeRoot(paseoHome()), "shared-browser-mcp.cjs");
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export default function contribute(server: PluginServerContext) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omercnet/paseo-shared-browser",
|
|
3
|
-
"version": "1.0.1",
|
|
3
|
+
"version": "1.0.2-next.179.1",
|
|
4
4
|
"description": "One real Chromium session per Paseo workspace, shared live across every connected client.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"browser",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"client",
|
|
30
30
|
"scripts/prepare-dependencies.mjs",
|
|
31
31
|
"scripts/prepare-runtime.mjs",
|
|
32
|
+
"scripts/replace-runtime.mjs",
|
|
32
33
|
"server",
|
|
33
34
|
"shared",
|
|
34
35
|
"paseo-plugin.json"
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { constants } from "node:fs";
|
|
3
|
-
import {
|
|
4
|
-
access,
|
|
5
|
-
chmod,
|
|
6
|
-
cp,
|
|
7
|
-
lstat,
|
|
8
|
-
mkdir,
|
|
9
|
-
readdir,
|
|
10
|
-
rename,
|
|
11
|
-
rm,
|
|
12
|
-
symlink,
|
|
13
|
-
writeFile,
|
|
14
|
-
} from "node:fs/promises";
|
|
4
|
+
import { access, chmod, cp, lstat, mkdir, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
15
5
|
import { createRequire } from "node:module";
|
|
16
6
|
import { arch, homedir, platform, userInfo } from "node:os";
|
|
17
7
|
import { dirname, join, resolve } from "node:path";
|
|
18
8
|
import { fileURLToPath } from "node:url";
|
|
19
9
|
import { promisify } from "node:util";
|
|
20
10
|
import { build } from "esbuild";
|
|
11
|
+
import { replaceRuntime } from "./replace-runtime.mjs";
|
|
21
12
|
|
|
22
13
|
const require = createRequire(import.meta.url);
|
|
23
14
|
|
|
@@ -34,7 +25,7 @@ const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
|
34
25
|
const paseoHome = process.env.PASEO_HOME || join(homedir(), ".paseo");
|
|
35
26
|
const pluginDataRoot = join(paseoHome, "plugin-data", "shared-browser");
|
|
36
27
|
const runtimeRoot = join(pluginDataRoot, "runtime");
|
|
37
|
-
const stagingRoot = join(pluginDataRoot, `.runtime-${
|
|
28
|
+
const stagingRoot = join(pluginDataRoot, `.runtime-${randomUUID()}`);
|
|
38
29
|
const runtimeModules = join(stagingRoot, "node_modules");
|
|
39
30
|
const packagedAgentBrowser = resolveDependencyRoot("agent-browser");
|
|
40
31
|
const runtimeEntry = join(
|
|
@@ -257,6 +248,6 @@ await applyPrivatePermissions(stagingRoot);
|
|
|
257
248
|
if (hostPlatform !== "win32") {
|
|
258
249
|
await validateChromium(await requireExecutable(chromiumEntry, "Staged Chromium executable"));
|
|
259
250
|
}
|
|
260
|
-
await
|
|
251
|
+
await replaceRuntime(stagingRoot, runtimeRoot);
|
|
261
252
|
|
|
262
|
-
console.log(`Prepared immutable Shared Browser runtime assets in ${
|
|
253
|
+
console.log(`Prepared immutable Shared Browser runtime assets in ${stagingRoot}`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { access, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
|
+
|
|
4
|
+
export async function replaceRuntime(stagingRoot, runtimeRoot) {
|
|
5
|
+
await access(stagingRoot);
|
|
6
|
+
const pluginDataRoot = dirname(runtimeRoot);
|
|
7
|
+
const pointer = join(pluginDataRoot, "runtime-current");
|
|
8
|
+
const pendingPointer = join(pluginDataRoot, `.runtime-current-${process.pid}`);
|
|
9
|
+
await writeFile(pendingPointer, `${basename(stagingRoot)}\n`, { mode: 0o600 });
|
|
10
|
+
try {
|
|
11
|
+
await rename(pendingPointer, pointer);
|
|
12
|
+
} finally {
|
|
13
|
+
await rm(pendingPointer, { force: true });
|
|
14
|
+
}
|
|
15
|
+
}
|
package/server/browser.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
resizeBrowserRpc,
|
|
18
18
|
sendBrowserInputRpc,
|
|
19
19
|
} from "../shared/browser";
|
|
20
|
+
import { resolveBrowserRuntimeRoot } from "./runtime-path";
|
|
20
21
|
import type { JsonValue } from "./runtime-protocol";
|
|
21
22
|
import { resolveSupervisorPaths } from "./supervisor";
|
|
22
23
|
import { SupervisorClient } from "./supervisor-client";
|
|
@@ -156,13 +157,7 @@ let productionStart: Promise<RemoteBrowserManager> | null = null;
|
|
|
156
157
|
let productionStopped = false;
|
|
157
158
|
|
|
158
159
|
async function launchSupervisor(): Promise<void> {
|
|
159
|
-
const supervisorPath = join(
|
|
160
|
-
paseoHome(),
|
|
161
|
-
"plugin-data",
|
|
162
|
-
"shared-browser",
|
|
163
|
-
"runtime",
|
|
164
|
-
"supervisor.cjs",
|
|
165
|
-
);
|
|
160
|
+
const supervisorPath = join(resolveBrowserRuntimeRoot(paseoHome()), "supervisor.cjs");
|
|
166
161
|
try {
|
|
167
162
|
await access(supervisorPath);
|
|
168
163
|
} catch {
|
package/server/runtime-owner.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { AgentBrowserRuntime, type BrowserViewport } from "./agent-browser-runtime";
|
|
5
|
+
import { resolveBrowserRuntimeRoot } from "./runtime-path";
|
|
5
6
|
import type { JsonValue } from "./runtime-protocol";
|
|
6
7
|
import type { RuntimeOwner } from "./supervisor";
|
|
7
8
|
|
|
@@ -23,7 +24,9 @@ function paseoHome(): string {
|
|
|
23
24
|
export async function createRuntimeOwner(
|
|
24
25
|
options: RuntimeOwnerOptions = {},
|
|
25
26
|
): Promise<RuntimeOwner<OwnedRuntime>> {
|
|
26
|
-
const
|
|
27
|
+
const home = paseoHome();
|
|
28
|
+
const root = join(home, "plugin-data", "shared-browser");
|
|
29
|
+
const runtimeRoot = resolveBrowserRuntimeRoot(home);
|
|
27
30
|
const ipcDirectory =
|
|
28
31
|
process.platform === "win32"
|
|
29
32
|
? join(root, "ipc")
|
|
@@ -34,15 +37,14 @@ export async function createRuntimeOwner(
|
|
|
34
37
|
const binaryPath =
|
|
35
38
|
process.env.PASEO_SHARED_BROWSER_AGENT_BROWSER_BINARY ??
|
|
36
39
|
join(
|
|
37
|
-
|
|
38
|
-
"runtime",
|
|
40
|
+
runtimeRoot,
|
|
39
41
|
"node_modules",
|
|
40
42
|
".bin",
|
|
41
43
|
process.platform === "win32" ? "agent-browser.exe" : "agent-browser",
|
|
42
44
|
);
|
|
43
45
|
const executablePath =
|
|
44
46
|
process.env.PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE ??
|
|
45
|
-
join(
|
|
47
|
+
join(runtimeRoot, "chromium", process.platform === "win32" ? "chrome.exe" : "chrome");
|
|
46
48
|
return {
|
|
47
49
|
async create(workspaceId) {
|
|
48
50
|
const hash = createHash("sha256").update(workspaceId).digest("hex");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
export function resolveBrowserRuntimeRoot(paseoHome: string): string {
|
|
5
|
+
const pluginDataRoot = join(paseoHome, "plugin-data", "shared-browser");
|
|
6
|
+
let directory: string;
|
|
7
|
+
try {
|
|
8
|
+
directory = readFileSync(join(pluginDataRoot, "runtime-current"), "utf8").trim();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return join(pluginDataRoot, "runtime");
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
if (
|
|
14
|
+
!/^\.runtime-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(
|
|
15
|
+
directory,
|
|
16
|
+
)
|
|
17
|
+
) {
|
|
18
|
+
throw new Error("Shared Browser runtime pointer is invalid");
|
|
19
|
+
}
|
|
20
|
+
return join(pluginDataRoot, directory);
|
|
21
|
+
}
|