@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.
Files changed (49) hide show
  1. package/bundled-plugins/plugins/lark/dist/runtime.js +2 -5
  2. package/bundled-plugins/plugins/lark/dist/settings.js +2 -2
  3. package/bundled-plugins/plugins/lark/package.json +1 -1
  4. package/dist/browser-artifact-management.d.ts +4 -1
  5. package/dist/browser-artifact-management.js +18 -10
  6. package/dist/browser-artifacts.d.ts +1 -0
  7. package/dist/browser-artifacts.js +1 -0
  8. package/dist/chrome-for-testing-runtime.d.ts +27 -0
  9. package/dist/chrome-for-testing-runtime.js +193 -0
  10. package/dist/chrome-for-testing-store.d.ts +2 -0
  11. package/dist/chrome-for-testing-store.js +9 -0
  12. package/dist/daemon-server.d.ts +4 -1
  13. package/dist/daemon-server.js +137 -32
  14. package/dist/db.js +2 -0
  15. package/dist/entry-path.d.ts +3 -0
  16. package/dist/entry-path.js +12 -0
  17. package/dist/index-daemon.js +3 -87
  18. package/dist/lifecycle.d.ts +12 -0
  19. package/dist/lifecycle.js +16 -0
  20. package/dist/maintenance-lease.d.ts +39 -0
  21. package/dist/maintenance-lease.js +250 -0
  22. package/dist/plugin-host-rpc.d.ts +19 -1
  23. package/dist/plugin-host-rpc.js +163 -23
  24. package/dist/plugin-installer.js +59 -0
  25. package/dist/plugin-supervisor.d.ts +5 -0
  26. package/dist/plugin-supervisor.js +218 -29
  27. package/dist/pm2.d.ts +11 -2
  28. package/dist/pm2.js +116 -19
  29. package/dist/process.d.ts +12 -0
  30. package/dist/process.js +91 -0
  31. package/dist/session-launch-operations.d.ts +10 -1
  32. package/dist/session-launch-operations.js +15 -6
  33. package/dist/setup-service.d.ts +20 -0
  34. package/dist/setup-service.js +38 -0
  35. package/package.json +33 -20
  36. package/dist/browser-cli-args.d.ts +0 -20
  37. package/dist/browser-cli-args.js +0 -100
  38. package/dist/cli.d.ts +0 -2
  39. package/dist/cli.js +0 -550
  40. package/dist/control-client.d.ts +0 -122
  41. package/dist/control-client.js +0 -855
  42. package/dist/control-endpoint.d.ts +0 -14
  43. package/dist/control-endpoint.js +0 -124
  44. package/dist/desktop-browser-host-client.d.ts +0 -35
  45. package/dist/desktop-browser-host-client.js +0 -415
  46. package/dist/setup.d.ts +0 -20
  47. package/dist/setup.js +0 -386
  48. package/dist/update.d.ts +0 -25
  49. 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
- AGENT_RUNTIME: external_exports.enum(["codex", "traex", "claude"]).default("codex"),
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 = nonEmptyString.refine((value) => path.isAbsolute(value) && path.normalize(value) === value, "path must be normalized and absolute");
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
- AGENT_RUNTIME: external_exports.enum(["codex", "traex", "claude"]).default("codex"),
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 = nonEmptyString.refine((value) => path.isAbsolute(value) && path.normalize(value) === value, "path must be normalized and absolute");
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/plugin-channel-lark",
3
- "version": "0.1.11",
3
+ "version": "0.1.11-beta.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -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: (message) => {
25
- if (messages.length >= MAX_PROGRESS_MESSAGES)
26
- return;
27
- const bounded = boundedUtf8(message, MAX_PROGRESS_MESSAGE_BYTES);
28
- const bytes = Buffer.byteLength(bounded, "utf8");
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;
@@ -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