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

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 (117) hide show
  1. package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
  2. package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -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 +54 -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 +504 -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 +1977 -0
  43. package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
  44. package/bundled-plugins/plugins/lark/dist/runtime.js +131316 -0
  45. package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
  46. package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
  47. package/bundled-plugins/plugins/lark/package.json +57 -0
  48. package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
  49. package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.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/bundled-plugins.d.ts +15 -0
  64. package/dist/bundled-plugins.js +134 -0
  65. package/dist/cli.js +26 -208
  66. package/dist/control-deps.js +2 -79
  67. package/dist/daemon-server.d.ts +4 -1
  68. package/dist/daemon-server.js +167 -57
  69. package/dist/db.js +145 -124
  70. package/dist/index-daemon.js +25 -4
  71. package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
  72. package/dist/migrations/cleanup-legacy-sessions.js +33 -15
  73. package/dist/official-plugins.d.ts +2 -0
  74. package/dist/official-plugins.js +2 -0
  75. package/dist/plugin-cli.d.ts +1 -3
  76. package/dist/plugin-cli.js +56 -45
  77. package/dist/plugin-host-leases.d.ts +4 -0
  78. package/dist/plugin-host-leases.js +7 -0
  79. package/dist/plugin-host-rpc.d.ts +42 -4
  80. package/dist/plugin-host-rpc.js +144 -34
  81. package/dist/plugin-installer.d.ts +24 -55
  82. package/dist/plugin-installer.js +202 -415
  83. package/dist/plugin-management-service.d.ts +30 -23
  84. package/dist/plugin-management-service.js +290 -105
  85. package/dist/plugin-marketplace.d.ts +35 -0
  86. package/dist/plugin-marketplace.js +299 -0
  87. package/dist/plugin-package.d.ts +22 -24
  88. package/dist/plugin-package.js +520 -571
  89. package/dist/plugin-skill-context.d.ts +4 -0
  90. package/dist/plugin-skill-context.js +35 -0
  91. package/dist/plugin-store.d.ts +36 -37
  92. package/dist/plugin-store.js +140 -92
  93. package/dist/plugin-supervisor.d.ts +45 -125
  94. package/dist/plugin-supervisor.js +516 -1053
  95. package/dist/pm2.js +15 -10
  96. package/dist/runtime-project-store.d.ts +9 -0
  97. package/dist/runtime-project-store.js +83 -0
  98. package/dist/session-fallback-workspace.d.ts +22 -0
  99. package/dist/session-fallback-workspace.js +120 -0
  100. package/dist/session-fork-store.d.ts +41 -0
  101. package/dist/session-fork-store.js +288 -0
  102. package/dist/session-launch-operations.d.ts +14 -2
  103. package/dist/session-launch-operations.js +34 -2
  104. package/dist/session-meta-store.d.ts +7 -9
  105. package/dist/session-meta-store.js +28 -49
  106. package/dist/setup.js +26 -14
  107. package/package.json +14 -11
  108. package/dist/channel-store.d.ts +0 -22
  109. package/dist/channel-store.js +0 -65
  110. package/dist/instance-store.d.ts +0 -38
  111. package/dist/instance-store.js +0 -85
  112. package/dist/plugin-install-restart.d.ts +0 -13
  113. package/dist/plugin-install-restart.js +0 -24
  114. package/dist/plugin-runtime-control.d.ts +0 -2
  115. package/dist/plugin-runtime-control.js +0 -37
  116. package/dist/registry.d.ts +0 -10
  117. package/dist/registry.js +0 -52
