@rynx-ai/daemon 0.1.11-beta.2 → 0.1.11-beta.3
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/bundled-plugins/plugins/lark/dist/runtime.js +2 -5
- package/bundled-plugins/plugins/lark/dist/settings.js +2 -2
- package/bundled-plugins/plugins/lark/package.json +1 -1
- package/dist/browser-artifact-management.d.ts +4 -1
- package/dist/browser-artifact-management.js +18 -10
- package/dist/browser-artifacts.d.ts +1 -0
- package/dist/browser-artifacts.js +1 -0
- package/dist/chrome-for-testing-runtime.d.ts +27 -0
- package/dist/chrome-for-testing-runtime.js +193 -0
- package/dist/chrome-for-testing-store.d.ts +2 -0
- package/dist/chrome-for-testing-store.js +9 -0
- package/dist/daemon-server.d.ts +4 -1
- package/dist/daemon-server.js +137 -32
- package/dist/db.js +2 -0
- package/dist/entry-path.d.ts +3 -0
- package/dist/entry-path.js +12 -0
- package/dist/index-daemon.js +3 -87
- package/dist/lifecycle.d.ts +12 -0
- package/dist/lifecycle.js +16 -0
- package/dist/maintenance-lease.d.ts +39 -0
- package/dist/maintenance-lease.js +250 -0
- package/dist/plugin-host-rpc.d.ts +19 -1
- package/dist/plugin-host-rpc.js +163 -23
- package/dist/plugin-installer.js +59 -0
- package/dist/plugin-supervisor.d.ts +5 -0
- package/dist/plugin-supervisor.js +218 -29
- package/dist/pm2.d.ts +11 -2
- package/dist/pm2.js +116 -19
- package/dist/process.d.ts +12 -0
- package/dist/process.js +91 -0
- package/dist/session-launch-operations.d.ts +10 -1
- package/dist/session-launch-operations.js +15 -6
- package/dist/setup-service.d.ts +20 -0
- package/dist/setup-service.js +38 -0
- package/package.json +33 -20
- package/dist/browser-cli-args.d.ts +0 -20
- package/dist/browser-cli-args.js +0 -100
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -550
- package/dist/control-client.d.ts +0 -122
- package/dist/control-client.js +0 -855
- package/dist/control-endpoint.d.ts +0 -14
- package/dist/control-endpoint.js +0 -124
- package/dist/desktop-browser-host-client.d.ts +0 -35
- package/dist/desktop-browser-host-client.js +0 -415
- package/dist/setup.d.ts +0 -20
- package/dist/setup.js +0 -386
- package/dist/update.d.ts +0 -25
- package/dist/update.js +0 -133
|
@@ -126032,9 +126032,6 @@ function isAgentRuntimeId(value) {
|
|
|
126032
126032
|
return value === "codex" || value === "traex" || value === "claude";
|
|
126033
126033
|
}
|
|
126034
126034
|
function normalizeRuntimeId(value) {
|
|
126035
|
-
if (value === "traecli") {
|
|
126036
|
-
return "traex";
|
|
126037
|
-
}
|
|
126038
126035
|
return isAgentRuntimeId(value) ? value : void 0;
|
|
126039
126036
|
}
|
|
126040
126037
|
var RUNTIME_PROFILES = {
|
|
@@ -126100,7 +126097,7 @@ var envSchema = external_exports.object({
|
|
|
126100
126097
|
* `/runtime` card. `codex` keeps the legacy behaviour; `traex` targets the
|
|
126101
126098
|
* ByteDance Codex fork. Per-conversation overrides are stored separately.
|
|
126102
126099
|
*/
|
|
126103
|
-
|
|
126100
|
+
DEFAULT_RUNTIME: external_exports.enum(["codex", "traex", "claude"]).default("codex"),
|
|
126104
126101
|
/**
|
|
126105
126102
|
* Default declarative agent (a spec under `~/.rynx/agents/<name>.json`) for
|
|
126106
126103
|
* conversations that haven't selected one via `/agent`. Empty ⇒ no default;
|
|
@@ -126352,7 +126349,7 @@ var CHROME_INSPECTION_ERROR_MAX_BYTES = 4 * 1024;
|
|
|
126352
126349
|
import path from "node:path";
|
|
126353
126350
|
var SESSION_EXECUTION_SNAPSHOT_VERSION = 1;
|
|
126354
126351
|
var nonEmptyString = external_exports.string().trim().min(1);
|
|
126355
|
-
var absolutePath =
|
|
126352
|
+
var absolutePath = external_exports.string().min(1).refine((value) => Boolean(value.trim()) && path.isAbsolute(value) && path.normalize(value) === value, "path must be normalized and absolute");
|
|
126356
126353
|
var sessionWorkspaceSnapshotSchema = external_exports.object({
|
|
126357
126354
|
cwd: absolutePath,
|
|
126358
126355
|
allowedDirs: external_exports.array(absolutePath).min(1)
|
|
@@ -126033,7 +126033,7 @@ var envSchema = external_exports.object({
|
|
|
126033
126033
|
* `/runtime` card. `codex` keeps the legacy behaviour; `traex` targets the
|
|
126034
126034
|
* ByteDance Codex fork. Per-conversation overrides are stored separately.
|
|
126035
126035
|
*/
|
|
126036
|
-
|
|
126036
|
+
DEFAULT_RUNTIME: external_exports.enum(["codex", "traex", "claude"]).default("codex"),
|
|
126037
126037
|
/**
|
|
126038
126038
|
* Default declarative agent (a spec under `~/.rynx/agents/<name>.json`) for
|
|
126039
126039
|
* conversations that haven't selected one via `/agent`. Empty ⇒ no default;
|
|
@@ -126217,7 +126217,7 @@ var CHROME_INSPECTION_ERROR_MAX_BYTES = 4 * 1024;
|
|
|
126217
126217
|
import path from "node:path";
|
|
126218
126218
|
var SESSION_EXECUTION_SNAPSHOT_VERSION = 1;
|
|
126219
126219
|
var nonEmptyString = external_exports.string().trim().min(1);
|
|
126220
|
-
var absolutePath =
|
|
126220
|
+
var absolutePath = external_exports.string().min(1).refine((value) => Boolean(value.trim()) && path.isAbsolute(value) && path.normalize(value) === value, "path must be normalized and absolute");
|
|
126221
126221
|
var sessionWorkspaceSnapshotSchema = external_exports.object({
|
|
126222
126222
|
cwd: absolutePath,
|
|
126223
126223
|
allowedDirs: external_exports.array(absolutePath).min(1)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { DaemonBrowserArtifactCleanResult, DaemonBrowserArtifactInstallInput, DaemonBrowserArtifactInstallResult, DaemonBrowserArtifactUpdateInput, DaemonBrowserArtifactVersionResult } from "@rynx-ai/protocol/control";
|
|
2
2
|
import { type ChromeForTestingReleaseSelector, type ResolvedChromeForTestingRelease } from "./chrome-for-testing-release-resolver.js";
|
|
3
|
-
import { type ChromeForTestingArtifactStore } from "./chrome-for-testing-store.js";
|
|
3
|
+
import { type InstalledChromeForTestingBuild, type ChromeForTestingArtifactStore } from "./chrome-for-testing-store.js";
|
|
4
|
+
import { type EnsureChromeForTestingRuntimeOptions } from "./chrome-for-testing-runtime.js";
|
|
4
5
|
export interface BrowserArtifactManagementContext {
|
|
5
6
|
signal?: AbortSignal;
|
|
7
|
+
onProgress?: (message: string) => void;
|
|
6
8
|
}
|
|
7
9
|
export interface BrowserArtifactManagementService {
|
|
8
10
|
install(input: DaemonBrowserArtifactInstallInput, context?: BrowserArtifactManagementContext): Promise<DaemonBrowserArtifactInstallResult>;
|
|
@@ -15,6 +17,7 @@ export interface BrowserArtifactManagementServiceOptions {
|
|
|
15
17
|
signal?: AbortSignal;
|
|
16
18
|
}) => Promise<ResolvedChromeForTestingRelease>;
|
|
17
19
|
createStore?: () => ChromeForTestingArtifactStore;
|
|
20
|
+
ensureRuntime?: (build: InstalledChromeForTestingBuild, options?: EnsureChromeForTestingRuntimeOptions) => Promise<void>;
|
|
18
21
|
}
|
|
19
22
|
/** Daemon-owned Browser artifact operations exposed through local management. */
|
|
20
23
|
export declare function createBrowserArtifactManagementService(options?: BrowserArtifactManagementServiceOptions): BrowserArtifactManagementService;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveChromeForTestingRelease, } from "./chrome-for-testing-release-resolver.js";
|
|
2
2
|
import { createChromeForTestingArtifactStore, } from "./chrome-for-testing-store.js";
|
|
3
|
+
import { ensureChromeForTestingRuntime, } from "./chrome-for-testing-runtime.js";
|
|
3
4
|
const MAX_PROGRESS_MESSAGES = 64;
|
|
4
5
|
const MAX_PROGRESS_MESSAGE_BYTES = 2 * 1024;
|
|
5
6
|
const MAX_PROGRESS_TOTAL_BYTES = 32 * 1024;
|
|
@@ -7,6 +8,7 @@ const MAX_PROGRESS_TOTAL_BYTES = 32 * 1024;
|
|
|
7
8
|
export function createBrowserArtifactManagementService(options = {}) {
|
|
8
9
|
const resolveRelease = options.resolveRelease ?? resolveChromeForTestingRelease;
|
|
9
10
|
const createStore = options.createStore ?? createChromeForTestingArtifactStore;
|
|
11
|
+
const ensureRuntime = options.ensureRuntime ?? ensureChromeForTestingRuntime;
|
|
10
12
|
let store;
|
|
11
13
|
const artifactStore = () => store ??= createStore();
|
|
12
14
|
const install = async (input, context = {}) => {
|
|
@@ -19,18 +21,24 @@ export function createBrowserArtifactManagementService(options = {}) {
|
|
|
19
21
|
const resolved = await resolveRelease(selector, { signal: context.signal });
|
|
20
22
|
const messages = [];
|
|
21
23
|
let messageBytes = 0;
|
|
24
|
+
const onProgress = (message) => {
|
|
25
|
+
context.onProgress?.(message);
|
|
26
|
+
if (messages.length >= MAX_PROGRESS_MESSAGES)
|
|
27
|
+
return;
|
|
28
|
+
const bounded = boundedUtf8(message, MAX_PROGRESS_MESSAGE_BYTES);
|
|
29
|
+
const bytes = Buffer.byteLength(bounded, "utf8");
|
|
30
|
+
if (messageBytes + bytes > MAX_PROGRESS_TOTAL_BYTES)
|
|
31
|
+
return;
|
|
32
|
+
messageBytes += bytes;
|
|
33
|
+
messages.push(bounded);
|
|
34
|
+
};
|
|
22
35
|
const installed = await artifactStore().installResolved(resolved, {
|
|
23
36
|
signal: context.signal,
|
|
24
|
-
onProgress
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (messageBytes + bytes > MAX_PROGRESS_TOTAL_BYTES)
|
|
30
|
-
return;
|
|
31
|
-
messageBytes += bytes;
|
|
32
|
-
messages.push(bounded);
|
|
33
|
-
},
|
|
37
|
+
onProgress,
|
|
38
|
+
verifyBeforeActivate: (build) => ensureRuntime(build, {
|
|
39
|
+
signal: context.signal,
|
|
40
|
+
onProgress,
|
|
41
|
+
}),
|
|
34
42
|
});
|
|
35
43
|
return { resolved, installed, messages };
|
|
36
44
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createBrowserArtifactManagementService, type BrowserArtifactManagementContext, type BrowserArtifactManagementService, type BrowserArtifactManagementServiceOptions, } from "./browser-artifact-management.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createBrowserArtifactManagementService, } from "./browser-artifact-management.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { InstalledChromeForTestingBuild } from "./chrome-for-testing-store.js";
|
|
2
|
+
export interface BrowserRuntimeCommandResult {
|
|
3
|
+
exitCode: number | null;
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
errorCode?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BrowserRuntimeCommandOptions {
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
timeoutMs: number;
|
|
11
|
+
}
|
|
12
|
+
export type BrowserRuntimeCommandRunner = (command: string, args: readonly string[], options: BrowserRuntimeCommandOptions) => Promise<BrowserRuntimeCommandResult>;
|
|
13
|
+
export interface EnsureChromeForTestingRuntimeOptions {
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
onProgress?: (message: string) => void;
|
|
16
|
+
platform?: string;
|
|
17
|
+
getuid?: () => number | undefined;
|
|
18
|
+
findSystemExecutable?: (name: string) => Promise<string | undefined>;
|
|
19
|
+
runCommand?: BrowserRuntimeCommandRunner;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Verifies that a managed Chrome build can start. On Linux, known missing
|
|
23
|
+
* shared libraries are installed with a fixed package allowlist before a
|
|
24
|
+
* second probe; arbitrary output from ldd is never passed to a shell.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ensureChromeForTestingRuntime(build: InstalledChromeForTestingBuild, options?: EnsureChromeForTestingRuntimeOptions): Promise<void>;
|
|
27
|
+
export declare function parseMissingSharedLibraries(output: string): string[];
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
const PROBE_TIMEOUT_MS = 10_000;
|
|
5
|
+
const INSTALL_TIMEOUT_MS = 5 * 60_000;
|
|
6
|
+
const MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
7
|
+
const SYSTEM_PACKAGES = {
|
|
8
|
+
apt: {
|
|
9
|
+
"libasound.so.2": "libasound2",
|
|
10
|
+
"libatk-1.0.so.0": "libatk1.0-0",
|
|
11
|
+
"libatk-bridge-2.0.so.0": "libatk-bridge2.0-0",
|
|
12
|
+
"libatspi.so.0": "libatspi2.0-0",
|
|
13
|
+
"libcairo.so.2": "libcairo2",
|
|
14
|
+
"libcups.so.2": "libcups2",
|
|
15
|
+
"libdbus-1.so.3": "libdbus-1-3",
|
|
16
|
+
"libdrm.so.2": "libdrm2",
|
|
17
|
+
"libexpat.so.1": "libexpat1",
|
|
18
|
+
"libfontconfig.so.1": "libfontconfig1",
|
|
19
|
+
"libfreetype.so.6": "libfreetype6",
|
|
20
|
+
"libgbm.so.1": "libgbm1",
|
|
21
|
+
"libglib-2.0.so.0": "libglib2.0-0",
|
|
22
|
+
"libgobject-2.0.so.0": "libglib2.0-0",
|
|
23
|
+
"libgtk-3.so.0": "libgtk-3-0",
|
|
24
|
+
"libnspr4.so": "libnspr4",
|
|
25
|
+
"libnss3.so": "libnss3",
|
|
26
|
+
"libpango-1.0.so.0": "libpango-1.0-0",
|
|
27
|
+
"libX11.so.6": "libx11-6",
|
|
28
|
+
"libxcb.so.1": "libxcb1",
|
|
29
|
+
"libXcomposite.so.1": "libxcomposite1",
|
|
30
|
+
"libXdamage.so.1": "libxdamage1",
|
|
31
|
+
"libXext.so.6": "libxext6",
|
|
32
|
+
"libXfixes.so.3": "libxfixes3",
|
|
33
|
+
"libxkbcommon.so.0": "libxkbcommon0",
|
|
34
|
+
"libXrandr.so.2": "libxrandr2",
|
|
35
|
+
},
|
|
36
|
+
rpm: {
|
|
37
|
+
"libasound.so.2": "alsa-lib",
|
|
38
|
+
"libatk-1.0.so.0": "atk",
|
|
39
|
+
"libatk-bridge-2.0.so.0": "at-spi2-atk",
|
|
40
|
+
"libatspi.so.0": "at-spi2-core",
|
|
41
|
+
"libcairo.so.2": "cairo",
|
|
42
|
+
"libcups.so.2": "cups-libs",
|
|
43
|
+
"libdbus-1.so.3": "dbus-libs",
|
|
44
|
+
"libdrm.so.2": "libdrm",
|
|
45
|
+
"libexpat.so.1": "expat",
|
|
46
|
+
"libfontconfig.so.1": "fontconfig",
|
|
47
|
+
"libfreetype.so.6": "freetype",
|
|
48
|
+
"libgbm.so.1": "mesa-libgbm",
|
|
49
|
+
"libglib-2.0.so.0": "glib2",
|
|
50
|
+
"libgobject-2.0.so.0": "glib2",
|
|
51
|
+
"libgtk-3.so.0": "gtk3",
|
|
52
|
+
"libnspr4.so": "nspr",
|
|
53
|
+
"libnss3.so": "nss",
|
|
54
|
+
"libpango-1.0.so.0": "pango",
|
|
55
|
+
"libX11.so.6": "libX11",
|
|
56
|
+
"libxcb.so.1": "libxcb",
|
|
57
|
+
"libXcomposite.so.1": "libXcomposite",
|
|
58
|
+
"libXdamage.so.1": "libXdamage",
|
|
59
|
+
"libXext.so.6": "libXext",
|
|
60
|
+
"libXfixes.so.3": "libXfixes",
|
|
61
|
+
"libxkbcommon.so.0": "libxkbcommon",
|
|
62
|
+
"libXrandr.so.2": "libXrandr",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Verifies that a managed Chrome build can start. On Linux, known missing
|
|
67
|
+
* shared libraries are installed with a fixed package allowlist before a
|
|
68
|
+
* second probe; arbitrary output from ldd is never passed to a shell.
|
|
69
|
+
*/
|
|
70
|
+
export async function ensureChromeForTestingRuntime(build, options = {}) {
|
|
71
|
+
const runCommand = options.runCommand ?? runBrowserRuntimeCommand;
|
|
72
|
+
const findSystemExecutable = options.findSystemExecutable ?? findSystemCommand;
|
|
73
|
+
const run = async (command, args, timeoutMs = PROBE_TIMEOUT_MS) => {
|
|
74
|
+
options.signal?.throwIfAborted();
|
|
75
|
+
const result = await runCommand(command, args, { signal: options.signal, timeoutMs });
|
|
76
|
+
options.signal?.throwIfAborted();
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
const initialProbe = await run(build.executablePath, ["--version"]);
|
|
80
|
+
if (initialProbe.exitCode === 0) {
|
|
81
|
+
options.onProgress?.(`verified Chrome for Testing ${build.version} can start`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if ((options.platform ?? process.platform) !== "linux") {
|
|
85
|
+
throw browserLaunchError(build, initialProbe);
|
|
86
|
+
}
|
|
87
|
+
const ldd = await findSystemExecutable("ldd");
|
|
88
|
+
if (!ldd) {
|
|
89
|
+
throw new Error(`${browserLaunchError(build, initialProbe).message}; ldd is unavailable`);
|
|
90
|
+
}
|
|
91
|
+
const dependencyCheck = await run(ldd, [build.executablePath]);
|
|
92
|
+
const missingLibraries = parseMissingSharedLibraries(`${dependencyCheck.stdout}\n${dependencyCheck.stderr}`);
|
|
93
|
+
if (missingLibraries.length === 0)
|
|
94
|
+
throw browserLaunchError(build, initialProbe);
|
|
95
|
+
const packageManager = await resolvePackageManager(findSystemExecutable);
|
|
96
|
+
if (!packageManager) {
|
|
97
|
+
throw new Error(`Chrome for Testing is missing ${missingLibraries.join(", ")}, ` +
|
|
98
|
+
"but no supported system package manager (apt-get, dnf, or yum) is available");
|
|
99
|
+
}
|
|
100
|
+
const packages = packagesForLibraries(packageManager.family, missingLibraries);
|
|
101
|
+
const installArgs = packageManager.family === "apt"
|
|
102
|
+
? ["install", "-y", "--no-install-recommends", ...packages]
|
|
103
|
+
: ["install", "-y", ...packages];
|
|
104
|
+
let command = packageManager.path;
|
|
105
|
+
let args = installArgs;
|
|
106
|
+
const getuid = options.getuid ?? (() => process.getuid?.());
|
|
107
|
+
if (getuid() !== 0) {
|
|
108
|
+
const sudo = await findSystemExecutable("sudo");
|
|
109
|
+
if (!sudo || (await run(sudo, ["-n", "true"])).exitCode !== 0) {
|
|
110
|
+
throw new Error(`Chrome for Testing is missing ${missingLibraries.join(", ")}. ` +
|
|
111
|
+
`Install these packages as an administrator and retry: ${packages.join(" ")}`);
|
|
112
|
+
}
|
|
113
|
+
command = sudo;
|
|
114
|
+
args = ["-n", packageManager.path, ...installArgs];
|
|
115
|
+
}
|
|
116
|
+
options.onProgress?.(`installing Chrome for Testing system dependencies: ${packages.join(" ")}`);
|
|
117
|
+
const installation = await run(command, args, INSTALL_TIMEOUT_MS);
|
|
118
|
+
if (installation.exitCode !== 0) {
|
|
119
|
+
throw new Error(`failed to install Chrome for Testing system dependencies (${packages.join(" ")}): ` +
|
|
120
|
+
commandFailure(installation));
|
|
121
|
+
}
|
|
122
|
+
const finalProbe = await run(build.executablePath, ["--version"]);
|
|
123
|
+
if (finalProbe.exitCode !== 0)
|
|
124
|
+
throw browserLaunchError(build, finalProbe);
|
|
125
|
+
options.onProgress?.(`verified Chrome for Testing ${build.version} can start`);
|
|
126
|
+
}
|
|
127
|
+
export function parseMissingSharedLibraries(output) {
|
|
128
|
+
const libraries = new Set();
|
|
129
|
+
for (const line of output.split(/\r?\n/u)) {
|
|
130
|
+
const match = /^\s*(\S+)\s+=>\s+not found\s*$/u.exec(line);
|
|
131
|
+
if (match?.[1])
|
|
132
|
+
libraries.add(match[1]);
|
|
133
|
+
}
|
|
134
|
+
return [...libraries].sort();
|
|
135
|
+
}
|
|
136
|
+
function packagesForLibraries(family, libraries) {
|
|
137
|
+
const mapping = SYSTEM_PACKAGES[family];
|
|
138
|
+
const unsupported = libraries.filter((library) => !mapping[library]);
|
|
139
|
+
if (unsupported.length > 0) {
|
|
140
|
+
throw new Error(`Chrome for Testing is missing unsupported system libraries: ${unsupported.join(", ")}`);
|
|
141
|
+
}
|
|
142
|
+
return [...new Set(libraries.map((library) => mapping[library]))].sort();
|
|
143
|
+
}
|
|
144
|
+
async function resolvePackageManager(findExecutable) {
|
|
145
|
+
const apt = await findExecutable("apt-get");
|
|
146
|
+
if (apt)
|
|
147
|
+
return { family: "apt", path: apt };
|
|
148
|
+
const dnf = await findExecutable("dnf");
|
|
149
|
+
if (dnf)
|
|
150
|
+
return { family: "rpm", path: dnf };
|
|
151
|
+
const yum = await findExecutable("yum");
|
|
152
|
+
return yum ? { family: "rpm", path: yum } : undefined;
|
|
153
|
+
}
|
|
154
|
+
async function findSystemCommand(name) {
|
|
155
|
+
for (const directory of ["/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
|
|
156
|
+
const candidate = `${directory}/${name}`;
|
|
157
|
+
try {
|
|
158
|
+
await access(candidate, constants.X_OK);
|
|
159
|
+
return candidate;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Try the next standard system directory.
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
function runBrowserRuntimeCommand(command, args, options) {
|
|
168
|
+
return new Promise((resolveResult) => {
|
|
169
|
+
execFile(command, [...args], {
|
|
170
|
+
encoding: "utf8",
|
|
171
|
+
env: { ...process.env, LC_ALL: "C" },
|
|
172
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
173
|
+
signal: options.signal,
|
|
174
|
+
timeout: options.timeoutMs,
|
|
175
|
+
}, (error, stdout, stderr) => {
|
|
176
|
+
resolveResult({
|
|
177
|
+
exitCode: error
|
|
178
|
+
? typeof error.code === "number" ? error.code : null
|
|
179
|
+
: 0,
|
|
180
|
+
stdout,
|
|
181
|
+
stderr,
|
|
182
|
+
...(error && typeof error.code === "string" ? { errorCode: error.code } : {}),
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function browserLaunchError(build, result) {
|
|
188
|
+
return new Error(`Chrome for Testing ${build.version} was installed but cannot start: ${commandFailure(result)}`);
|
|
189
|
+
}
|
|
190
|
+
function commandFailure(result) {
|
|
191
|
+
const detail = result.stderr.trim() || result.stdout.trim() || result.errorCode;
|
|
192
|
+
return detail ? detail.slice(0, 2_000) : `exit code ${result.exitCode ?? "unknown"}`;
|
|
193
|
+
}
|
|
@@ -58,6 +58,8 @@ export interface ChromeForTestingArtifactStoreOptions {
|
|
|
58
58
|
export interface InstallChromeForTestingOptions {
|
|
59
59
|
signal?: AbortSignal;
|
|
60
60
|
onProgress?: (message: string) => void;
|
|
61
|
+
/** Runs after the build is complete but before it becomes active. */
|
|
62
|
+
verifyBeforeActivate?: (build: InstalledChromeForTestingBuild) => Promise<void>;
|
|
61
63
|
}
|
|
62
64
|
export interface PruneChromeForTestingStagingOptions {
|
|
63
65
|
olderThanMs?: number;
|
|
@@ -86,6 +86,11 @@ export function createChromeForTestingArtifactStore(options = {}) {
|
|
|
86
86
|
});
|
|
87
87
|
};
|
|
88
88
|
const installDownloadedBuild = async (release, expectedSha256, installOptions) => {
|
|
89
|
+
const verifyBeforeActivate = async (build) => {
|
|
90
|
+
throwIfAborted(installOptions.signal);
|
|
91
|
+
await installOptions.verifyBeforeActivate?.(build);
|
|
92
|
+
throwIfAborted(installOptions.signal);
|
|
93
|
+
};
|
|
89
94
|
const paths = ensureStorePaths(rootDir, platform.hostPlatform);
|
|
90
95
|
if (expectedSha256 !== undefined) {
|
|
91
96
|
const finalPath = buildPath(paths.buildsRoot, release.version, expectedSha256);
|
|
@@ -94,6 +99,7 @@ export function createChromeForTestingArtifactStore(options = {}) {
|
|
|
94
99
|
sha256: expectedSha256,
|
|
95
100
|
});
|
|
96
101
|
if (existing) {
|
|
102
|
+
await verifyBeforeActivate(existing);
|
|
97
103
|
writeActiveManifest(paths.root, existing);
|
|
98
104
|
return existing;
|
|
99
105
|
}
|
|
@@ -105,6 +111,7 @@ export function createChromeForTestingArtifactStore(options = {}) {
|
|
|
105
111
|
if (active?.version === release.version &&
|
|
106
112
|
active.artifactPlatform === release.platform &&
|
|
107
113
|
active.sourceUrl === release.url) {
|
|
114
|
+
await verifyBeforeActivate(active);
|
|
108
115
|
return active;
|
|
109
116
|
}
|
|
110
117
|
}
|
|
@@ -134,6 +141,7 @@ export function createChromeForTestingArtifactStore(options = {}) {
|
|
|
134
141
|
const finalPath = buildPath(paths.buildsRoot, build.version, build.sha256);
|
|
135
142
|
const existing = readInstalledBuild(finalPath, paths.buildsRoot, platform, build);
|
|
136
143
|
if (existing) {
|
|
144
|
+
await verifyBeforeActivate(existing);
|
|
137
145
|
writeActiveManifest(paths.root, existing);
|
|
138
146
|
return existing;
|
|
139
147
|
}
|
|
@@ -164,6 +172,7 @@ export function createChromeForTestingArtifactStore(options = {}) {
|
|
|
164
172
|
throw error;
|
|
165
173
|
}
|
|
166
174
|
const installed = requireInstalledBuild(finalPath, paths.buildsRoot, platform, build);
|
|
175
|
+
await verifyBeforeActivate(installed);
|
|
167
176
|
writeActiveManifest(paths.root, installed);
|
|
168
177
|
installOptions.onProgress?.(`installed Chrome for Testing ${build.version} (${build.sha256})`);
|
|
169
178
|
return installed;
|
package/dist/daemon-server.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export declare function daemonActivityBlocksShutdown(activity: DaemonActivitySna
|
|
|
9
9
|
export interface StartRynxDaemonServerOptions {
|
|
10
10
|
config?: AppConfig;
|
|
11
11
|
warn?: (message: string) => void;
|
|
12
|
+
/** Process-owner callback after every daemon resource and owner lease has
|
|
13
|
+
* shut down successfully. Library callers normally leave this unset. */
|
|
14
|
+
onShutdownComplete?: () => void;
|
|
12
15
|
/** Test/deployment seam; failures roll back the already-listening server. */
|
|
13
16
|
writeEndpoint?: (config: AppConfig, managementToken: string) => Promise<void>;
|
|
14
17
|
/** Test seam for owner-lock failure injection. Production always uses the RYNX_HOME lease. */
|
|
@@ -25,7 +28,7 @@ export interface StartRynxDaemonServerOptions {
|
|
|
25
28
|
/** Test seam for the App-only embedded Chromium process supervisor. */
|
|
26
29
|
createBrowserHostSupervisor?: (options: AppBrowserHostSupervisorOptions) => Pick<AppBrowserHostSupervisor, "ensureConnected" | "restart" | "stop">;
|
|
27
30
|
}
|
|
28
|
-
export declare function startRynxDaemonServer({ config, warn, writeEndpoint, acquireOwner, preparePlugins, loadDirectConfig, startDirectServer, createChromeInspectionManager, createBrowserHostSupervisor, }?: StartRynxDaemonServerOptions): Promise<Awaited<ReturnType<typeof startServer>>>;
|
|
31
|
+
export declare function startRynxDaemonServer({ config, warn, onShutdownComplete, writeEndpoint, acquireOwner, preparePlugins, loadDirectConfig, startDirectServer, createChromeInspectionManager, createBrowserHostSupervisor, }?: StartRynxDaemonServerOptions): Promise<Awaited<ReturnType<typeof startServer>>>;
|
|
29
32
|
export declare function createSupervisedAppSessionBrowserHost(desktop: SessionBrowserHost, supervisor: Pick<AppBrowserHostSupervisor, "ensureConnected" | "restart">): SessionBrowserHost;
|
|
30
33
|
/**
|
|
31
34
|
* Resolve the authenticated semantic target inside its owning Runtime and
|