@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.
- package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
- package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +25 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +56 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.js +506 -0
- package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/index.js +7 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
- package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
- package/bundled-plugins/plugins/lark/dist/lark.js +1975 -0
- package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/runtime.js +131328 -0
- package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/settings.js +126971 -0
- package/bundled-plugins/plugins/lark/package.json +57 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-CGUVAMsv.css +1 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-D8Amoe6a.js +201 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/index.html +13 -0
- package/dist/agent-file.js +0 -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/bundled-plugins.d.ts +15 -0
- package/dist/bundled-plugins.js +134 -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/control-deps.d.ts +6 -2
- package/dist/control-deps.js +88 -82
- package/dist/daemon-server.d.ts +7 -1
- package/dist/daemon-server.js +310 -87
- package/dist/db.js +181 -124
- package/dist/entry-path.d.ts +3 -0
- package/dist/entry-path.js +12 -0
- package/dist/index-daemon.js +3 -66
- 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/migrations/cleanup-legacy-sessions.d.ts +1 -1
- package/dist/migrations/cleanup-legacy-sessions.js +33 -15
- package/dist/official-plugins.d.ts +2 -0
- package/dist/official-plugins.js +2 -0
- package/dist/plugin-cli.d.ts +1 -3
- package/dist/plugin-cli.js +56 -45
- package/dist/plugin-host-leases.d.ts +4 -0
- package/dist/plugin-host-leases.js +7 -0
- package/dist/plugin-host-rpc.d.ts +73 -6
- package/dist/plugin-host-rpc.js +354 -81
- package/dist/plugin-installer.d.ts +24 -55
- package/dist/plugin-installer.js +258 -412
- package/dist/plugin-management-service.d.ts +30 -23
- package/dist/plugin-management-service.js +288 -105
- package/dist/plugin-marketplace.d.ts +35 -0
- package/dist/plugin-marketplace.js +299 -0
- package/dist/plugin-package.d.ts +22 -24
- package/dist/plugin-package.js +520 -571
- package/dist/plugin-skill-context.d.ts +4 -0
- package/dist/plugin-skill-context.js +35 -0
- package/dist/plugin-store.d.ts +36 -37
- package/dist/plugin-store.js +138 -92
- package/dist/plugin-supervisor.d.ts +50 -125
- package/dist/plugin-supervisor.js +678 -1030
- package/dist/pm2.d.ts +11 -2
- package/dist/pm2.js +130 -28
- package/dist/process.d.ts +12 -0
- package/dist/process.js +91 -0
- package/dist/runtime-project-store.d.ts +9 -0
- package/dist/runtime-project-store.js +83 -0
- package/dist/session-fallback-workspace.d.ts +22 -0
- package/dist/session-fallback-workspace.js +120 -0
- package/dist/session-fork-store.d.ts +41 -0
- package/dist/session-fork-store.js +288 -0
- package/dist/session-launch-operations.d.ts +23 -2
- package/dist/session-launch-operations.js +48 -7
- package/dist/session-meta-store.d.ts +12 -9
- package/dist/session-meta-store.js +50 -49
- package/dist/session-portal-grant-store.d.ts +29 -0
- package/dist/session-portal-grant-store.js +84 -0
- package/dist/setup-service.d.ts +21 -0
- package/dist/setup-service.js +39 -0
- package/dist/skills-catalog.d.ts +11 -2
- package/dist/skills-catalog.js +307 -7
- package/dist/system-dependencies.d.ts +26 -0
- package/dist/system-dependencies.js +149 -0
- package/package.json +36 -20
- package/dist/browser-cli-args.d.ts +0 -20
- package/dist/browser-cli-args.js +0 -100
- package/dist/channel-store.d.ts +0 -22
- package/dist/channel-store.js +0 -65
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -732
- 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/instance-store.d.ts +0 -38
- package/dist/instance-store.js +0 -85
- package/dist/plugin-install-restart.d.ts +0 -13
- package/dist/plugin-install-restart.js +0 -24
- package/dist/plugin-runtime-control.d.ts +0 -2
- package/dist/plugin-runtime-control.js +0 -37
- package/dist/registry.d.ts +0 -10
- package/dist/registry.js +0 -52
- package/dist/setup.d.ts +0 -20
- package/dist/setup.js +0 -374
- package/dist/update.d.ts +0 -25
- package/dist/update.js +0 -133
package/dist/daemon-server.js
CHANGED
|
@@ -6,26 +6,31 @@
|
|
|
6
6
|
* session registry. Keeping that wiring here avoids a second app-specific fork.
|
|
7
7
|
*/
|
|
8
8
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
9
|
-
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
import { mkdir, readFile, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
13
|
import WebSocket from "ws";
|
|
14
|
-
import { loadConfig, rynxHome } from "@rynx-ai/core";
|
|
14
|
+
import { CloseableAdmissionGate, loadConfig, resolveExecutionSnapshot, rynxHome, sessionWorkspaceSnapshotSchema, } from "@rynx-ai/core";
|
|
15
15
|
import { LOCAL_MANAGEMENT_PROTOCOL, } from "@rynx-ai/protocol/control";
|
|
16
16
|
import { REMOTE_RUNTIME_CORE_PROTOCOL } from "@rynx-ai/protocol/remote-runtime";
|
|
17
17
|
import { RUNTIME_BROWSER_INSPECT_MAX_MESSAGE_BYTES, RUNTIME_BROWSER_INSPECT_SEMANTIC_CAPABILITY, } from "@rynx-ai/protocol/runtime-browser-inspect";
|
|
18
18
|
import { RUNTIME_BROWSER_SURFACE_SEMANTIC_CAPABILITY } from "@rynx-ai/protocol/runtime-browser-surface";
|
|
19
19
|
import { RUNTIME_EMULATOR_SURFACE_SEMANTIC_CAPABILITY } from "@rynx-ai/protocol/runtime-emulator-surface";
|
|
20
|
-
import { createDaemonRuntimeHost, createDesktopFirstSessionBrowserHost, createRunnerSessionTerminalHost, createSessionRuntimeServices, DesktopBrowserHostAbsentError, DesktopBrowserHostRegistry, DirectRuntimeConnectionHub, DirectRuntimeBrowserInspectHostError, MachineSessionService, RemoteRuntimeDispatcher, SessionBrowserService, SessionBrowserServiceError, SessionBrowserSurfaceCoordinator, SessionEmulatorService, startServer, startDirectRuntimeServer, } from "@rynx-ai/server";
|
|
20
|
+
import { createDaemonRuntimeHost, createDesktopFirstSessionBrowserHost, createRunnerSessionTerminalHost, createSessionRuntimeServices, DesktopBrowserHostAbsentError, DesktopBrowserHostRegistry, DirectRuntimeConnectionHub, DirectRuntimeBrowserInspectHostError, MachineSessionService, MachineSessionServiceFailure, RemoteRuntimeDispatcher, SessionBrowserService, SessionBrowserServiceError, SessionBrowserSurfaceCoordinator, SessionEmulatorService, startServer, startDirectRuntimeServer, } from "@rynx-ai/server";
|
|
21
|
+
import { authorizeSessionPortalGrant, redeemSessionPortalTicket, } from "./session-portal-grant-store.js";
|
|
21
22
|
import { APP_BROWSER_HOST_BOOTSTRAP_TYPE, AppBrowserHostSupervisor, parseAppBrowserHostLaunchConfig, } from "./app-browser-host-supervisor.js";
|
|
22
|
-
import { buildControlDeps } from "./control-deps.js";
|
|
23
|
+
import { buildControlDeps, listControlAgentModels } from "./control-deps.js";
|
|
23
24
|
import { createBrowserArtifactManagementService } from "./browser-artifact-management.js";
|
|
24
25
|
import { createDaemonBuildStatus } from "./daemon-build-status.js";
|
|
26
|
+
import { MaintenanceLeaseStore } from "./maintenance-lease.js";
|
|
25
27
|
import { BrowserRunnerSessionContextProvider } from "./browser-runner-session-context.js";
|
|
28
|
+
import { removeLegacyPluginSkillSnapshot, snapshotEnabledPluginSkillSources, } from "./plugin-skill-context.js";
|
|
29
|
+
import { installedDaemonVersion } from "./entry-path.js";
|
|
26
30
|
import { isChromeForTestingHostSupported } from "./chrome-for-testing-store.js";
|
|
27
31
|
import { ChromeInspectionManager, } from "./chrome-inspection-manager.js";
|
|
28
32
|
import { createHeadlessBrowserHost } from "./headless-browser-host.js";
|
|
33
|
+
import { db } from "./db.js";
|
|
29
34
|
import { acquireDaemonOwner } from "./daemon-owner.js";
|
|
30
35
|
import { DaemonDirectRuntimeAuthenticator } from "./direct-runtime-authenticator.js";
|
|
31
36
|
import { DurableEmbeddedBrowserProfileHost } from "./embedded-browser-profile-cleanup.js";
|
|
@@ -34,16 +39,18 @@ import { isDaemonDirectRuntimeHostingSupported, loadOrCreateDaemonDirectRuntimeE
|
|
|
34
39
|
import { cleanupLegacySessions } from "./migrations/cleanup-legacy-sessions.js";
|
|
35
40
|
import { createMaintenanceManagementService } from "./maintenance-management.js";
|
|
36
41
|
import { PluginManagementService } from "./plugin-management-service.js";
|
|
42
|
+
import { addPluginMarketplace, listPluginMarketplaces, refreshPluginMarketplace, removePluginMarketplace, } from "./plugin-marketplace.js";
|
|
37
43
|
import { PluginSupervisor } from "./plugin-supervisor.js";
|
|
38
44
|
import { pruneInactivePluginInstallations } from "./plugin-installer.js";
|
|
39
45
|
import { runPluginCliCommand } from "./plugin-cli.js";
|
|
40
|
-
import {
|
|
41
|
-
import { loadPlugins, resolveChannelInstances } from "./registry.js";
|
|
46
|
+
import { listPlugins } from "./plugin-store.js";
|
|
42
47
|
import { SqliteSessionLogStore } from "./session-log-store.js";
|
|
48
|
+
import { SqliteSessionForkStore } from "./session-fork-store.js";
|
|
43
49
|
import { SqliteSessionResourceStore } from "./session-resource-store.js";
|
|
50
|
+
import { createSessionFallbackWorkspace, discardSessionFallbackWorkspace, } from "./session-fallback-workspace.js";
|
|
44
51
|
import { SessionBrowserCapabilityStore } from "./session-browser-capability-store.js";
|
|
45
52
|
import { SqliteSessionEmulatorBindingStore } from "./session-emulator-binding-store.js";
|
|
46
|
-
import { sessionRegistry } from "./session-meta-store.js";
|
|
53
|
+
import { sessionBelongsToPlugin, sessionRegistry } from "./session-meta-store.js";
|
|
47
54
|
import { sessionPendingMessageStore } from "./session-pending-message-store.js";
|
|
48
55
|
import { RemoteRuntimeAccessStore } from "./remote-runtime-access-store.js";
|
|
49
56
|
import { DaemonRemoteRuntimeAdmin } from "./remote-runtime-admin.js";
|
|
@@ -52,6 +59,7 @@ import { DaemonRuntimeConnectionManager } from "./remote-runtime-connection-mana
|
|
|
52
59
|
import { DaemonRuntimeTargetControl } from "./remote-runtime-target-control.js";
|
|
53
60
|
import { RemoteRuntimeTargetStore } from "./remote-runtime-target-store.js";
|
|
54
61
|
import { ProviderCliService } from "./provider-cli-service.js";
|
|
62
|
+
import { SqliteRuntimeProjectStore } from "./runtime-project-store.js";
|
|
55
63
|
const PLUGIN_CLI_OUTPUT_MAX_BYTES = 256 * 1024;
|
|
56
64
|
const BROWSER_INSPECT_OPEN_TIMEOUT_MS = 10_000;
|
|
57
65
|
const BROWSER_INSPECT_CLOSE_TIMEOUT_MS = 1_000;
|
|
@@ -59,8 +67,72 @@ const BROWSER_INSPECT_MAX_QUEUED_BYTES = 32 * 1024 * 1024;
|
|
|
59
67
|
const DIRECT_RUNTIME_HOSTING_UNSUPPORTED = "Direct Runtime hosting is supported only on macOS and Linux until protected server-key storage is available on other operating systems";
|
|
60
68
|
const require = createRequire(import.meta.url);
|
|
61
69
|
const DAEMON_PACKAGE_VERSION = readDaemonPackageVersion();
|
|
70
|
+
async function resolveSessionExecutionSnapshot(input) {
|
|
71
|
+
return {
|
|
72
|
+
...await resolveExecutionSnapshot(input),
|
|
73
|
+
pluginSkills: snapshotEnabledPluginSkillSources(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function resolveSessionWorkspace(projects, projectId, managedCwd, workspace) {
|
|
77
|
+
if (workspace) {
|
|
78
|
+
return sessionWorkspaceSnapshotSchema.parse(workspace);
|
|
79
|
+
}
|
|
80
|
+
if (projectId) {
|
|
81
|
+
const project = await projects.get(projectId);
|
|
82
|
+
if (!project) {
|
|
83
|
+
throw new MachineSessionServiceFailure("not_found", "project not found");
|
|
84
|
+
}
|
|
85
|
+
await assertWorkspaceDirectories(project.directories);
|
|
86
|
+
return sessionWorkspaceSnapshotSchema.parse({
|
|
87
|
+
cwd: project.primary,
|
|
88
|
+
allowedDirs: [
|
|
89
|
+
project.primary,
|
|
90
|
+
...project.directories.filter((directory) => directory !== project.primary),
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (managedCwd) {
|
|
95
|
+
let canonical;
|
|
96
|
+
try {
|
|
97
|
+
canonical = await realpath(managedCwd);
|
|
98
|
+
await assertWorkspaceDirectories([canonical]);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error instanceof MachineSessionServiceFailure)
|
|
102
|
+
throw error;
|
|
103
|
+
throw new MachineSessionServiceFailure("failed_precondition", "Session working directory is unavailable");
|
|
104
|
+
}
|
|
105
|
+
return sessionWorkspaceSnapshotSchema.parse({
|
|
106
|
+
cwd: canonical,
|
|
107
|
+
allowedDirs: [canonical],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return await createSessionFallbackWorkspace();
|
|
111
|
+
}
|
|
112
|
+
async function assertWorkspaceDirectories(directories) {
|
|
113
|
+
try {
|
|
114
|
+
await Promise.all(directories.map(async (directory) => {
|
|
115
|
+
if (!(await stat(directory)).isDirectory())
|
|
116
|
+
throw new Error(directory);
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new MachineSessionServiceFailure("failed_precondition", "one or more Project directories are unavailable");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function toMarketplaceItem(record) {
|
|
124
|
+
return {
|
|
125
|
+
id: record.marketplaceId,
|
|
126
|
+
source: record.sourceType,
|
|
127
|
+
builtIn: record.builtIn,
|
|
128
|
+
plugins: record.catalog.plugins.map((plugin) => ({ id: plugin.id })),
|
|
129
|
+
resolvedRevision: record.resolvedRevision,
|
|
130
|
+
refreshedAt: record.refreshedAt,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
62
133
|
export function daemonActivityBlocksShutdown(activity) {
|
|
63
|
-
return activity.runningTurns > 0
|
|
134
|
+
return activity.runningTurns > 0
|
|
135
|
+
|| activity.pendingInteractions > 0;
|
|
64
136
|
}
|
|
65
137
|
function defaultWarn(message) {
|
|
66
138
|
console.warn(JSON.stringify({ level: "warn", type: "channel-registry", msg: message }));
|
|
@@ -179,18 +251,31 @@ async function removeControlEndpointForCurrentProcess() {
|
|
|
179
251
|
// Best effort only; stale endpoint files are ignored by the client fallback.
|
|
180
252
|
}
|
|
181
253
|
}
|
|
182
|
-
export async function startRynxDaemonServer({ config, warn = defaultWarn, writeEndpoint = writeControlEndpoint, acquireOwner = acquireDaemonOwner, loadDirectConfig = loadDirectRuntimeConfig, startDirectServer = startDirectRuntimeServer, createChromeInspectionManager = (options) => ChromeInspectionManager.create(options), createBrowserHostSupervisor = (options) => new AppBrowserHostSupervisor(options), } = {}) {
|
|
254
|
+
export async function startRynxDaemonServer({ config, warn = defaultWarn, onShutdownComplete, writeEndpoint = writeControlEndpoint, acquireOwner = acquireDaemonOwner, preparePlugins, loadDirectConfig = loadDirectRuntimeConfig, startDirectServer = startDirectRuntimeServer, createChromeInspectionManager = (options) => ChromeInspectionManager.create(options), createBrowserHostSupervisor = (options) => new AppBrowserHostSupervisor(options), } = {}) {
|
|
183
255
|
const owner = await acquireOwner();
|
|
184
256
|
let ownerManagedByServer = false;
|
|
185
257
|
try {
|
|
258
|
+
await preparePlugins?.();
|
|
186
259
|
const appConfig = config ?? loadConfig();
|
|
260
|
+
const admissionGate = new CloseableAdmissionGate();
|
|
261
|
+
let shutdownAccepted = false;
|
|
262
|
+
const maintenanceLease = new MaintenanceLeaseStore({
|
|
263
|
+
// Expiry restores the gate primitive for a process that outlives its
|
|
264
|
+
// upgrader. The independent accepted-shutdown fence below still prevents
|
|
265
|
+
// new work after an irreversible server shutdown has begun.
|
|
266
|
+
onExpired: () => admissionGate.reopen(),
|
|
267
|
+
});
|
|
268
|
+
const admissionOpen = () => !shutdownAccepted && !maintenanceLease.isActive();
|
|
269
|
+
const reserveAdmission = () => !admissionOpen()
|
|
270
|
+
? undefined
|
|
271
|
+
: admissionGate.tryReserve();
|
|
187
272
|
const appBrowserHostLaunch = parseAppBrowserHostLaunchConfig();
|
|
188
273
|
const directHostingSupported = isDaemonDirectRuntimeHostingSupported();
|
|
189
274
|
const runtimeBrowserSupported = appBrowserHostLaunch !== undefined || isChromeForTestingHostSupported();
|
|
190
275
|
const directConfig = directHostingSupported
|
|
191
276
|
? await loadDirectConfig()
|
|
192
277
|
: undefined;
|
|
193
|
-
const control = buildControlDeps();
|
|
278
|
+
const control = buildControlDeps(appConfig);
|
|
194
279
|
const installationIdentity = await loadOrCreateDaemonInstallationIdentity();
|
|
195
280
|
const directEncryptionIdentity = directHostingSupported
|
|
196
281
|
? await loadOrCreateDaemonDirectRuntimeEncryptionIdentity()
|
|
@@ -214,12 +299,15 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
214
299
|
"semantic.session.interrupt.v1",
|
|
215
300
|
"semantic.session.agent-options.v1",
|
|
216
301
|
"semantic.session.launch-options.v2",
|
|
302
|
+
"semantic.session.execution-settings.v1",
|
|
217
303
|
"semantic.session.create.v1",
|
|
304
|
+
"semantic.session.fork.v1",
|
|
218
305
|
"semantic.session.message.v1",
|
|
219
306
|
"semantic.session.resources.v1",
|
|
220
307
|
"semantic.session.message-queue.v1",
|
|
221
308
|
"semantic.session.delete.v1",
|
|
222
309
|
"semantic.session.interaction.v1",
|
|
310
|
+
"semantic.project.manage.v1",
|
|
223
311
|
"semantic.provider-cli.status.v1",
|
|
224
312
|
...(runtimeBrowserSupported ? ["semantic.browser.v1"] : []),
|
|
225
313
|
...(runtimeBrowserSupported && directHostingSupported
|
|
@@ -259,8 +347,11 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
259
347
|
catch (error) {
|
|
260
348
|
warn(`plugin package cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
261
349
|
}
|
|
262
|
-
const pluginSupervisor = new PluginSupervisor(
|
|
350
|
+
const pluginSupervisor = new PluginSupervisor(listPlugins(), {
|
|
263
351
|
daemonInstanceId,
|
|
352
|
+
productVersion: controlEndpointDistributionMetadata().productVersion,
|
|
353
|
+
cliVersion: boundedEnvironmentMetadata(process.env.RYNX_CLI_VERSION, 128)
|
|
354
|
+
?? installedDaemonVersion(),
|
|
264
355
|
log: (entry) => {
|
|
265
356
|
const output = entry.level === "error"
|
|
266
357
|
? console.error
|
|
@@ -270,39 +361,14 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
270
361
|
output(JSON.stringify(entry));
|
|
271
362
|
},
|
|
272
363
|
});
|
|
273
|
-
const pluginManagement = new PluginManagementService(
|
|
364
|
+
const pluginManagement = new PluginManagementService(undefined, {
|
|
365
|
+
supervisor: pluginSupervisor,
|
|
366
|
+
});
|
|
274
367
|
const browserArtifactManagement = createBrowserArtifactManagementService();
|
|
275
368
|
const maintenanceManagement = createMaintenanceManagementService({
|
|
276
369
|
codexStorePath: appConfig.AGENT_SESSION_STORE_PATH,
|
|
277
370
|
});
|
|
278
|
-
await loadPlugins(pluginSupervisor, warn);
|
|
279
371
|
logLegacyCleanup(appConfig);
|
|
280
|
-
const reloadPluginRuntime = async (pluginId) => {
|
|
281
|
-
const record = getPlugin(pluginId);
|
|
282
|
-
if (!record)
|
|
283
|
-
throw new Error(`plugin "${pluginId}" is not installed`);
|
|
284
|
-
if (!record.enabled)
|
|
285
|
-
throw new Error(`plugin "${pluginId}" is disabled`);
|
|
286
|
-
if (!isRunnablePluginRecord(record)) {
|
|
287
|
-
throw new Error(`plugin "${pluginId}" must be reinstalled before its runtime can start`);
|
|
288
|
-
}
|
|
289
|
-
const status = await pluginSupervisor.reloadPluginRuntime(record);
|
|
290
|
-
await loadPlugins(pluginSupervisor, warn);
|
|
291
|
-
return { pluginId, status };
|
|
292
|
-
};
|
|
293
|
-
const ensurePluginRuntime = async (pluginId) => {
|
|
294
|
-
const record = getPlugin(pluginId);
|
|
295
|
-
if (!record)
|
|
296
|
-
throw new Error(`plugin "${pluginId}" is not installed`);
|
|
297
|
-
if (!record.enabled)
|
|
298
|
-
throw new Error(`plugin "${pluginId}" is disabled`);
|
|
299
|
-
if (!isRunnablePluginRecord(record)) {
|
|
300
|
-
throw new Error(`plugin "${pluginId}" must be reinstalled before its runtime can start`);
|
|
301
|
-
}
|
|
302
|
-
const status = await pluginSupervisor.ensurePluginRuntime(record);
|
|
303
|
-
await loadPlugins(pluginSupervisor, warn);
|
|
304
|
-
return { pluginId, status };
|
|
305
|
-
};
|
|
306
372
|
const invokePluginCli = async ({ pluginId, args, stdin }, { signal }) => {
|
|
307
373
|
const result = await runPluginCliCommand(pluginId, args, {
|
|
308
374
|
stdio: "pipe",
|
|
@@ -310,14 +376,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
310
376
|
captureOutputBytes: PLUGIN_CLI_OUTPUT_MAX_BYTES,
|
|
311
377
|
signal,
|
|
312
378
|
});
|
|
313
|
-
if (result.code === 0) {
|
|
314
|
-
const reload = result.effects.some((effect) => effect.effect === "runtime.reload");
|
|
315
|
-
const ensure = result.effects.some((effect) => effect.effect === "runtime.ensure");
|
|
316
|
-
if (reload)
|
|
317
|
-
await reloadPluginRuntime(pluginId);
|
|
318
|
-
else if (ensure)
|
|
319
|
-
await ensurePluginRuntime(pluginId);
|
|
320
|
-
}
|
|
321
379
|
const output = result.output;
|
|
322
380
|
return {
|
|
323
381
|
code: result.code,
|
|
@@ -326,6 +384,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
326
384
|
truncated: Boolean(output?.stdoutTruncated || output?.stderrTruncated),
|
|
327
385
|
};
|
|
328
386
|
};
|
|
387
|
+
let machineSessions;
|
|
329
388
|
const pluginRuntime = {
|
|
330
389
|
bindHostServices: (services) => pluginSupervisor.bindHostServices({
|
|
331
390
|
...services,
|
|
@@ -335,10 +394,37 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
335
394
|
publicKey: installationIdentity.publicKey,
|
|
336
395
|
sign: installationIdentity.sign,
|
|
337
396
|
},
|
|
397
|
+
sessionLaunch: {
|
|
398
|
+
resolve: async (selection) => {
|
|
399
|
+
const workspace = await resolveSessionWorkspace(runtimeProjects, selection.projectId, selection.managedCwd, selection.workspace);
|
|
400
|
+
return {
|
|
401
|
+
workspace,
|
|
402
|
+
execution: await resolveSessionExecutionSnapshot({
|
|
403
|
+
config: appConfig,
|
|
404
|
+
...(selection.agent ? { agentName: selection.agent } : {}),
|
|
405
|
+
...(selection.config ? { spec: selection.config } : {}),
|
|
406
|
+
...((selection.provider || (!selection.agent && !selection.config))
|
|
407
|
+
? { provider: selection.provider ?? appConfig.DEFAULT_RUNTIME }
|
|
408
|
+
: {}),
|
|
409
|
+
...(selection.model !== undefined ? { model: selection.model } : {}),
|
|
410
|
+
...(selection.reasoningEffort
|
|
411
|
+
? { reasoningEffort: selection.reasoningEffort }
|
|
412
|
+
: {}),
|
|
413
|
+
cwd: workspace.cwd,
|
|
414
|
+
}),
|
|
415
|
+
};
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
sessionExecution: {
|
|
419
|
+
update: async (input) => {
|
|
420
|
+
await machineSessions.updateExecutionSettings(input);
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
sessionFork: (input) => machineSessions.fork(input),
|
|
424
|
+
admissionOpen,
|
|
425
|
+
admissionReserve: reserveAdmission,
|
|
338
426
|
}),
|
|
339
427
|
startPluginRuntimes: pluginSupervisor.startPluginRuntimes.bind(pluginSupervisor),
|
|
340
|
-
reloadPluginRuntime,
|
|
341
|
-
ensurePluginRuntime,
|
|
342
428
|
statusSnapshot: pluginSupervisor.statusSnapshot.bind(pluginSupervisor),
|
|
343
429
|
dispose: pluginSupervisor.dispose.bind(pluginSupervisor),
|
|
344
430
|
};
|
|
@@ -346,6 +432,8 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
346
432
|
const directConnections = new DirectRuntimeConnectionHub();
|
|
347
433
|
const sessionLog = new SqliteSessionLogStore();
|
|
348
434
|
const sessionResources = new SqliteSessionResourceStore();
|
|
435
|
+
const sessionForks = new SqliteSessionForkStore();
|
|
436
|
+
const runtimeProjects = new SqliteRuntimeProjectStore();
|
|
349
437
|
const providerClis = new ProviderCliService();
|
|
350
438
|
const sessionBrowserCapabilities = new SessionBrowserCapabilityStore();
|
|
351
439
|
const durableDesktopBrowserHost = new DurableEmbeddedBrowserProfileHost(desktopBrowserHosts, { warn });
|
|
@@ -357,16 +445,21 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
357
445
|
config: appConfig,
|
|
358
446
|
sessionLog,
|
|
359
447
|
sessionContextProvider: browserRunnerSessionContexts,
|
|
448
|
+
admissionOpen,
|
|
449
|
+
admissionReserve: reserveAdmission,
|
|
360
450
|
onMirrorError: (error, sessionId) => warn(`Session mirror failed for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`),
|
|
361
451
|
});
|
|
452
|
+
const sessionBrowserHost = appBrowserHostSupervisor
|
|
453
|
+
? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
|
|
454
|
+
: createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost());
|
|
362
455
|
const sessionBrowsers = new SessionBrowserService({
|
|
363
|
-
host:
|
|
364
|
-
? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
|
|
365
|
-
: createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost()),
|
|
456
|
+
host: sessionBrowserHost,
|
|
366
457
|
sessions: {
|
|
367
458
|
exists: async (sessionId) => Boolean(sessionRegistry.get(sessionId) ??
|
|
368
459
|
await sessionRuntimeServices.sessionStore.get(sessionId)),
|
|
369
460
|
},
|
|
461
|
+
}, {
|
|
462
|
+
admissionReserve: reserveAdmission,
|
|
370
463
|
});
|
|
371
464
|
const sessionEmulators = control.emulator
|
|
372
465
|
? new SessionEmulatorService({
|
|
@@ -422,14 +515,35 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
422
515
|
sessionEmulators?.cleanupSession(sessionId),
|
|
423
516
|
]);
|
|
424
517
|
},
|
|
425
|
-
afterDelete: (sessionId) => {
|
|
518
|
+
afterDelete: async (sessionId) => {
|
|
426
519
|
sessionBrowserCapabilities.revoke(sessionId);
|
|
520
|
+
removeLegacyPluginSkillSnapshot(sessionId);
|
|
521
|
+
await sessionRuntimeServices.sessionStore.delete(sessionId);
|
|
427
522
|
},
|
|
428
523
|
};
|
|
429
|
-
const
|
|
524
|
+
const deletedSessions = db()
|
|
525
|
+
.prepare("SELECT session_id AS sessionId FROM session_snapshot_cleanup ORDER BY session_id")
|
|
526
|
+
.all();
|
|
527
|
+
for (const { sessionId } of deletedSessions) {
|
|
528
|
+
try {
|
|
529
|
+
await Promise.all([
|
|
530
|
+
sessionBrowsers.cleanupSession(sessionId),
|
|
531
|
+
sessionEmulators?.cleanupSession(sessionId),
|
|
532
|
+
]);
|
|
533
|
+
sessionResources.deleteSession(sessionId);
|
|
534
|
+
removeLegacyPluginSkillSnapshot(sessionId);
|
|
535
|
+
await sessionRuntimeServices.sessionStore.delete(sessionId);
|
|
536
|
+
db().prepare("DELETE FROM session_snapshot_cleanup WHERE session_id = ?").run(sessionId);
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
warn(`Legacy Session artifact cleanup will retry for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
machineSessions = new MachineSessionService({
|
|
430
543
|
registry: sessionRegistry,
|
|
431
544
|
log: sessionLog,
|
|
432
545
|
events: sessionRuntimeServices.sessionBus,
|
|
546
|
+
publishEvent: sessionRuntimeServices.publishSessionEvent,
|
|
433
547
|
runtimeState: sessionRuntimeServices.sessionRuntimeIndex,
|
|
434
548
|
interruption: {
|
|
435
549
|
interrupt: (sessionId) => sessionRuntimeServices.runnerManager.interruptLiveSession(sessionId),
|
|
@@ -440,29 +554,131 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
440
554
|
},
|
|
441
555
|
pendingMessages: sessionPendingMessageStore,
|
|
442
556
|
resources: sessionResources,
|
|
557
|
+
forks: sessionForks,
|
|
443
558
|
execution: {
|
|
444
559
|
runtime: sessionRuntimeServices.conversationRuntime,
|
|
560
|
+
resolve: ({ agent, provider, model, reasoningEffort, permissionPreset, cwd }) => resolveSessionExecutionSnapshot({
|
|
561
|
+
config: appConfig,
|
|
562
|
+
...(agent ? { agentName: agent } : {}),
|
|
563
|
+
...(provider ? { provider } : {}),
|
|
564
|
+
...(model ? { model } : {}),
|
|
565
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
566
|
+
...(permissionPreset ? { permissionPreset } : {}),
|
|
567
|
+
cwd,
|
|
568
|
+
}),
|
|
569
|
+
listModels: (provider) => listControlAgentModels(appConfig, provider),
|
|
445
570
|
runner: sessionRuntimeServices.runnerManager,
|
|
446
|
-
sessionStore: sessionRuntimeServices.sessionStore,
|
|
447
571
|
},
|
|
572
|
+
workspace: {
|
|
573
|
+
resolve: (projectId) => resolveSessionWorkspace(runtimeProjects, projectId),
|
|
574
|
+
discardUnbound: discardSessionFallbackWorkspace,
|
|
575
|
+
},
|
|
576
|
+
}, {
|
|
577
|
+
admissionOpen,
|
|
578
|
+
admissionReserve: reserveAdmission,
|
|
448
579
|
});
|
|
449
580
|
const directAuthenticator = new DaemonDirectRuntimeAuthenticator(installationIdentity, remoteRuntime, remoteRuntimeAccess);
|
|
450
581
|
const sessionTerminals = createRunnerSessionTerminalHost({
|
|
451
582
|
runnerManager: sessionRuntimeServices.runnerManager,
|
|
583
|
+
admissionReserve: reserveAdmission,
|
|
452
584
|
resolveLiveSession: async (sessionId) => {
|
|
453
|
-
const bound = await sessionRuntimeServices.sessionStore.get(sessionId);
|
|
454
585
|
const registered = sessionRegistry.get(sessionId);
|
|
455
|
-
|
|
456
|
-
if ((!bound && !registered) ||
|
|
457
|
-
!cwd ||
|
|
586
|
+
if (!registered ||
|
|
458
587
|
!sessionRuntimeServices.runnerManager.hasLiveSession(sessionId)) {
|
|
459
588
|
return undefined;
|
|
460
589
|
}
|
|
461
|
-
return { cwd };
|
|
590
|
+
return { cwd: registered.workspace.cwd };
|
|
462
591
|
},
|
|
463
592
|
});
|
|
464
|
-
let shutdownAccepted = false;
|
|
465
593
|
let requestServerShutdown;
|
|
594
|
+
let shutdownAttempt;
|
|
595
|
+
let shutdownAttemptLeaseToken;
|
|
596
|
+
const shutdownIfIdle = (maintenanceLeaseToken) => {
|
|
597
|
+
if (maintenanceLease.isActive()) {
|
|
598
|
+
if (!maintenanceLeaseToken || !maintenanceLease.isHeldBy(maintenanceLeaseToken)) {
|
|
599
|
+
return Promise.reject(new Error("a different maintenance lease is already active"));
|
|
600
|
+
}
|
|
601
|
+
// The previous daemon may have persisted the lease and exited after
|
|
602
|
+
// its 202 response was lost. A replacement process holding the same
|
|
603
|
+
// token must perform its own close/drain/shutdown; returning accepted
|
|
604
|
+
// without scheduling this PID would strand the updater waiting for a
|
|
605
|
+
// process that can never exit.
|
|
606
|
+
}
|
|
607
|
+
if (shutdownAccepted) {
|
|
608
|
+
if (maintenanceLeaseToken) {
|
|
609
|
+
maintenanceLease.acquire(maintenanceLeaseToken);
|
|
610
|
+
return Promise.resolve({
|
|
611
|
+
outcome: "accepted",
|
|
612
|
+
maintenanceLease: "active",
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
return Promise.resolve({ outcome: "accepted" });
|
|
616
|
+
}
|
|
617
|
+
if (shutdownAttempt) {
|
|
618
|
+
if (maintenanceLeaseToken === shutdownAttemptLeaseToken) {
|
|
619
|
+
return shutdownAttempt;
|
|
620
|
+
}
|
|
621
|
+
return Promise.reject(new Error("another idle shutdown check is already in progress"));
|
|
622
|
+
}
|
|
623
|
+
shutdownAttemptLeaseToken = maintenanceLeaseToken;
|
|
624
|
+
const attempt = (async () => {
|
|
625
|
+
await admissionGate.closeAndDrain();
|
|
626
|
+
const runtimeActivity = sessionRuntimeServices.sessionRuntimeIndex.activitySnapshot();
|
|
627
|
+
const activity = {
|
|
628
|
+
...runtimeActivity,
|
|
629
|
+
// A terminal submission keeps its own admission reservation until the
|
|
630
|
+
// first response or native rotation is visible. Failed process-tree
|
|
631
|
+
// cleanup releases the reservation but remains pinned here, so an
|
|
632
|
+
// idle check returns busy instead of hanging or killing hidden work.
|
|
633
|
+
runningTurns: runtimeActivity.runningTurns
|
|
634
|
+
+ sessionRuntimeServices.runnerManager.pendingTerminalInputCount(),
|
|
635
|
+
activeTerminals: sessionTerminals.activeTerminalCount(),
|
|
636
|
+
activeBrowsers: sessionBrowsers.activeBrowserCount(),
|
|
637
|
+
};
|
|
638
|
+
if (daemonActivityBlocksShutdown(activity)) {
|
|
639
|
+
admissionGate.reopen();
|
|
640
|
+
return { outcome: "busy", activity };
|
|
641
|
+
}
|
|
642
|
+
const shutdown = requestServerShutdown;
|
|
643
|
+
if (!shutdown) {
|
|
644
|
+
admissionGate.reopen();
|
|
645
|
+
throw new Error("idle daemon shutdown was requested before server lifecycle was ready");
|
|
646
|
+
}
|
|
647
|
+
const acquiredLease = maintenanceLeaseToken
|
|
648
|
+
? maintenanceLease.acquire(maintenanceLeaseToken)
|
|
649
|
+
: false;
|
|
650
|
+
shutdownAccepted = true;
|
|
651
|
+
try {
|
|
652
|
+
void shutdown().catch((error) => {
|
|
653
|
+
shutdownAccepted = false;
|
|
654
|
+
if (acquiredLease && maintenanceLeaseToken) {
|
|
655
|
+
maintenanceLease.release(maintenanceLeaseToken);
|
|
656
|
+
}
|
|
657
|
+
admissionGate.reopen();
|
|
658
|
+
warn(`idle daemon shutdown failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
shutdownAccepted = false;
|
|
663
|
+
if (acquiredLease && maintenanceLeaseToken) {
|
|
664
|
+
maintenanceLease.release(maintenanceLeaseToken);
|
|
665
|
+
}
|
|
666
|
+
admissionGate.reopen();
|
|
667
|
+
throw error;
|
|
668
|
+
}
|
|
669
|
+
return maintenanceLeaseToken
|
|
670
|
+
? { outcome: "accepted", maintenanceLease: "active" }
|
|
671
|
+
: { outcome: "accepted" };
|
|
672
|
+
})();
|
|
673
|
+
shutdownAttempt = attempt;
|
|
674
|
+
void attempt.finally(() => {
|
|
675
|
+
if (shutdownAttempt === attempt) {
|
|
676
|
+
shutdownAttempt = undefined;
|
|
677
|
+
shutdownAttemptLeaseToken = undefined;
|
|
678
|
+
}
|
|
679
|
+
}).catch(() => undefined);
|
|
680
|
+
return attempt;
|
|
681
|
+
};
|
|
466
682
|
const daemonManagement = {
|
|
467
683
|
managementToken,
|
|
468
684
|
identity: () => ({
|
|
@@ -471,6 +687,14 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
471
687
|
publicKey: installationIdentity.publicKey,
|
|
472
688
|
}),
|
|
473
689
|
buildStatus: daemonBuildStatus,
|
|
690
|
+
releaseMaintenanceLease: (token) => ({
|
|
691
|
+
outcome: (() => {
|
|
692
|
+
const outcome = maintenanceLease.release(token);
|
|
693
|
+
if (outcome === "released")
|
|
694
|
+
admissionGate.reopen();
|
|
695
|
+
return outcome;
|
|
696
|
+
})(),
|
|
697
|
+
}),
|
|
474
698
|
pluginManagement: {
|
|
475
699
|
listPlugins: () => pluginManagement.list(),
|
|
476
700
|
setPluginEnabled: (pluginId, enabled) => pluginManagement.setEnabled(pluginId, enabled),
|
|
@@ -478,34 +702,25 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
478
702
|
prepareInstallation: (input, context) => pluginManagement.prepareInstallation(input, context),
|
|
479
703
|
commitInstallation: (token, input, context) => pluginManagement.commitInstallation(token, input, context),
|
|
480
704
|
cancelPreparation: (token) => pluginManagement.cancelPreparation(token),
|
|
705
|
+
settingsUi: (pluginId) => pluginManagement.settingsUi(pluginId),
|
|
706
|
+
settingsUiAsset: (pluginId, assetGeneration, assetPath) => pluginManagement.settingsUiAsset(pluginId, assetGeneration, assetPath),
|
|
707
|
+
callSettings: (pluginId, generation, method, params, context) => pluginManagement.callSettings(pluginId, generation, method, params, context),
|
|
481
708
|
dispose: () => pluginManagement.dispose(),
|
|
482
709
|
},
|
|
710
|
+
pluginMarketplaces: {
|
|
711
|
+
list: () => listPluginMarketplaces().map(toMarketplaceItem),
|
|
712
|
+
add: async (input, context) => toMarketplaceItem(await addPluginMarketplace(input.source, {
|
|
713
|
+
...(input.alias ? { alias: input.alias } : {}),
|
|
714
|
+
signal: context.signal,
|
|
715
|
+
})),
|
|
716
|
+
refresh: async (id, context) => toMarketplaceItem(await refreshPluginMarketplace(id, {
|
|
717
|
+
signal: context.signal,
|
|
718
|
+
})),
|
|
719
|
+
remove: (id) => removePluginMarketplace(id),
|
|
720
|
+
},
|
|
483
721
|
browserArtifacts: browserArtifactManagement,
|
|
484
722
|
maintenance: maintenanceManagement,
|
|
485
|
-
shutdownIfIdle
|
|
486
|
-
if (shutdownAccepted)
|
|
487
|
-
return { outcome: "accepted" };
|
|
488
|
-
const activity = {
|
|
489
|
-
...sessionRuntimeServices.sessionRuntimeIndex.activitySnapshot(),
|
|
490
|
-
activeTerminals: sessionTerminals.activeTerminalCount(),
|
|
491
|
-
activeBrowsers: sessionBrowsers.activeBrowserCount(),
|
|
492
|
-
};
|
|
493
|
-
if (daemonActivityBlocksShutdown(activity)) {
|
|
494
|
-
return { outcome: "busy", activity };
|
|
495
|
-
}
|
|
496
|
-
shutdownAccepted = true;
|
|
497
|
-
const shutdown = requestServerShutdown;
|
|
498
|
-
if (!shutdown) {
|
|
499
|
-
shutdownAccepted = false;
|
|
500
|
-
throw new Error("idle daemon shutdown was requested before server lifecycle was ready");
|
|
501
|
-
}
|
|
502
|
-
// Start admission fences in this event-loop turn, before another
|
|
503
|
-
// request or Direct dispatch can be accepted.
|
|
504
|
-
void shutdown().catch((error) => {
|
|
505
|
-
warn(`idle daemon shutdown failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
506
|
-
});
|
|
507
|
-
return { outcome: "accepted" };
|
|
508
|
-
},
|
|
723
|
+
shutdownIfIdle,
|
|
509
724
|
invokePluginCli,
|
|
510
725
|
};
|
|
511
726
|
const remoteRuntimeDispatcher = new RemoteRuntimeDispatcher({
|
|
@@ -516,6 +731,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
516
731
|
terminals: sessionTerminals,
|
|
517
732
|
browsers: sessionBrowsers,
|
|
518
733
|
providerClis,
|
|
734
|
+
projects: runtimeProjects,
|
|
519
735
|
onError: (error) => warn(`Remote Runtime dispatch failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
520
736
|
});
|
|
521
737
|
const remoteRuntimeAdmin = directConfig && directEncryptionIdentity
|
|
@@ -552,7 +768,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
552
768
|
};
|
|
553
769
|
server = await startServer({
|
|
554
770
|
config: appConfig,
|
|
555
|
-
loadInstances: () => resolveChannelInstances(warn),
|
|
556
771
|
control,
|
|
557
772
|
sessionLog,
|
|
558
773
|
sessionRegistry,
|
|
@@ -564,6 +779,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
564
779
|
runtimeTargetControl,
|
|
565
780
|
runtimeConnectionResolver: runtimeConnectionManager,
|
|
566
781
|
localSessionResources: machineSessions,
|
|
782
|
+
localMachineSessions: machineSessions,
|
|
567
783
|
providerClis,
|
|
568
784
|
sessionEmulators,
|
|
569
785
|
sessionLifecycle: sessionResourceLifecycle,
|
|
@@ -581,6 +797,11 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
581
797
|
registry: desktopBrowserHosts,
|
|
582
798
|
daemonInstanceId,
|
|
583
799
|
},
|
|
800
|
+
sessionPortalAuthorization: {
|
|
801
|
+
redeem: redeemSessionPortalTicket,
|
|
802
|
+
authorize: authorizeSessionPortalGrant,
|
|
803
|
+
ownsSession: sessionBelongsToPlugin,
|
|
804
|
+
},
|
|
584
805
|
});
|
|
585
806
|
baseShutdown = server.shutdown.bind(server);
|
|
586
807
|
if (directConfig && directEncryptionIdentity) {
|
|
@@ -743,8 +964,10 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
743
964
|
// A failed resource shutdown may leave plugin transports alive. Keep
|
|
744
965
|
// the process-scoped owner lease in that fail-closed state; it will be
|
|
745
966
|
// released by the OS when the process exits.
|
|
746
|
-
if (shutdownComplete)
|
|
967
|
+
if (shutdownComplete) {
|
|
747
968
|
await owner.release();
|
|
969
|
+
onShutdownComplete?.();
|
|
970
|
+
}
|
|
748
971
|
}
|
|
749
972
|
})();
|
|
750
973
|
return shutdownPromise;
|