@rynx-ai/daemon 0.1.11-beta.1 → 0.1.11-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
- package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -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 +54 -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 +504 -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 +1977 -0
- package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/runtime.js +131313 -0
- package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
- package/bundled-plugins/plugins/lark/package.json +57 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.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/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.js +2 -79
- package/dist/daemon-server.d.ts +7 -1
- package/dist/daemon-server.js +299 -84
- package/dist/db.js +147 -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 +60 -4
- package/dist/plugin-host-rpc.js +300 -50
- 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 +290 -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 +140 -92
- package/dist/plugin-supervisor.d.ts +50 -125
- package/dist/plugin-supervisor.js +682 -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 +7 -9
- package/dist/session-meta-store.js +28 -49
- package/dist/setup-service.d.ts +20 -0
- package/dist/setup-service.js +38 -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.d.ts
CHANGED
|
@@ -9,10 +9,16 @@ 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. */
|
|
15
18
|
acquireOwner?: () => Promise<DaemonOwnerLease>;
|
|
19
|
+
/** Runs after the exclusive daemon-owner lock is acquired and before plugin
|
|
20
|
+
* records are loaded or runners are started. */
|
|
21
|
+
preparePlugins?: () => Promise<void>;
|
|
16
22
|
/** Test/deployment seam for the always-available Direct Runtime socket. */
|
|
17
23
|
loadDirectConfig?: () => Promise<DirectRuntimeConfig>;
|
|
18
24
|
/** Test seam for listener lifecycle and bind failures. */
|
|
@@ -22,7 +28,7 @@ export interface StartRynxDaemonServerOptions {
|
|
|
22
28
|
/** Test seam for the App-only embedded Chromium process supervisor. */
|
|
23
29
|
createBrowserHostSupervisor?: (options: AppBrowserHostSupervisorOptions) => Pick<AppBrowserHostSupervisor, "ensureConnected" | "restart" | "stop">;
|
|
24
30
|
}
|
|
25
|
-
export declare function startRynxDaemonServer({ config, warn, writeEndpoint, acquireOwner, 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>>>;
|
|
26
32
|
export declare function createSupervisedAppSessionBrowserHost(desktop: SessionBrowserHost, supervisor: Pick<AppBrowserHostSupervisor, "ensureConnected" | "restart">): SessionBrowserHost;
|
|
27
33
|
/**
|
|
28
34
|
* Resolve the authenticated semantic target inside its owning Runtime and
|
package/dist/daemon-server.js
CHANGED
|
@@ -6,26 +6,30 @@
|
|
|
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, listRuntimeModels, RemoteRuntimeDispatcher, SessionBrowserService, SessionBrowserServiceError, SessionBrowserSurfaceCoordinator, SessionEmulatorService, startServer, startDirectRuntimeServer, } from "@rynx-ai/server";
|
|
21
21
|
import { APP_BROWSER_HOST_BOOTSTRAP_TYPE, AppBrowserHostSupervisor, parseAppBrowserHostLaunchConfig, } from "./app-browser-host-supervisor.js";
|
|
22
22
|
import { buildControlDeps } from "./control-deps.js";
|
|
23
23
|
import { createBrowserArtifactManagementService } from "./browser-artifact-management.js";
|
|
24
24
|
import { createDaemonBuildStatus } from "./daemon-build-status.js";
|
|
25
|
+
import { MaintenanceLeaseStore } from "./maintenance-lease.js";
|
|
25
26
|
import { BrowserRunnerSessionContextProvider } from "./browser-runner-session-context.js";
|
|
27
|
+
import { removeLegacyPluginSkillSnapshot, snapshotEnabledPluginSkillSources, } from "./plugin-skill-context.js";
|
|
28
|
+
import { installedDaemonVersion } from "./entry-path.js";
|
|
26
29
|
import { isChromeForTestingHostSupported } from "./chrome-for-testing-store.js";
|
|
27
30
|
import { ChromeInspectionManager, } from "./chrome-inspection-manager.js";
|
|
28
31
|
import { createHeadlessBrowserHost } from "./headless-browser-host.js";
|
|
32
|
+
import { db } from "./db.js";
|
|
29
33
|
import { acquireDaemonOwner } from "./daemon-owner.js";
|
|
30
34
|
import { DaemonDirectRuntimeAuthenticator } from "./direct-runtime-authenticator.js";
|
|
31
35
|
import { DurableEmbeddedBrowserProfileHost } from "./embedded-browser-profile-cleanup.js";
|
|
@@ -34,13 +38,15 @@ import { isDaemonDirectRuntimeHostingSupported, loadOrCreateDaemonDirectRuntimeE
|
|
|
34
38
|
import { cleanupLegacySessions } from "./migrations/cleanup-legacy-sessions.js";
|
|
35
39
|
import { createMaintenanceManagementService } from "./maintenance-management.js";
|
|
36
40
|
import { PluginManagementService } from "./plugin-management-service.js";
|
|
41
|
+
import { addPluginMarketplace, listPluginMarketplaces, refreshPluginMarketplace, removePluginMarketplace, } from "./plugin-marketplace.js";
|
|
37
42
|
import { PluginSupervisor } from "./plugin-supervisor.js";
|
|
38
43
|
import { pruneInactivePluginInstallations } from "./plugin-installer.js";
|
|
39
44
|
import { runPluginCliCommand } from "./plugin-cli.js";
|
|
40
|
-
import {
|
|
41
|
-
import { loadPlugins, resolveChannelInstances } from "./registry.js";
|
|
45
|
+
import { listPlugins } from "./plugin-store.js";
|
|
42
46
|
import { SqliteSessionLogStore } from "./session-log-store.js";
|
|
47
|
+
import { SqliteSessionForkStore } from "./session-fork-store.js";
|
|
43
48
|
import { SqliteSessionResourceStore } from "./session-resource-store.js";
|
|
49
|
+
import { createSessionFallbackWorkspace, discardSessionFallbackWorkspace, } from "./session-fallback-workspace.js";
|
|
44
50
|
import { SessionBrowserCapabilityStore } from "./session-browser-capability-store.js";
|
|
45
51
|
import { SqliteSessionEmulatorBindingStore } from "./session-emulator-binding-store.js";
|
|
46
52
|
import { sessionRegistry } from "./session-meta-store.js";
|
|
@@ -52,6 +58,7 @@ import { DaemonRuntimeConnectionManager } from "./remote-runtime-connection-mana
|
|
|
52
58
|
import { DaemonRuntimeTargetControl } from "./remote-runtime-target-control.js";
|
|
53
59
|
import { RemoteRuntimeTargetStore } from "./remote-runtime-target-store.js";
|
|
54
60
|
import { ProviderCliService } from "./provider-cli-service.js";
|
|
61
|
+
import { SqliteRuntimeProjectStore } from "./runtime-project-store.js";
|
|
55
62
|
const PLUGIN_CLI_OUTPUT_MAX_BYTES = 256 * 1024;
|
|
56
63
|
const BROWSER_INSPECT_OPEN_TIMEOUT_MS = 10_000;
|
|
57
64
|
const BROWSER_INSPECT_CLOSE_TIMEOUT_MS = 1_000;
|
|
@@ -59,8 +66,78 @@ const BROWSER_INSPECT_MAX_QUEUED_BYTES = 32 * 1024 * 1024;
|
|
|
59
66
|
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
67
|
const require = createRequire(import.meta.url);
|
|
61
68
|
const DAEMON_PACKAGE_VERSION = readDaemonPackageVersion();
|
|
69
|
+
async function resolveSessionExecutionSnapshot(input) {
|
|
70
|
+
return {
|
|
71
|
+
...await resolveExecutionSnapshot({
|
|
72
|
+
...input,
|
|
73
|
+
resolveDefaultModel: async (provider) => {
|
|
74
|
+
const models = await listRuntimeModels(input.config, provider);
|
|
75
|
+
return models?.data.find((candidate) => candidate.isDefault)?.model;
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
pluginSkills: snapshotEnabledPluginSkillSources(),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function resolveSessionWorkspace(projects, projectId, managedCwd, workspace) {
|
|
82
|
+
if (workspace) {
|
|
83
|
+
return sessionWorkspaceSnapshotSchema.parse(workspace);
|
|
84
|
+
}
|
|
85
|
+
if (projectId) {
|
|
86
|
+
const project = await projects.get(projectId);
|
|
87
|
+
if (!project) {
|
|
88
|
+
throw new MachineSessionServiceFailure("not_found", "project not found");
|
|
89
|
+
}
|
|
90
|
+
await assertWorkspaceDirectories(project.directories);
|
|
91
|
+
return sessionWorkspaceSnapshotSchema.parse({
|
|
92
|
+
cwd: project.primary,
|
|
93
|
+
allowedDirs: [
|
|
94
|
+
project.primary,
|
|
95
|
+
...project.directories.filter((directory) => directory !== project.primary),
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (managedCwd) {
|
|
100
|
+
let canonical;
|
|
101
|
+
try {
|
|
102
|
+
canonical = await realpath(managedCwd);
|
|
103
|
+
await assertWorkspaceDirectories([canonical]);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof MachineSessionServiceFailure)
|
|
107
|
+
throw error;
|
|
108
|
+
throw new MachineSessionServiceFailure("failed_precondition", "Session working directory is unavailable");
|
|
109
|
+
}
|
|
110
|
+
return sessionWorkspaceSnapshotSchema.parse({
|
|
111
|
+
cwd: canonical,
|
|
112
|
+
allowedDirs: [canonical],
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return await createSessionFallbackWorkspace();
|
|
116
|
+
}
|
|
117
|
+
async function assertWorkspaceDirectories(directories) {
|
|
118
|
+
try {
|
|
119
|
+
await Promise.all(directories.map(async (directory) => {
|
|
120
|
+
if (!(await stat(directory)).isDirectory())
|
|
121
|
+
throw new Error(directory);
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
throw new MachineSessionServiceFailure("failed_precondition", "one or more Project directories are unavailable");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function toMarketplaceItem(record) {
|
|
129
|
+
return {
|
|
130
|
+
id: record.marketplaceId,
|
|
131
|
+
source: record.sourceType,
|
|
132
|
+
builtIn: record.builtIn,
|
|
133
|
+
plugins: record.catalog.plugins.map((plugin) => ({ id: plugin.id })),
|
|
134
|
+
resolvedRevision: record.resolvedRevision,
|
|
135
|
+
refreshedAt: record.refreshedAt,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
62
138
|
export function daemonActivityBlocksShutdown(activity) {
|
|
63
|
-
return activity.runningTurns > 0
|
|
139
|
+
return activity.runningTurns > 0
|
|
140
|
+
|| activity.pendingInteractions > 0;
|
|
64
141
|
}
|
|
65
142
|
function defaultWarn(message) {
|
|
66
143
|
console.warn(JSON.stringify({ level: "warn", type: "channel-registry", msg: message }));
|
|
@@ -179,11 +256,24 @@ async function removeControlEndpointForCurrentProcess() {
|
|
|
179
256
|
// Best effort only; stale endpoint files are ignored by the client fallback.
|
|
180
257
|
}
|
|
181
258
|
}
|
|
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), } = {}) {
|
|
259
|
+
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
260
|
const owner = await acquireOwner();
|
|
184
261
|
let ownerManagedByServer = false;
|
|
185
262
|
try {
|
|
263
|
+
await preparePlugins?.();
|
|
186
264
|
const appConfig = config ?? loadConfig();
|
|
265
|
+
const admissionGate = new CloseableAdmissionGate();
|
|
266
|
+
let shutdownAccepted = false;
|
|
267
|
+
const maintenanceLease = new MaintenanceLeaseStore({
|
|
268
|
+
// Expiry restores the gate primitive for a process that outlives its
|
|
269
|
+
// upgrader. The independent accepted-shutdown fence below still prevents
|
|
270
|
+
// new work after an irreversible server shutdown has begun.
|
|
271
|
+
onExpired: () => admissionGate.reopen(),
|
|
272
|
+
});
|
|
273
|
+
const admissionOpen = () => !shutdownAccepted && !maintenanceLease.isActive();
|
|
274
|
+
const reserveAdmission = () => !admissionOpen()
|
|
275
|
+
? undefined
|
|
276
|
+
: admissionGate.tryReserve();
|
|
187
277
|
const appBrowserHostLaunch = parseAppBrowserHostLaunchConfig();
|
|
188
278
|
const directHostingSupported = isDaemonDirectRuntimeHostingSupported();
|
|
189
279
|
const runtimeBrowserSupported = appBrowserHostLaunch !== undefined || isChromeForTestingHostSupported();
|
|
@@ -215,11 +305,13 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
215
305
|
"semantic.session.agent-options.v1",
|
|
216
306
|
"semantic.session.launch-options.v2",
|
|
217
307
|
"semantic.session.create.v1",
|
|
308
|
+
"semantic.session.fork.v1",
|
|
218
309
|
"semantic.session.message.v1",
|
|
219
310
|
"semantic.session.resources.v1",
|
|
220
311
|
"semantic.session.message-queue.v1",
|
|
221
312
|
"semantic.session.delete.v1",
|
|
222
313
|
"semantic.session.interaction.v1",
|
|
314
|
+
"semantic.project.manage.v1",
|
|
223
315
|
"semantic.provider-cli.status.v1",
|
|
224
316
|
...(runtimeBrowserSupported ? ["semantic.browser.v1"] : []),
|
|
225
317
|
...(runtimeBrowserSupported && directHostingSupported
|
|
@@ -259,8 +351,11 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
259
351
|
catch (error) {
|
|
260
352
|
warn(`plugin package cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
261
353
|
}
|
|
262
|
-
const pluginSupervisor = new PluginSupervisor(
|
|
354
|
+
const pluginSupervisor = new PluginSupervisor(listPlugins(), {
|
|
263
355
|
daemonInstanceId,
|
|
356
|
+
productVersion: controlEndpointDistributionMetadata().productVersion,
|
|
357
|
+
cliVersion: boundedEnvironmentMetadata(process.env.RYNX_CLI_VERSION, 128)
|
|
358
|
+
?? installedDaemonVersion(),
|
|
264
359
|
log: (entry) => {
|
|
265
360
|
const output = entry.level === "error"
|
|
266
361
|
? console.error
|
|
@@ -270,39 +365,14 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
270
365
|
output(JSON.stringify(entry));
|
|
271
366
|
},
|
|
272
367
|
});
|
|
273
|
-
const pluginManagement = new PluginManagementService(
|
|
368
|
+
const pluginManagement = new PluginManagementService(undefined, {
|
|
369
|
+
supervisor: pluginSupervisor,
|
|
370
|
+
});
|
|
274
371
|
const browserArtifactManagement = createBrowserArtifactManagementService();
|
|
275
372
|
const maintenanceManagement = createMaintenanceManagementService({
|
|
276
373
|
codexStorePath: appConfig.AGENT_SESSION_STORE_PATH,
|
|
277
374
|
});
|
|
278
|
-
await loadPlugins(pluginSupervisor, warn);
|
|
279
375
|
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
376
|
const invokePluginCli = async ({ pluginId, args, stdin }, { signal }) => {
|
|
307
377
|
const result = await runPluginCliCommand(pluginId, args, {
|
|
308
378
|
stdio: "pipe",
|
|
@@ -310,14 +380,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
310
380
|
captureOutputBytes: PLUGIN_CLI_OUTPUT_MAX_BYTES,
|
|
311
381
|
signal,
|
|
312
382
|
});
|
|
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
383
|
const output = result.output;
|
|
322
384
|
return {
|
|
323
385
|
code: result.code,
|
|
@@ -326,6 +388,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
326
388
|
truncated: Boolean(output?.stdoutTruncated || output?.stderrTruncated),
|
|
327
389
|
};
|
|
328
390
|
};
|
|
391
|
+
let machineSessions;
|
|
329
392
|
const pluginRuntime = {
|
|
330
393
|
bindHostServices: (services) => pluginSupervisor.bindHostServices({
|
|
331
394
|
...services,
|
|
@@ -335,10 +398,32 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
335
398
|
publicKey: installationIdentity.publicKey,
|
|
336
399
|
sign: installationIdentity.sign,
|
|
337
400
|
},
|
|
401
|
+
sessionLaunch: {
|
|
402
|
+
resolve: async (selection) => {
|
|
403
|
+
const workspace = await resolveSessionWorkspace(runtimeProjects, selection.projectId, selection.managedCwd, selection.workspace);
|
|
404
|
+
return {
|
|
405
|
+
workspace,
|
|
406
|
+
execution: await resolveSessionExecutionSnapshot({
|
|
407
|
+
config: appConfig,
|
|
408
|
+
...(selection.agent ? { agentName: selection.agent } : {}),
|
|
409
|
+
...(selection.config ? { spec: selection.config } : {}),
|
|
410
|
+
...((selection.provider || (!selection.agent && !selection.config))
|
|
411
|
+
? { provider: selection.provider ?? appConfig.DEFAULT_RUNTIME }
|
|
412
|
+
: {}),
|
|
413
|
+
...(selection.model ? { model: selection.model } : {}),
|
|
414
|
+
...(selection.reasoningEffort
|
|
415
|
+
? { reasoningEffort: selection.reasoningEffort }
|
|
416
|
+
: {}),
|
|
417
|
+
cwd: workspace.cwd,
|
|
418
|
+
}),
|
|
419
|
+
};
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
sessionFork: (input) => machineSessions.fork(input),
|
|
423
|
+
admissionOpen,
|
|
424
|
+
admissionReserve: reserveAdmission,
|
|
338
425
|
}),
|
|
339
426
|
startPluginRuntimes: pluginSupervisor.startPluginRuntimes.bind(pluginSupervisor),
|
|
340
|
-
reloadPluginRuntime,
|
|
341
|
-
ensurePluginRuntime,
|
|
342
427
|
statusSnapshot: pluginSupervisor.statusSnapshot.bind(pluginSupervisor),
|
|
343
428
|
dispose: pluginSupervisor.dispose.bind(pluginSupervisor),
|
|
344
429
|
};
|
|
@@ -346,6 +431,8 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
346
431
|
const directConnections = new DirectRuntimeConnectionHub();
|
|
347
432
|
const sessionLog = new SqliteSessionLogStore();
|
|
348
433
|
const sessionResources = new SqliteSessionResourceStore();
|
|
434
|
+
const sessionForks = new SqliteSessionForkStore();
|
|
435
|
+
const runtimeProjects = new SqliteRuntimeProjectStore();
|
|
349
436
|
const providerClis = new ProviderCliService();
|
|
350
437
|
const sessionBrowserCapabilities = new SessionBrowserCapabilityStore();
|
|
351
438
|
const durableDesktopBrowserHost = new DurableEmbeddedBrowserProfileHost(desktopBrowserHosts, { warn });
|
|
@@ -357,16 +444,21 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
357
444
|
config: appConfig,
|
|
358
445
|
sessionLog,
|
|
359
446
|
sessionContextProvider: browserRunnerSessionContexts,
|
|
447
|
+
admissionOpen,
|
|
448
|
+
admissionReserve: reserveAdmission,
|
|
360
449
|
onMirrorError: (error, sessionId) => warn(`Session mirror failed for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`),
|
|
361
450
|
});
|
|
451
|
+
const sessionBrowserHost = appBrowserHostSupervisor
|
|
452
|
+
? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
|
|
453
|
+
: createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost());
|
|
362
454
|
const sessionBrowsers = new SessionBrowserService({
|
|
363
|
-
host:
|
|
364
|
-
? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
|
|
365
|
-
: createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost()),
|
|
455
|
+
host: sessionBrowserHost,
|
|
366
456
|
sessions: {
|
|
367
457
|
exists: async (sessionId) => Boolean(sessionRegistry.get(sessionId) ??
|
|
368
458
|
await sessionRuntimeServices.sessionStore.get(sessionId)),
|
|
369
459
|
},
|
|
460
|
+
}, {
|
|
461
|
+
admissionReserve: reserveAdmission,
|
|
370
462
|
});
|
|
371
463
|
const sessionEmulators = control.emulator
|
|
372
464
|
? new SessionEmulatorService({
|
|
@@ -422,14 +514,35 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
422
514
|
sessionEmulators?.cleanupSession(sessionId),
|
|
423
515
|
]);
|
|
424
516
|
},
|
|
425
|
-
afterDelete: (sessionId) => {
|
|
517
|
+
afterDelete: async (sessionId) => {
|
|
426
518
|
sessionBrowserCapabilities.revoke(sessionId);
|
|
519
|
+
removeLegacyPluginSkillSnapshot(sessionId);
|
|
520
|
+
await sessionRuntimeServices.sessionStore.delete(sessionId);
|
|
427
521
|
},
|
|
428
522
|
};
|
|
429
|
-
const
|
|
523
|
+
const deletedSessions = db()
|
|
524
|
+
.prepare("SELECT session_id AS sessionId FROM session_snapshot_cleanup ORDER BY session_id")
|
|
525
|
+
.all();
|
|
526
|
+
for (const { sessionId } of deletedSessions) {
|
|
527
|
+
try {
|
|
528
|
+
await Promise.all([
|
|
529
|
+
sessionBrowsers.cleanupSession(sessionId),
|
|
530
|
+
sessionEmulators?.cleanupSession(sessionId),
|
|
531
|
+
]);
|
|
532
|
+
sessionResources.deleteSession(sessionId);
|
|
533
|
+
removeLegacyPluginSkillSnapshot(sessionId);
|
|
534
|
+
await sessionRuntimeServices.sessionStore.delete(sessionId);
|
|
535
|
+
db().prepare("DELETE FROM session_snapshot_cleanup WHERE session_id = ?").run(sessionId);
|
|
536
|
+
}
|
|
537
|
+
catch (error) {
|
|
538
|
+
warn(`Legacy Session artifact cleanup will retry for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
machineSessions = new MachineSessionService({
|
|
430
542
|
registry: sessionRegistry,
|
|
431
543
|
log: sessionLog,
|
|
432
544
|
events: sessionRuntimeServices.sessionBus,
|
|
545
|
+
publishEvent: sessionRuntimeServices.publishSessionEvent,
|
|
433
546
|
runtimeState: sessionRuntimeServices.sessionRuntimeIndex,
|
|
434
547
|
interruption: {
|
|
435
548
|
interrupt: (sessionId) => sessionRuntimeServices.runnerManager.interruptLiveSession(sessionId),
|
|
@@ -440,29 +553,129 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
440
553
|
},
|
|
441
554
|
pendingMessages: sessionPendingMessageStore,
|
|
442
555
|
resources: sessionResources,
|
|
556
|
+
forks: sessionForks,
|
|
443
557
|
execution: {
|
|
444
558
|
runtime: sessionRuntimeServices.conversationRuntime,
|
|
559
|
+
resolve: ({ agent, provider, model, reasoningEffort, cwd }) => resolveSessionExecutionSnapshot({
|
|
560
|
+
config: appConfig,
|
|
561
|
+
...(agent ? { agentName: agent } : {}),
|
|
562
|
+
...(provider ? { provider } : {}),
|
|
563
|
+
...(model ? { model } : {}),
|
|
564
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
565
|
+
cwd,
|
|
566
|
+
}),
|
|
445
567
|
runner: sessionRuntimeServices.runnerManager,
|
|
446
|
-
sessionStore: sessionRuntimeServices.sessionStore,
|
|
447
568
|
},
|
|
569
|
+
workspace: {
|
|
570
|
+
resolve: (projectId) => resolveSessionWorkspace(runtimeProjects, projectId),
|
|
571
|
+
discardUnbound: discardSessionFallbackWorkspace,
|
|
572
|
+
},
|
|
573
|
+
}, {
|
|
574
|
+
admissionOpen,
|
|
575
|
+
admissionReserve: reserveAdmission,
|
|
448
576
|
});
|
|
449
577
|
const directAuthenticator = new DaemonDirectRuntimeAuthenticator(installationIdentity, remoteRuntime, remoteRuntimeAccess);
|
|
450
578
|
const sessionTerminals = createRunnerSessionTerminalHost({
|
|
451
579
|
runnerManager: sessionRuntimeServices.runnerManager,
|
|
580
|
+
admissionReserve: reserveAdmission,
|
|
452
581
|
resolveLiveSession: async (sessionId) => {
|
|
453
|
-
const bound = await sessionRuntimeServices.sessionStore.get(sessionId);
|
|
454
582
|
const registered = sessionRegistry.get(sessionId);
|
|
455
|
-
|
|
456
|
-
if ((!bound && !registered) ||
|
|
457
|
-
!cwd ||
|
|
583
|
+
if (!registered ||
|
|
458
584
|
!sessionRuntimeServices.runnerManager.hasLiveSession(sessionId)) {
|
|
459
585
|
return undefined;
|
|
460
586
|
}
|
|
461
|
-
return { cwd };
|
|
587
|
+
return { cwd: registered.workspace.cwd };
|
|
462
588
|
},
|
|
463
589
|
});
|
|
464
|
-
let shutdownAccepted = false;
|
|
465
590
|
let requestServerShutdown;
|
|
591
|
+
let shutdownAttempt;
|
|
592
|
+
let shutdownAttemptLeaseToken;
|
|
593
|
+
const shutdownIfIdle = (maintenanceLeaseToken) => {
|
|
594
|
+
if (maintenanceLease.isActive()) {
|
|
595
|
+
if (!maintenanceLeaseToken || !maintenanceLease.isHeldBy(maintenanceLeaseToken)) {
|
|
596
|
+
return Promise.reject(new Error("a different maintenance lease is already active"));
|
|
597
|
+
}
|
|
598
|
+
// The previous daemon may have persisted the lease and exited after
|
|
599
|
+
// its 202 response was lost. A replacement process holding the same
|
|
600
|
+
// token must perform its own close/drain/shutdown; returning accepted
|
|
601
|
+
// without scheduling this PID would strand the updater waiting for a
|
|
602
|
+
// process that can never exit.
|
|
603
|
+
}
|
|
604
|
+
if (shutdownAccepted) {
|
|
605
|
+
if (maintenanceLeaseToken) {
|
|
606
|
+
maintenanceLease.acquire(maintenanceLeaseToken);
|
|
607
|
+
return Promise.resolve({
|
|
608
|
+
outcome: "accepted",
|
|
609
|
+
maintenanceLease: "active",
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
return Promise.resolve({ outcome: "accepted" });
|
|
613
|
+
}
|
|
614
|
+
if (shutdownAttempt) {
|
|
615
|
+
if (maintenanceLeaseToken === shutdownAttemptLeaseToken) {
|
|
616
|
+
return shutdownAttempt;
|
|
617
|
+
}
|
|
618
|
+
return Promise.reject(new Error("another idle shutdown check is already in progress"));
|
|
619
|
+
}
|
|
620
|
+
shutdownAttemptLeaseToken = maintenanceLeaseToken;
|
|
621
|
+
const attempt = (async () => {
|
|
622
|
+
await admissionGate.closeAndDrain();
|
|
623
|
+
const runtimeActivity = sessionRuntimeServices.sessionRuntimeIndex.activitySnapshot();
|
|
624
|
+
const activity = {
|
|
625
|
+
...runtimeActivity,
|
|
626
|
+
// A terminal submission keeps its own admission reservation until the
|
|
627
|
+
// first response or native rotation is visible. Failed process-tree
|
|
628
|
+
// cleanup releases the reservation but remains pinned here, so an
|
|
629
|
+
// idle check returns busy instead of hanging or killing hidden work.
|
|
630
|
+
runningTurns: runtimeActivity.runningTurns
|
|
631
|
+
+ sessionRuntimeServices.runnerManager.pendingTerminalInputCount(),
|
|
632
|
+
activeTerminals: sessionTerminals.activeTerminalCount(),
|
|
633
|
+
activeBrowsers: sessionBrowsers.activeBrowserCount(),
|
|
634
|
+
};
|
|
635
|
+
if (daemonActivityBlocksShutdown(activity)) {
|
|
636
|
+
admissionGate.reopen();
|
|
637
|
+
return { outcome: "busy", activity };
|
|
638
|
+
}
|
|
639
|
+
const shutdown = requestServerShutdown;
|
|
640
|
+
if (!shutdown) {
|
|
641
|
+
admissionGate.reopen();
|
|
642
|
+
throw new Error("idle daemon shutdown was requested before server lifecycle was ready");
|
|
643
|
+
}
|
|
644
|
+
const acquiredLease = maintenanceLeaseToken
|
|
645
|
+
? maintenanceLease.acquire(maintenanceLeaseToken)
|
|
646
|
+
: false;
|
|
647
|
+
shutdownAccepted = true;
|
|
648
|
+
try {
|
|
649
|
+
void shutdown().catch((error) => {
|
|
650
|
+
shutdownAccepted = false;
|
|
651
|
+
if (acquiredLease && maintenanceLeaseToken) {
|
|
652
|
+
maintenanceLease.release(maintenanceLeaseToken);
|
|
653
|
+
}
|
|
654
|
+
admissionGate.reopen();
|
|
655
|
+
warn(`idle daemon shutdown failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
shutdownAccepted = false;
|
|
660
|
+
if (acquiredLease && maintenanceLeaseToken) {
|
|
661
|
+
maintenanceLease.release(maintenanceLeaseToken);
|
|
662
|
+
}
|
|
663
|
+
admissionGate.reopen();
|
|
664
|
+
throw error;
|
|
665
|
+
}
|
|
666
|
+
return maintenanceLeaseToken
|
|
667
|
+
? { outcome: "accepted", maintenanceLease: "active" }
|
|
668
|
+
: { outcome: "accepted" };
|
|
669
|
+
})();
|
|
670
|
+
shutdownAttempt = attempt;
|
|
671
|
+
void attempt.finally(() => {
|
|
672
|
+
if (shutdownAttempt === attempt) {
|
|
673
|
+
shutdownAttempt = undefined;
|
|
674
|
+
shutdownAttemptLeaseToken = undefined;
|
|
675
|
+
}
|
|
676
|
+
}).catch(() => undefined);
|
|
677
|
+
return attempt;
|
|
678
|
+
};
|
|
466
679
|
const daemonManagement = {
|
|
467
680
|
managementToken,
|
|
468
681
|
identity: () => ({
|
|
@@ -471,6 +684,14 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
471
684
|
publicKey: installationIdentity.publicKey,
|
|
472
685
|
}),
|
|
473
686
|
buildStatus: daemonBuildStatus,
|
|
687
|
+
releaseMaintenanceLease: (token) => ({
|
|
688
|
+
outcome: (() => {
|
|
689
|
+
const outcome = maintenanceLease.release(token);
|
|
690
|
+
if (outcome === "released")
|
|
691
|
+
admissionGate.reopen();
|
|
692
|
+
return outcome;
|
|
693
|
+
})(),
|
|
694
|
+
}),
|
|
474
695
|
pluginManagement: {
|
|
475
696
|
listPlugins: () => pluginManagement.list(),
|
|
476
697
|
setPluginEnabled: (pluginId, enabled) => pluginManagement.setEnabled(pluginId, enabled),
|
|
@@ -478,34 +699,25 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
478
699
|
prepareInstallation: (input, context) => pluginManagement.prepareInstallation(input, context),
|
|
479
700
|
commitInstallation: (token, input, context) => pluginManagement.commitInstallation(token, input, context),
|
|
480
701
|
cancelPreparation: (token) => pluginManagement.cancelPreparation(token),
|
|
702
|
+
settingsUi: (pluginId) => pluginManagement.settingsUi(pluginId),
|
|
703
|
+
settingsUiAsset: (pluginId, assetGeneration, assetPath) => pluginManagement.settingsUiAsset(pluginId, assetGeneration, assetPath),
|
|
704
|
+
callSettings: (pluginId, generation, method, params, context) => pluginManagement.callSettings(pluginId, generation, method, params, context),
|
|
481
705
|
dispose: () => pluginManagement.dispose(),
|
|
482
706
|
},
|
|
707
|
+
pluginMarketplaces: {
|
|
708
|
+
list: () => listPluginMarketplaces().map(toMarketplaceItem),
|
|
709
|
+
add: async (input, context) => toMarketplaceItem(await addPluginMarketplace(input.source, {
|
|
710
|
+
...(input.alias ? { alias: input.alias } : {}),
|
|
711
|
+
signal: context.signal,
|
|
712
|
+
})),
|
|
713
|
+
refresh: async (id, context) => toMarketplaceItem(await refreshPluginMarketplace(id, {
|
|
714
|
+
signal: context.signal,
|
|
715
|
+
})),
|
|
716
|
+
remove: (id) => removePluginMarketplace(id),
|
|
717
|
+
},
|
|
483
718
|
browserArtifacts: browserArtifactManagement,
|
|
484
719
|
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
|
-
},
|
|
720
|
+
shutdownIfIdle,
|
|
509
721
|
invokePluginCli,
|
|
510
722
|
};
|
|
511
723
|
const remoteRuntimeDispatcher = new RemoteRuntimeDispatcher({
|
|
@@ -516,6 +728,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
516
728
|
terminals: sessionTerminals,
|
|
517
729
|
browsers: sessionBrowsers,
|
|
518
730
|
providerClis,
|
|
731
|
+
projects: runtimeProjects,
|
|
519
732
|
onError: (error) => warn(`Remote Runtime dispatch failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
520
733
|
});
|
|
521
734
|
const remoteRuntimeAdmin = directConfig && directEncryptionIdentity
|
|
@@ -552,7 +765,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
552
765
|
};
|
|
553
766
|
server = await startServer({
|
|
554
767
|
config: appConfig,
|
|
555
|
-
loadInstances: () => resolveChannelInstances(warn),
|
|
556
768
|
control,
|
|
557
769
|
sessionLog,
|
|
558
770
|
sessionRegistry,
|
|
@@ -564,6 +776,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
564
776
|
runtimeTargetControl,
|
|
565
777
|
runtimeConnectionResolver: runtimeConnectionManager,
|
|
566
778
|
localSessionResources: machineSessions,
|
|
779
|
+
localMachineSessions: machineSessions,
|
|
567
780
|
providerClis,
|
|
568
781
|
sessionEmulators,
|
|
569
782
|
sessionLifecycle: sessionResourceLifecycle,
|
|
@@ -743,8 +956,10 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
|
|
|
743
956
|
// A failed resource shutdown may leave plugin transports alive. Keep
|
|
744
957
|
// the process-scoped owner lease in that fail-closed state; it will be
|
|
745
958
|
// released by the OS when the process exits.
|
|
746
|
-
if (shutdownComplete)
|
|
959
|
+
if (shutdownComplete) {
|
|
747
960
|
await owner.release();
|
|
961
|
+
onShutdownComplete?.();
|
|
962
|
+
}
|
|
748
963
|
}
|
|
749
964
|
})();
|
|
750
965
|
return shutdownPromise;
|