@rynx-ai/daemon 0.1.10 → 0.1.11-beta.10

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 (156) hide show
  1. package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
  2. package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +25 -0
  3. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
  4. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +56 -0
  5. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
  6. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
  7. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
  8. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
  9. package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
  10. package/bundled-plugins/plugins/lark/dist/host-adapters.js +506 -0
  11. package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
  12. package/bundled-plugins/plugins/lark/dist/index.js +7 -0
  13. package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
  14. package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
  15. package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
  16. package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
  17. package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
  18. package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
  19. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
  20. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
  21. package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
  22. package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
  23. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
  24. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
  25. package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
  26. package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
  27. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
  28. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
  29. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
  30. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
  31. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
  32. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
  33. package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
  34. package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
  35. package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
  36. package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
  37. package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
  38. package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
  39. package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
  40. package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
  41. package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
  42. package/bundled-plugins/plugins/lark/dist/lark.js +1975 -0
  43. package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
  44. package/bundled-plugins/plugins/lark/dist/runtime.js +131328 -0
  45. package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
  46. package/bundled-plugins/plugins/lark/dist/settings.js +126971 -0
  47. package/bundled-plugins/plugins/lark/package.json +57 -0
  48. package/bundled-plugins/plugins/lark/ui/assets/index-CGUVAMsv.css +1 -0
  49. package/bundled-plugins/plugins/lark/ui/assets/index-D8Amoe6a.js +201 -0
  50. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  51. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  52. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  53. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  54. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  55. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  56. package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  57. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  58. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  59. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  60. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  61. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  62. package/bundled-plugins/plugins/lark/ui/index.html +13 -0
  63. package/dist/agent-file.js +0 -1
  64. package/dist/browser-artifact-management.d.ts +4 -1
  65. package/dist/browser-artifact-management.js +18 -10
  66. package/dist/browser-artifacts.d.ts +1 -0
  67. package/dist/browser-artifacts.js +1 -0
  68. package/dist/bundled-plugins.d.ts +15 -0
  69. package/dist/bundled-plugins.js +134 -0
  70. package/dist/chrome-for-testing-runtime.d.ts +27 -0
  71. package/dist/chrome-for-testing-runtime.js +193 -0
  72. package/dist/chrome-for-testing-store.d.ts +2 -0
  73. package/dist/chrome-for-testing-store.js +9 -0
  74. package/dist/control-deps.d.ts +6 -2
  75. package/dist/control-deps.js +88 -82
  76. package/dist/daemon-server.d.ts +7 -1
  77. package/dist/daemon-server.js +310 -87
  78. package/dist/db.js +181 -124
  79. package/dist/entry-path.d.ts +3 -0
  80. package/dist/entry-path.js +12 -0
  81. package/dist/index-daemon.js +3 -66
  82. package/dist/lifecycle.d.ts +12 -0
  83. package/dist/lifecycle.js +16 -0
  84. package/dist/maintenance-lease.d.ts +39 -0
  85. package/dist/maintenance-lease.js +250 -0
  86. package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
  87. package/dist/migrations/cleanup-legacy-sessions.js +33 -15
  88. package/dist/official-plugins.d.ts +2 -0
  89. package/dist/official-plugins.js +2 -0
  90. package/dist/plugin-cli.d.ts +1 -3
  91. package/dist/plugin-cli.js +56 -45
  92. package/dist/plugin-host-leases.d.ts +4 -0
  93. package/dist/plugin-host-leases.js +7 -0
  94. package/dist/plugin-host-rpc.d.ts +73 -6
  95. package/dist/plugin-host-rpc.js +354 -81
  96. package/dist/plugin-installer.d.ts +24 -55
  97. package/dist/plugin-installer.js +258 -412
  98. package/dist/plugin-management-service.d.ts +30 -23
  99. package/dist/plugin-management-service.js +288 -105
  100. package/dist/plugin-marketplace.d.ts +35 -0
  101. package/dist/plugin-marketplace.js +299 -0
  102. package/dist/plugin-package.d.ts +22 -24
  103. package/dist/plugin-package.js +520 -571
  104. package/dist/plugin-skill-context.d.ts +4 -0
  105. package/dist/plugin-skill-context.js +35 -0
  106. package/dist/plugin-store.d.ts +36 -37
  107. package/dist/plugin-store.js +138 -92
  108. package/dist/plugin-supervisor.d.ts +50 -125
  109. package/dist/plugin-supervisor.js +678 -1030
  110. package/dist/pm2.d.ts +11 -2
  111. package/dist/pm2.js +130 -28
  112. package/dist/process.d.ts +12 -0
  113. package/dist/process.js +91 -0
  114. package/dist/runtime-project-store.d.ts +9 -0
  115. package/dist/runtime-project-store.js +83 -0
  116. package/dist/session-fallback-workspace.d.ts +22 -0
  117. package/dist/session-fallback-workspace.js +120 -0
  118. package/dist/session-fork-store.d.ts +41 -0
  119. package/dist/session-fork-store.js +288 -0
  120. package/dist/session-launch-operations.d.ts +23 -2
  121. package/dist/session-launch-operations.js +48 -7
  122. package/dist/session-meta-store.d.ts +12 -9
  123. package/dist/session-meta-store.js +50 -49
  124. package/dist/session-portal-grant-store.d.ts +29 -0
  125. package/dist/session-portal-grant-store.js +84 -0
  126. package/dist/setup-service.d.ts +21 -0
  127. package/dist/setup-service.js +39 -0
  128. package/dist/skills-catalog.d.ts +11 -2
  129. package/dist/skills-catalog.js +307 -7
  130. package/dist/system-dependencies.d.ts +26 -0
  131. package/dist/system-dependencies.js +149 -0
  132. package/package.json +36 -20
  133. package/dist/browser-cli-args.d.ts +0 -20
  134. package/dist/browser-cli-args.js +0 -100
  135. package/dist/channel-store.d.ts +0 -22
  136. package/dist/channel-store.js +0 -65
  137. package/dist/cli.d.ts +0 -2
  138. package/dist/cli.js +0 -732
  139. package/dist/control-client.d.ts +0 -122
  140. package/dist/control-client.js +0 -855
  141. package/dist/control-endpoint.d.ts +0 -14
  142. package/dist/control-endpoint.js +0 -124
  143. package/dist/desktop-browser-host-client.d.ts +0 -35
  144. package/dist/desktop-browser-host-client.js +0 -415
  145. package/dist/instance-store.d.ts +0 -38
  146. package/dist/instance-store.js +0 -85
  147. package/dist/plugin-install-restart.d.ts +0 -13
  148. package/dist/plugin-install-restart.js +0 -24
  149. package/dist/plugin-runtime-control.d.ts +0 -2
  150. package/dist/plugin-runtime-control.js +0 -37
  151. package/dist/registry.d.ts +0 -10
  152. package/dist/registry.js +0 -52
  153. package/dist/setup.d.ts +0 -20
  154. package/dist/setup.js +0 -374
  155. package/dist/update.d.ts +0 -25
  156. package/dist/update.js +0 -133
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Lark settings</title>
7
+ <script type="module" crossorigin src="./assets/index-D8Amoe6a.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-CGUVAMsv.css">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ </body>
13
+ </html>
@@ -46,7 +46,6 @@ export function scaffoldAgentSpec(id) {
46
46
  instructions: "You are a helpful agent.",
47
47
  executor: {
48
48
  runtime: "claude",
49
- model: "claude-sonnet-4-6",
50
49
  reasoningEffort: "medium",
51
50
  // Runtime budget (edit/remove as needed): timeout is enforced on every
52
51
  // runtime; retry maps to per-runtime env. maxIterations (claude only) and
@@ -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,15 @@
1
+ export interface EnsureBundledPluginsResult {
2
+ status: "ready" | "unavailable";
3
+ installed: string[];
4
+ updated: string[];
5
+ unchanged: string[];
6
+ marketplacePath?: string;
7
+ }
8
+ export declare function ensureBundledOfficialPlugins(options?: {
9
+ bundleDirectory?: string;
10
+ defaultPlugins?: readonly string[];
11
+ onProgress?: (message: string) => void;
12
+ /** Reclaim supervisor leases left by a prior daemon process. The caller
13
+ * must already hold the exclusive RYNX_HOME daemon-owner lock. */
14
+ reclaimHostLeases?: boolean;
15
+ }): Promise<EnsureBundledPluginsResult>;
@@ -0,0 +1,134 @@
1
+ import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, renameSync, rmSync, } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { isAbsolute, join } from "node:path";
4
+ import { rynxHome } from "@rynx-ai/core";
5
+ import { removePluginRuntimeLease } from "@rynx-ai/plugin-sdk";
6
+ import { pluginDataDir, preparePluginInstallation, } from "./plugin-installer.js";
7
+ import { PLUGIN_HOST_RUNTIME_LEASE_IDS } from "./plugin-host-leases.js";
8
+ import { addPluginMarketplace, resolveMarketplacePlugin, } from "./plugin-marketplace.js";
9
+ import { DEFAULT_BUNDLED_PLUGINS, OFFICIAL_MARKETPLACE_ID, } from "./official-plugins.js";
10
+ import { getPlugin, setPluginEnabled } from "./plugin-store.js";
11
+ export async function ensureBundledOfficialPlugins(options = {}) {
12
+ const configuredBundle = options.bundleDirectory ?? process.env.RYNX_BUNDLED_PLUGINS_DIR?.trim();
13
+ const bundleDirectory = configuredBundle ?? fileURLToPath(new URL("../bundled-plugins", import.meta.url));
14
+ if (!isAbsolute(bundleDirectory)) {
15
+ throw new Error("bundled plugin directory must be an absolute path");
16
+ }
17
+ if (!existsSync(bundleDirectory)) {
18
+ if (configuredBundle) {
19
+ throw new Error(`bundled plugin directory not found: ${bundleDirectory}`);
20
+ }
21
+ return emptyResult("unavailable");
22
+ }
23
+ if (!lstatSync(bundleDirectory).isDirectory()) {
24
+ throw new Error(`bundled plugin path is not a directory: ${bundleDirectory}`);
25
+ }
26
+ const marketplacePath = syncBundledMarketplace(bundleDirectory);
27
+ await addPluginMarketplace(marketplacePath, {
28
+ allowSourceRebind: true,
29
+ builtIn: true,
30
+ onProgress: options.onProgress,
31
+ });
32
+ const result = {
33
+ ...emptyResult("ready"),
34
+ marketplacePath,
35
+ };
36
+ for (const identity of options.defaultPlugins ?? DEFAULT_BUNDLED_PLUGINS) {
37
+ if (options.reclaimHostLeases)
38
+ reclaimPluginHostLeases(identity);
39
+ const resolved = resolveMarketplacePlugin(identity);
40
+ const prepared = await preparePluginInstallation(resolved.spec, options.onProgress, {
41
+ marketplaceId: OFFICIAL_MARKETPLACE_ID,
42
+ expectedId: resolved.pluginId,
43
+ expectedIdentity: identity,
44
+ });
45
+ try {
46
+ if (prepared.existing?.integrity === prepared.integrity) {
47
+ result.unchanged.push(identity);
48
+ continue;
49
+ }
50
+ const updating = Boolean(prepared.existing);
51
+ await prepared.commit({ expectedDigest: prepared.integrity });
52
+ if (!updating)
53
+ setPluginEnabled(identity, false);
54
+ (updating ? result.updated : result.installed).push(identity);
55
+ }
56
+ finally {
57
+ prepared.discard();
58
+ }
59
+ }
60
+ return result;
61
+ }
62
+ function reclaimPluginHostLeases(identity) {
63
+ const installed = getPlugin(identity);
64
+ if (!installed)
65
+ return;
66
+ const dataDir = pluginDataDir(installed.marketplaceId, installed.pluginId);
67
+ for (const leaseId of PLUGIN_HOST_RUNTIME_LEASE_IDS) {
68
+ removePluginRuntimeLease(dataDir, leaseId);
69
+ }
70
+ }
71
+ function syncBundledMarketplace(bundleDirectory) {
72
+ const distributionRoot = join(rynxHome(), "distribution");
73
+ const marketplacePath = join(distributionRoot, "official-market");
74
+ mkdirSync(distributionRoot, { recursive: true, mode: 0o700 });
75
+ const transactionDirectory = mkdtempSync(join(distributionRoot, "official-market-stage-"));
76
+ const stagedMarketplace = join(transactionDirectory, "market");
77
+ const backupPath = join(distributionRoot, `official-market-backup-${process.pid}-${Date.now()}`);
78
+ let backedUp = false;
79
+ try {
80
+ copyBundledTree(bundleDirectory, stagedMarketplace);
81
+ if (existsSync(marketplacePath)) {
82
+ renameSync(marketplacePath, backupPath);
83
+ backedUp = true;
84
+ }
85
+ try {
86
+ renameSync(stagedMarketplace, marketplacePath);
87
+ }
88
+ catch (error) {
89
+ if (backedUp && !existsSync(marketplacePath)) {
90
+ renameSync(backupPath, marketplacePath);
91
+ backedUp = false;
92
+ }
93
+ throw error;
94
+ }
95
+ if (backedUp) {
96
+ rmSync(backupPath, { recursive: true, force: true });
97
+ backedUp = false;
98
+ }
99
+ return marketplacePath;
100
+ }
101
+ finally {
102
+ rmSync(transactionDirectory, { recursive: true, force: true });
103
+ if (backedUp && !existsSync(marketplacePath) && existsSync(backupPath)) {
104
+ renameSync(backupPath, marketplacePath);
105
+ }
106
+ }
107
+ }
108
+ function copyBundledTree(source, destination) {
109
+ const info = lstatSync(source);
110
+ const mode = info.mode & 0o777;
111
+ if (info.isSymbolicLink()) {
112
+ throw new Error(`bundled plugin tree must not contain symbolic links: ${source}`);
113
+ }
114
+ if (info.isDirectory()) {
115
+ mkdirSync(destination, { recursive: true, mode: 0o700 });
116
+ for (const entry of readdirSync(source)) {
117
+ copyBundledTree(join(source, entry), join(destination, entry));
118
+ }
119
+ return;
120
+ }
121
+ if (!info.isFile()) {
122
+ throw new Error(`bundled plugin tree contains an unsupported entry: ${source}`);
123
+ }
124
+ copyFileSync(source, destination);
125
+ chmodSync(destination, mode);
126
+ }
127
+ function emptyResult(status) {
128
+ return {
129
+ status,
130
+ installed: [],
131
+ updated: [],
132
+ unchanged: [],
133
+ };
134
+ }
@@ -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;
@@ -1,2 +1,6 @@
1
- import type { ControlPlaneDeps } from "@rynx-ai/server";
2
- export declare function buildControlDeps(): ControlPlaneDeps;
1
+ import { type AgentRuntimeId, type AppConfig } from "@rynx-ai/core";
2
+ import { type ControlPlaneDeps } from "@rynx-ai/server";
3
+ import type { ControlAgentModelOption } from "@rynx-ai/protocol/control";
4
+ export declare function buildControlDeps(config: AppConfig): ControlPlaneDeps;
5
+ /** Project a Runtime-native model catalog into the control-plane option shape. */
6
+ export declare function listControlAgentModels(config: AppConfig, runtime: AgentRuntimeId): Promise<ControlAgentModelOption[]>;