@@ -6,26 +6,28 @@
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 { 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
25
  import { BrowserRunnerSessionContextProvider } from "./browser-runner-session-context.js";
26
+ import { removeLegacyPluginSkillSnapshot, snapshotEnabledPluginSkillSources, } from "./plugin-skill-context.js";
26
27
  import { isChromeForTestingHostSupported } from "./chrome-for-testing-store.js";
27
28
  import { ChromeInspectionManager, } from "./chrome-inspection-manager.js";
28
29
  import { createHeadlessBrowserHost } from "./headless-browser-host.js";
30
+ import { db } from "./db.js";
29
31
  import { acquireDaemonOwner } from "./daemon-owner.js";
30
32
  import { DaemonDirectRuntimeAuthenticator } from "./direct-runtime-authenticator.js";
31
33
  import { DurableEmbeddedBrowserProfileHost } from "./embedded-browser-profile-cleanup.js";
@@ -34,13 +36,15 @@ import { isDaemonDirectRuntimeHostingSupported, loadOrCreateDaemonDirectRuntimeE
34
36
  import { cleanupLegacySessions } from "./migrations/cleanup-legacy-sessions.js";
35
37
  import { createMaintenanceManagementService } from "./maintenance-management.js";
36
38
  import { PluginManagementService } from "./plugin-management-service.js";
39
+ import { addPluginMarketplace, listPluginMarketplaces, refreshPluginMarketplace, removePluginMarketplace, } from "./plugin-marketplace.js";
37
40
  import { PluginSupervisor } from "./plugin-supervisor.js";
38
41
  import { pruneInactivePluginInstallations } from "./plugin-installer.js";
39
42
  import { runPluginCliCommand } from "./plugin-cli.js";
40
- import { getPlugin, isRunnablePluginRecord, listEnabledPlugins } from "./plugin-store.js";
41
- import { loadPlugins, resolveChannelInstances } from "./registry.js";
43
+ import { listPlugins } from "./plugin-store.js";
42
44
  import { SqliteSessionLogStore } from "./session-log-store.js";
45
+ import { SqliteSessionForkStore } from "./session-fork-store.js";
43
46
  import { SqliteSessionResourceStore } from "./session-resource-store.js";
47
+ import { createSessionFallbackWorkspace, discardSessionFallbackWorkspace, } from "./session-fallback-workspace.js";
44
48
  import { SessionBrowserCapabilityStore } from "./session-browser-capability-store.js";
45
49
  import { SqliteSessionEmulatorBindingStore } from "./session-emulator-binding-store.js";
46
50
  import { sessionRegistry } from "./session-meta-store.js";
@@ -52,6 +56,7 @@ import { DaemonRuntimeConnectionManager } from "./remote-runtime-connection-mana
52
56
  import { DaemonRuntimeTargetControl } from "./remote-runtime-target-control.js";
53
57
  import { RemoteRuntimeTargetStore } from "./remote-runtime-target-store.js";
54
58
  import { ProviderCliService } from "./provider-cli-service.js";
59
+ import { SqliteRuntimeProjectStore } from "./runtime-project-store.js";
55
60
  const PLUGIN_CLI_OUTPUT_MAX_BYTES = 256 * 1024;
56
61
  const BROWSER_INSPECT_OPEN_TIMEOUT_MS = 10_000;
57
62
  const BROWSER_INSPECT_CLOSE_TIMEOUT_MS = 1_000;
@@ -59,6 +64,72 @@ const BROWSER_INSPECT_MAX_QUEUED_BYTES = 32 * 1024 * 1024;
59
64
  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
65
  const require = createRequire(import.meta.url);
61
66
  const DAEMON_PACKAGE_VERSION = readDaemonPackageVersion();
67
+ async function resolveSessionExecutionSnapshot(input) {
68
+ return {
69
+ ...await resolveExecutionSnapshot({
70
+ ...input,
71
+ resolveDefaultModel: async (provider) => {
72
+ const models = await listRuntimeModels(input.config, provider);
73
+ return models?.data.find((candidate) => candidate.isDefault)?.model;
74
+ },
75
+ }),
76
+ pluginSkills: snapshotEnabledPluginSkillSources(),
77
+ };
78
+ }
79
+ async function resolveSessionWorkspace(projects, projectId, managedCwd) {
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
134
  return activity.runningTurns > 0 || activity.pendingInteractions > 0;
64
135
  }
@@ -179,10 +250,11 @@ async function removeControlEndpointForCurrentProcess() {
179
250
  // Best effort only; stale endpoint files are ignored by the client fallback.
180
251
  }
181
252
  }
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), } = {}) {
253
+ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeEndpoint = writeControlEndpoint, acquireOwner = acquireDaemonOwner, preparePlugins, loadDirectConfig = loadDirectRuntimeConfig, startDirectServer = startDirectRuntimeServer, createChromeInspectionManager = (options) => ChromeInspectionManager.create(options), createBrowserHostSupervisor = (options) => new AppBrowserHostSupervisor(options), } = {}) {
183
254
  const owner = await acquireOwner();
184
255
  let ownerManagedByServer = false;
185
256
  try {
257
+ await preparePlugins?.();
186
258
  const appConfig = config ?? loadConfig();
187
259
  const appBrowserHostLaunch = parseAppBrowserHostLaunchConfig();
188
260
  const directHostingSupported = isDaemonDirectRuntimeHostingSupported();
@@ -215,11 +287,13 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
215
287
  "semantic.session.agent-options.v1",
216
288
  "semantic.session.launch-options.v2",
217
289
  "semantic.session.create.v1",
290
+ "semantic.session.fork.v1",
218
291
  "semantic.session.message.v1",
219
292
  "semantic.session.resources.v1",
220
293
  "semantic.session.message-queue.v1",
221
294
  "semantic.session.delete.v1",
222
295
  "semantic.session.interaction.v1",
296
+ "semantic.project.manage.v1",
223
297
  "semantic.provider-cli.status.v1",
224
298
  ...(runtimeBrowserSupported ? ["semantic.browser.v1"] : []),
225
299
  ...(runtimeBrowserSupported && directHostingSupported
@@ -259,7 +333,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
259
333
  catch (error) {
260
334
  warn(`plugin package cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
261
335
  }
262
- const pluginSupervisor = new PluginSupervisor(listEnabledPlugins(), {
336
+ const pluginSupervisor = new PluginSupervisor(listPlugins(), {
263
337
  daemonInstanceId,
264
338
  log: (entry) => {
265
339
  const output = entry.level === "error"
@@ -270,39 +344,14 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
270
344
  output(JSON.stringify(entry));
271
345
  },
272
346
  });
273
- const pluginManagement = new PluginManagementService();
347
+ const pluginManagement = new PluginManagementService(undefined, {
348
+ supervisor: pluginSupervisor,
349
+ });
274
350
  const browserArtifactManagement = createBrowserArtifactManagementService();
275
351
  const maintenanceManagement = createMaintenanceManagementService({
276
352
  codexStorePath: appConfig.AGENT_SESSION_STORE_PATH,
277
353
  });
278
- await loadPlugins(pluginSupervisor, warn);
279
354
  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
355
  const invokePluginCli = async ({ pluginId, args, stdin }, { signal }) => {
307
356
  const result = await runPluginCliCommand(pluginId, args, {
308
357
  stdio: "pipe",
@@ -310,14 +359,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
310
359
  captureOutputBytes: PLUGIN_CLI_OUTPUT_MAX_BYTES,
311
360
  signal,
312
361
  });
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
362
  const output = result.output;
322
363
  return {
323
364
  code: result.code,
@@ -326,6 +367,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
326
367
  truncated: Boolean(output?.stdoutTruncated || output?.stderrTruncated),
327
368
  };
328
369
  };
370
+ let machineSessions;
329
371
  const pluginRuntime = {
330
372
  bindHostServices: (services) => pluginSupervisor.bindHostServices({
331
373
  ...services,
@@ -335,10 +377,30 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
335
377
  publicKey: installationIdentity.publicKey,
336
378
  sign: installationIdentity.sign,
337
379
  },
380
+ sessionLaunch: {
381
+ resolve: async (selection) => {
382
+ const workspace = await resolveSessionWorkspace(runtimeProjects, selection.projectId, selection.managedCwd);
383
+ return {
384
+ workspace,
385
+ execution: await resolveSessionExecutionSnapshot({
386
+ config: appConfig,
387
+ ...(selection.agent ? { agentName: selection.agent } : {}),
388
+ ...(selection.config ? { spec: selection.config } : {}),
389
+ ...((selection.provider || (!selection.agent && !selection.config))
390
+ ? { provider: selection.provider ?? appConfig.AGENT_RUNTIME }
391
+ : {}),
392
+ ...(selection.model ? { model: selection.model } : {}),
393
+ ...(selection.reasoningEffort
394
+ ? { reasoningEffort: selection.reasoningEffort }
395
+ : {}),
396
+ cwd: workspace.cwd,
397
+ }),
398
+ };
399
+ },
400
+ },
401
+ sessionFork: (input) => machineSessions.fork(input),
338
402
  }),
339
403
  startPluginRuntimes: pluginSupervisor.startPluginRuntimes.bind(pluginSupervisor),
340
- reloadPluginRuntime,
341
- ensurePluginRuntime,
342
404
  statusSnapshot: pluginSupervisor.statusSnapshot.bind(pluginSupervisor),
343
405
  dispose: pluginSupervisor.dispose.bind(pluginSupervisor),
344
406
  };
@@ -346,6 +408,8 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
346
408
  const directConnections = new DirectRuntimeConnectionHub();
347
409
  const sessionLog = new SqliteSessionLogStore();
348
410
  const sessionResources = new SqliteSessionResourceStore();
411
+ const sessionForks = new SqliteSessionForkStore();
412
+ const runtimeProjects = new SqliteRuntimeProjectStore();
349
413
  const providerClis = new ProviderCliService();
350
414
  const sessionBrowserCapabilities = new SessionBrowserCapabilityStore();
351
415
  const durableDesktopBrowserHost = new DurableEmbeddedBrowserProfileHost(desktopBrowserHosts, { warn });
@@ -359,10 +423,11 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
359
423
  sessionContextProvider: browserRunnerSessionContexts,
360
424
  onMirrorError: (error, sessionId) => warn(`Session mirror failed for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`),
361
425
  });
426
+ const sessionBrowserHost = appBrowserHostSupervisor
427
+ ? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
428
+ : createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost());
362
429
  const sessionBrowsers = new SessionBrowserService({
363
- host: appBrowserHostSupervisor
364
- ? createSupervisedAppSessionBrowserHost(durableDesktopBrowserHost, appBrowserHostSupervisor)
365
- : createDesktopFirstSessionBrowserHost(durableDesktopBrowserHost, createHeadlessBrowserHost()),
430
+ host: sessionBrowserHost,
366
431
  sessions: {
367
432
  exists: async (sessionId) => Boolean(sessionRegistry.get(sessionId) ??
368
433
  await sessionRuntimeServices.sessionStore.get(sessionId)),
@@ -422,14 +487,35 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
422
487
  sessionEmulators?.cleanupSession(sessionId),
423
488
  ]);
424
489
  },
425
- afterDelete: (sessionId) => {
490
+ afterDelete: async (sessionId) => {
426
491
  sessionBrowserCapabilities.revoke(sessionId);
492
+ removeLegacyPluginSkillSnapshot(sessionId);
493
+ await sessionRuntimeServices.sessionStore.delete(sessionId);
427
494
  },
428
495
  };
429
- const machineSessions = new MachineSessionService({
496
+ const deletedSessions = db()
497
+ .prepare("SELECT session_id AS sessionId FROM session_snapshot_cleanup ORDER BY session_id")
498
+ .all();
499
+ for (const { sessionId } of deletedSessions) {
500
+ try {
501
+ await Promise.all([
502
+ sessionBrowsers.cleanupSession(sessionId),
503
+ sessionEmulators?.cleanupSession(sessionId),
504
+ ]);
505
+ sessionResources.deleteSession(sessionId);
506
+ removeLegacyPluginSkillSnapshot(sessionId);
507
+ await sessionRuntimeServices.sessionStore.delete(sessionId);
508
+ db().prepare("DELETE FROM session_snapshot_cleanup WHERE session_id = ?").run(sessionId);
509
+ }
510
+ catch (error) {
511
+ warn(`Legacy Session artifact cleanup will retry for ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
512
+ }
513
+ }
514
+ machineSessions = new MachineSessionService({
430
515
  registry: sessionRegistry,
431
516
  log: sessionLog,
432
517
  events: sessionRuntimeServices.sessionBus,
518
+ publishEvent: sessionRuntimeServices.publishSessionEvent,
433
519
  runtimeState: sessionRuntimeServices.sessionRuntimeIndex,
434
520
  interruption: {
435
521
  interrupt: (sessionId) => sessionRuntimeServices.runnerManager.interruptLiveSession(sessionId),
@@ -440,25 +526,34 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
440
526
  },
441
527
  pendingMessages: sessionPendingMessageStore,
442
528
  resources: sessionResources,
529
+ forks: sessionForks,
443
530
  execution: {
444
531
  runtime: sessionRuntimeServices.conversationRuntime,
532
+ resolve: ({ agent, provider, model, reasoningEffort, cwd }) => resolveSessionExecutionSnapshot({
533
+ config: appConfig,
534
+ ...(agent ? { agentName: agent } : {}),
535
+ ...(provider ? { provider } : {}),
536
+ ...(model ? { model } : {}),
537
+ ...(reasoningEffort ? { reasoningEffort } : {}),
538
+ cwd,
539
+ }),
445
540
  runner: sessionRuntimeServices.runnerManager,
446
- sessionStore: sessionRuntimeServices.sessionStore,
541
+ },
542
+ workspace: {
543
+ resolve: (projectId) => resolveSessionWorkspace(runtimeProjects, projectId),
544
+ discardUnbound: discardSessionFallbackWorkspace,
447
545
  },
448
546
  });
449
547
  const directAuthenticator = new DaemonDirectRuntimeAuthenticator(installationIdentity, remoteRuntime, remoteRuntimeAccess);
450
548
  const sessionTerminals = createRunnerSessionTerminalHost({
451
549
  runnerManager: sessionRuntimeServices.runnerManager,
452
550
  resolveLiveSession: async (sessionId) => {
453
- const bound = await sessionRuntimeServices.sessionStore.get(sessionId);
454
551
  const registered = sessionRegistry.get(sessionId);
455
- const cwd = bound?.cwd ?? registered?.config?.osEnv?.cwd;
456
- if ((!bound && !registered) ||
457
- !cwd ||
552
+ if (!registered ||
458
553
  !sessionRuntimeServices.runnerManager.hasLiveSession(sessionId)) {
459
554
  return undefined;
460
555
  }
461
- return { cwd };
556
+ return { cwd: registered.workspace.cwd };
462
557
  },
463
558
  });
464
559
  let shutdownAccepted = false;
@@ -478,8 +573,22 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
478
573
  prepareInstallation: (input, context) => pluginManagement.prepareInstallation(input, context),
479
574
  commitInstallation: (token, input, context) => pluginManagement.commitInstallation(token, input, context),
480
575
  cancelPreparation: (token) => pluginManagement.cancelPreparation(token),
576
+ settingsUi: (pluginId) => pluginManagement.settingsUi(pluginId),
577
+ settingsUiAsset: (pluginId, assetGeneration, assetPath) => pluginManagement.settingsUiAsset(pluginId, assetGeneration, assetPath),
578
+ callSettings: (pluginId, generation, method, params, context) => pluginManagement.callSettings(pluginId, generation, method, params, context),
481
579
  dispose: () => pluginManagement.dispose(),
482
580
  },
581
+ pluginMarketplaces: {
582
+ list: () => listPluginMarketplaces().map(toMarketplaceItem),
583
+ add: async (input, context) => toMarketplaceItem(await addPluginMarketplace(input.source, {
584
+ ...(input.alias ? { alias: input.alias } : {}),
585
+ signal: context.signal,
586
+ })),
587
+ refresh: async (id, context) => toMarketplaceItem(await refreshPluginMarketplace(id, {
588
+ signal: context.signal,
589
+ })),
590
+ remove: (id) => removePluginMarketplace(id),
591
+ },
483
592
  browserArtifacts: browserArtifactManagement,
484
593
  maintenance: maintenanceManagement,
485
594
  shutdownIfIdle: () => {
@@ -516,6 +625,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
516
625
  terminals: sessionTerminals,
517
626
  browsers: sessionBrowsers,
518
627
  providerClis,
628
+ projects: runtimeProjects,
519
629
  onError: (error) => warn(`Remote Runtime dispatch failed: ${error instanceof Error ? error.message : String(error)}`),
520
630
  });
521
631
  const remoteRuntimeAdmin = directConfig && directEncryptionIdentity
@@ -552,7 +662,6 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
552
662
  };
553
663
  server = await startServer({
554
664
  config: appConfig,
555
- loadInstances: () => resolveChannelInstances(warn),
556
665
  control,
557
666
  sessionLog,
558
667
  sessionRegistry,
@@ -564,6 +673,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, writeE
564
673
  runtimeTargetControl,
565
674
  runtimeConnectionResolver: runtimeConnectionManager,
566
675
  localSessionResources: machineSessions,
676
+ localMachineSessions: machineSessions,
567
677
  providerClis,
568
678
  sessionEmulators,
569
679
  sessionLifecycle: sessionResourceLifecycle,