@rynx-ai/server 0.1.9 → 0.1.10-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 (39) hide show
  1. package/dist/browser-surface-ws.d.ts +2 -0
  2. package/dist/browser-surface-ws.js +1 -0
  3. package/dist/control-api.d.ts +17 -0
  4. package/dist/control-api.js +809 -9
  5. package/dist/control-web/assets/{highlighted-body-OFNGDK62-e-w61YLy.js → highlighted-body-OFNGDK62-DHu2g-rk.js} +1 -1
  6. package/dist/control-web/assets/index-B6Pb5j9M.js +666 -0
  7. package/dist/control-web/assets/index-BU-_Qud_.css +32 -0
  8. package/dist/control-web/assets/{mermaid-GHXKKRXX-DZn7Hbr2.js → mermaid-GHXKKRXX-CSYzOmBR.js} +3 -3
  9. package/dist/control-web/index.html +2 -2
  10. package/dist/desktop-browser-host.d.ts +20 -3
  11. package/dist/desktop-browser-host.js +126 -44
  12. package/dist/direct-runtime-browser-inspect-server.d.ts +72 -0
  13. package/dist/direct-runtime-browser-inspect-server.js +749 -0
  14. package/dist/direct-runtime-server.d.ts +6 -0
  15. package/dist/direct-runtime-server.js +29 -1
  16. package/dist/emulator-surface-ws.d.ts +2 -0
  17. package/dist/emulator-surface-ws.js +1 -0
  18. package/dist/machine-session-service.d.ts +88 -5
  19. package/dist/machine-session-service.js +283 -20
  20. package/dist/remote-runtime-dispatcher.d.ts +1 -1
  21. package/dist/remote-runtime-dispatcher.js +25 -2
  22. package/dist/remote-runtime-session-projection.js +10 -0
  23. package/dist/runtime-web-auth.d.ts +5 -0
  24. package/dist/runtime-web-auth.js +43 -3
  25. package/dist/server.d.ts +78 -8
  26. package/dist/server.js +42 -17
  27. package/dist/session-browser-service.d.ts +30 -0
  28. package/dist/session-browser-service.js +89 -3
  29. package/dist/session-browser-surface-coordinator.d.ts +4 -3
  30. package/dist/session-browser-surface-coordinator.js +374 -268
  31. package/dist/session-runtime-index.d.ts +6 -0
  32. package/dist/session-runtime-index.js +10 -0
  33. package/dist/session-terminal-host.d.ts +6 -1
  34. package/dist/session-terminal-host.js +18 -0
  35. package/dist/terminal-ws.d.ts +3 -0
  36. package/dist/terminal-ws.js +1 -0
  37. package/package.json +12 -7
  38. package/dist/control-web/assets/index-BQ7XVBKO.css +0 -32
  39. package/dist/control-web/assets/index-ClpzuBJx.js +0 -606
package/dist/server.d.ts CHANGED
@@ -2,46 +2,52 @@ import type { Server as HttpServer } from "node:http";
2
2
  import Koa from "koa";
3
3
  import { ConversationRuntime, type AgentCapabilities, type AgentSessionStore, type AppConfig, type ChannelInstanceDescriptor, type SessionEvent, type SessionBus, type SessionLogStore, type SessionRegistry } from "@rynx-ai/core";
4
4
  import type { SessionInteractionResolution } from "@rynx-ai/protocol";
5
- import type { ControlRuntimeShareAddress } from "@rynx-ai/protocol/control";
5
+ import type { ControlRuntimeShareAddress, DaemonBrowserArtifactCleanResult, DaemonBrowserArtifactInstallInput, DaemonBrowserArtifactInstallResult, DaemonBrowserArtifactUpdateInput, DaemonBrowserArtifactVersionResult, DaemonCleanupSessionsInput, DaemonCleanupSessionsResult, DaemonChromeInspectionConfigureInput, DaemonChromeInspectionStatus, DaemonShutdownIfIdleResult } from "@rynx-ai/protocol/control";
6
+ import type { PluginInstallCommitInput, PluginInstallCommitResult, PluginInstallPreparation, PluginInstallPrepareInput, PluginManagementItem } from "@rynx-ai/protocol/plugin-management";
6
7
  import type { PairingOffer } from "@rynx-ai/protocol/direct-runtime";
7
8
  import type { DaemonStatus } from "@rynx-ai/protocol/remote-runtime";
8
9
  import type { RuntimeBrowserBootstrapCredential, RuntimeBrowserEndpointDescriptor } from "@rynx-ai/protocol/runtime-browser-bootstrap";
10
+ import type { RuntimeBrowserInspectMessage, RuntimeBrowserInspectTarget } from "@rynx-ai/protocol/runtime-browser-inspect";
9
11
  import type { RuntimeBrowserSurfaceClientFrame, RuntimeBrowserSurfaceImageFrame, RuntimeBrowserSurfaceOpenFrame, RuntimeBrowserSurfaceReadyFrame, RuntimeBrowserSurfaceServerFrame } from "@rynx-ai/protocol/runtime-browser-surface";
10
12
  import type { RuntimeEmulatorSurfaceImageFrame, RuntimeEmulatorSurfaceReadyFrame } from "@rynx-ai/protocol/runtime-emulator-surface";
11
13
  import type { RemoteRuntimeRpcMethod, RemoteRuntimeRpcParams, RemoteRuntimeRpcResultFor, RemoteRuntimeSequencedSessionEvent } from "@rynx-ai/protocol/remote-runtime-rpc";
12
14
  import type { PluginAgentSummary, PluginResolvedSessionExecution, PluginSessionExecutionSnapshot } from "@rynx-ai/plugin-sdk";
13
15
  import { RunnerManager, type CodexSessionStore, type RunnerSessionContextProvider } from "@rynx-ai/runtime";
14
16
  import { ChannelManager } from "./channel-manager.js";
15
- import { type ControlPlaneDeps, type SessionResourceLifecycle } from "./control-api.js";
17
+ import { type ControlPlaneDeps, type LocalSessionResourceHost, type SessionResourceLifecycle } from "./control-api.js";
16
18
  import type { DaemonRuntimeHost } from "./remote-runtime.js";
17
19
  import { type AttachDesktopBrowserHostServerOptions } from "./desktop-browser-host.js";
18
20
  import { SessionRuntimeIndex } from "./session-runtime-index.js";
19
21
  import type { SessionEmulatorService } from "./session-emulator-service.js";
22
+ import { type SessionTerminalHost } from "./session-terminal-host.js";
20
23
  import type { ProviderCliManagementHost } from "./provider-cli-host.js";
24
+ import { type RuntimeWebAccessPolicy } from "./runtime-web-auth.js";
21
25
  export { ChannelManager } from "./channel-manager.js";
22
26
  export type { ChannelInstanceStatus } from "./channel-manager.js";
23
27
  export type { ProviderCliManagementHost, ProviderCliStatusHost, } from "./provider-cli-host.js";
24
28
  export { MachineSessionService, MachineSessionServiceFailure, MachineSessionServiceInputError, synthesizeSessionTitle, } from "./machine-session-service.js";
25
- export type { MachineSessionAgentCatalogPort, MachineSessionCreateInput, MachineSessionCreateResult, MachineSessionDeleteResult, MachineSessionInterruptPort, MachineSessionInterruptResult, MachineSessionInteractionResult, MachineSessionListInput, MachineSessionListPage, MachineSessionMessageResult, MachineSessionRunnerPort, MachineSessionRuntimeStatePort, MachineSessionServiceFailureCode, MachineSessionServiceOptions, MachineSessionServicePorts, MachineSessionSnapshotInput, MachineSessionSnapshotPage, MachineSessionWatch, } from "./machine-session-service.js";
29
+ export type { MachineSessionAgentCatalogPort, MachineSessionCreateInput, MachineSessionCreateResult, MachineSessionDeleteResult, MachineSessionInterruptPort, MachineSessionInterruptResult, MachineSessionInteractionResult, MachineSessionListInput, MachineSessionListPage, MachineSessionMessageResult, MachineSessionMessageEnqueueResult, MachineSessionMessageInput, MachineSessionMessageOperationState, MachineSessionPendingMessage, MachineSessionPendingMessagePort, MachineSessionPreparedInput, MachineSessionResourcePort, MachineSessionRunnerPort, MachineSessionRuntimeStatePort, MachineSessionServiceFailureCode, MachineSessionServiceOptions, MachineSessionServicePorts, MachineSessionSnapshotInput, MachineSessionSnapshotPage, MachineSessionWatch, } from "./machine-session-service.js";
26
30
  export { SessionBrowserHostError, SessionBrowserService, SessionBrowserServiceError, SessionBrowserSurfaceUnsupportedError, } from "./session-browser-service.js";
27
- export type { SessionBrowserHost, SessionBrowserHostCreateInput, SessionBrowserHostErrorCode, SessionBrowserHostEvent, SessionBrowserHostHandle, SessionBrowserHostPage, SessionBrowserHostSurfaceFrame, SessionBrowserHostSurfaceOpenInput, SessionBrowserHostSurfaceSource, SessionBrowserHostSurfaceTrustedInput, SessionBrowserHostSurfaceViewport, SessionBrowserHostSnapshot, SessionBrowserRegistryPort, SessionBrowserServiceErrorCode, SessionBrowserServiceOptions, SessionBrowserServicePorts, SessionBrowserSurfaceOpenInput, SessionBrowserSurfaceSource, } from "./session-browser-service.js";
31
+ export type { SessionBrowserHost, SessionBrowserHostCreateInput, SessionBrowserHostErrorCode, SessionBrowserHostEvent, SessionBrowserHostHandle, SessionBrowserHostPage, SessionBrowserHostSurfaceFrame, SessionBrowserHostSurfaceOpenInput, SessionBrowserHostSurfaceSource, SessionBrowserHostSurfaceTrustedInput, SessionBrowserHostSurfaceViewport, SessionBrowserHostSnapshot, SessionBrowserInspectionEndpoint, SessionBrowserInspectionTarget, SessionBrowserRegistryPort, SessionBrowserServiceErrorCode, SessionBrowserServiceOptions, SessionBrowserServicePorts, SessionBrowserSurfaceOpenInput, SessionBrowserSurfaceSource, } from "./session-browser-service.js";
28
32
  export { SessionEmulatorBindingConflictError, SessionEmulatorService, SessionEmulatorServiceError, } from "./session-emulator-service.js";
29
33
  export type { SessionEmulatorBindingRecord, SessionEmulatorBindingStore, SessionEmulatorServiceErrorCode, SessionEmulatorServiceOptions, SessionEmulatorSurface, } from "./session-emulator-service.js";
30
34
  export { SessionBrowserSurfaceCoordinator } from "./session-browser-surface-coordinator.js";
31
35
  export type { SessionBrowserSurfaceCoordinatorOptions, } from "./session-browser-surface-coordinator.js";
32
36
  export { attachDesktopBrowserHostServer, createDesktopFirstSessionBrowserHost, DesktopBrowserHostAbsentError, DesktopBrowserHostProtocolError, DesktopBrowserHostRegistry, } from "./desktop-browser-host.js";
33
37
  export type { AttachDesktopBrowserHostServerOptions, DesktopBrowserHostRegistryOptions, } from "./desktop-browser-host.js";
34
- export type { ControlPlaneDeps, StoredSessionMeta } from "./control-api.js";
38
+ export type { ControlPlaneDeps, LocalSessionResourceHost, StoredSessionMeta, } from "./control-api.js";
35
39
  export { createDaemonRuntimeHost, encodeDaemonStatus } from "./remote-runtime.js";
36
40
  export type { DaemonRuntimeHost, DaemonRuntimeSnapshot } from "./remote-runtime.js";
37
41
  export { DIRECT_RUNTIME_CONTROL_PATH, DirectRuntimeConnectionHub, startDirectRuntimeServer, } from "./direct-runtime-server.js";
38
42
  export type { DirectRuntimeAuthenticationResult, DirectRuntimeAuthenticator, DirectRuntimeEmulatorSurfaceAttachment, DirectRuntimeEmulatorSurfaceHost, DirectRuntimePeer, DirectRuntimeServer, DirectRuntimeServerLimits, StartDirectRuntimeServerOptions, } from "./direct-runtime-server.js";
39
43
  export { attachDirectRuntimeBrowserSurfaceServer, DirectRuntimeBrowserSurfaceHostError, } from "./direct-runtime-browser-surface-server.js";
44
+ export { attachDirectRuntimeBrowserInspectServer, DirectRuntimeBrowserInspectHostError, } from "./direct-runtime-browser-inspect-server.js";
45
+ export type { AttachDirectRuntimeBrowserInspectServerOptions, DirectRuntimeBrowserInspectAttachment, DirectRuntimeBrowserInspectConnectionHub, DirectRuntimeBrowserInspectHost, DirectRuntimeBrowserInspectServer, DirectRuntimeBrowserInspectServerLimits, DirectRuntimeBrowserInspectTransportCloseReason, } from "./direct-runtime-browser-inspect-server.js";
40
46
  export type { AttachDirectRuntimeBrowserSurfaceServerOptions, DirectRuntimeBrowserSurfaceAttachment, DirectRuntimeBrowserSurfaceAttachmentEvent, DirectRuntimeBrowserSurfaceConnectionHub, DirectRuntimeBrowserSurfaceHost, DirectRuntimeBrowserSurfaceServer, DirectRuntimeBrowserSurfaceServerLimits, DirectRuntimeBrowserSurfaceTransportCloseReason, } from "./direct-runtime-browser-surface-server.js";
41
47
  export { RemoteRuntimeDispatcher } from "./remote-runtime-dispatcher.js";
42
48
  export type { AuthenticatedRuntimeSubject, RemoteRuntimeEmulatorHost, RemoteRuntimeSessionEmulatorHost, RemoteRuntimeDispatchContext, RemoteRuntimeDispatcherOptions, } from "./remote-runtime-dispatcher.js";
43
49
  export { createRunnerSessionTerminalHost, SessionTerminalOpenError, SessionTerminalStreamError, } from "./session-terminal-host.js";
44
- export type { RunnerSessionTerminalHostOptions, SessionTerminalAttachment, SessionTerminalCloseInfo, SessionTerminalCloseReason, SessionTerminalHost, SessionTerminalOpenErrorCode, SessionTerminalOpenOptions, SessionTerminalRole, } from "./session-terminal-host.js";
50
+ export type { RunnerSessionTerminalHostOptions, RunnerSessionTerminalHost, SessionTerminalAttachment, SessionTerminalCloseInfo, SessionTerminalCloseReason, SessionTerminalHost, SessionTerminalOpenErrorCode, SessionTerminalOpenOptions, SessionTerminalRole, } from "./session-terminal-host.js";
45
51
  export type { ControlChannel, ControlChannelType, ControlInstanceConfig, ControlInstanceStatus, ControlAgentSummary, } from "@rynx-ai/protocol/control";
46
52
  export interface CreateAppOptions {
47
53
  config?: AppConfig;
@@ -63,7 +69,9 @@ export interface CreateAppOptions {
63
69
  remoteRuntime?: DaemonRuntimeHost;
64
70
  remoteRuntimeAdmin?: RemoteRuntimeAdminHost;
65
71
  runtimeTargetControl?: RuntimeTargetControlHost;
72
+ runtimeWebAccess?: RuntimeWebAccessPolicy;
66
73
  runtimeConnectionResolver?: RuntimeConnectionResolverHost;
74
+ localSessionResources?: LocalSessionResourceHost;
67
75
  sessionEmulators?: SessionEmulatorService;
68
76
  /** Host lifecycle signal for ending SSE/video streams before drain. */
69
77
  shutdownSignal?: AbortSignal;
@@ -114,6 +122,8 @@ export interface StartServerOptions {
114
122
  runtimeTargetControl?: RuntimeTargetControlHost;
115
123
  /** Secret-owning backend resolver for explicit Local or Direct Runtime calls. */
116
124
  runtimeConnectionResolver?: RuntimeConnectionResolverHost;
125
+ /** In-process resource authority used only by the Local Runtime BFF. */
126
+ localSessionResources?: LocalSessionResourceHost;
117
127
  /** Runtime-owned Session Emulator binding authority for Local compatibility routes. */
118
128
  sessionEmulators?: SessionEmulatorService;
119
129
  /** Pre-composed daemon-owned Session runtime. Supplying this lets the daemon
@@ -122,6 +132,9 @@ export interface StartServerOptions {
122
132
  sessionRuntimeServices?: SessionRuntimeServices;
123
133
  /** Shared fence for Session-owned resources on canonical and legacy deletes. */
124
134
  sessionLifecycle?: SessionResourceLifecycle;
135
+ /** Shared local terminal host. Supplying this lets Local HTTP/WebSocket and
136
+ * Direct Runtime attachments contribute to one activity count. */
137
+ sessionTerminals?: SessionTerminalHost;
125
138
  /** Runtime-local, Session-capability-authorized CDP bootstrap. Never remote. */
126
139
  runtimeLocalBrowser?: RuntimeLocalBrowserAutomationHost;
127
140
  /** Runtime-owned provider CLI inspection and local lifecycle operations. */
@@ -182,10 +195,50 @@ export interface PluginCliInvocationOutput {
182
195
  export interface DaemonManagementInvocationContext {
183
196
  signal: AbortSignal;
184
197
  }
198
+ export interface PluginManagementHost {
199
+ listPlugins(): {
200
+ plugins: PluginManagementItem[];
201
+ } | Promise<{
202
+ plugins: PluginManagementItem[];
203
+ }>;
204
+ setPluginEnabled(pluginId: string, enabled: boolean): PluginManagementItem | undefined | Promise<PluginManagementItem | undefined>;
205
+ uninstallPlugin(pluginId: string): Promise<boolean>;
206
+ prepareInstallation(input: PluginInstallPrepareInput, context: DaemonManagementInvocationContext): Promise<PluginInstallPreparation>;
207
+ commitInstallation(token: string, input: PluginInstallCommitInput, context: DaemonManagementInvocationContext): Promise<PluginInstallCommitResult>;
208
+ cancelPreparation(token: string): boolean | Promise<boolean>;
209
+ dispose?(): void | Promise<void>;
210
+ }
211
+ export interface BrowserArtifactManagementHost {
212
+ install(input: DaemonBrowserArtifactInstallInput, context: DaemonManagementInvocationContext): Promise<DaemonBrowserArtifactInstallResult>;
213
+ update(input: DaemonBrowserArtifactUpdateInput, context: DaemonManagementInvocationContext): Promise<DaemonBrowserArtifactInstallResult>;
214
+ version(): DaemonBrowserArtifactVersionResult;
215
+ clean(): DaemonBrowserArtifactCleanResult;
216
+ }
217
+ export interface MaintenanceManagementHost {
218
+ cleanupSessions(input: DaemonCleanupSessionsInput): DaemonCleanupSessionsResult;
219
+ }
220
+ export interface ChromeInspectionManagementHost {
221
+ status(): DaemonChromeInspectionStatus | Promise<DaemonChromeInspectionStatus>;
222
+ configure(input: DaemonChromeInspectionConfigureInput): Promise<DaemonChromeInspectionStatus>;
223
+ }
185
224
  /** The complete local management authority injected by the daemon composition root. */
186
225
  export interface DaemonManagementHost {
187
226
  managementToken: string;
188
227
  identity(): DaemonControlIdentity;
228
+ /** Public, non-secret health signal used to detect an in-place daemon rebuild. */
229
+ buildStatus?(): {
230
+ restartRequired: boolean;
231
+ };
232
+ /** Perform one final activity check and schedule shutdown only when idle. */
233
+ shutdownIfIdle?(): DaemonShutdownIfIdleResult;
234
+ /** Stateful plugin registry operations owned by the resident daemon. */
235
+ pluginManagement?: PluginManagementHost;
236
+ /** Stateful Chrome for Testing artifact operations owned by the daemon. */
237
+ browserArtifacts?: BrowserArtifactManagementHost;
238
+ /** Destructive maintenance operations over daemon-owned state. */
239
+ maintenance?: MaintenanceManagementHost;
240
+ /** Local Chrome DevTools discovery gateway configuration and readiness. */
241
+ chromeInspection?: ChromeInspectionManagementHost;
189
242
  invokePluginCli(input: PluginCliInvocationInput, context: DaemonManagementInvocationContext): Promise<PluginCliInvocationOutput>;
190
243
  }
191
244
  /**
@@ -221,6 +274,9 @@ export interface RemoteRuntimeAdminHost {
221
274
  revoked: boolean;
222
275
  closedConnections: number;
223
276
  };
277
+ deleteRevokedClientGrant(grantId: string): {
278
+ deleted: boolean;
279
+ };
224
280
  }
225
281
  /** Secret-free Runtime target projection safe for the local Control Plane UI. */
226
282
  export interface RuntimeTargetView {
@@ -248,6 +304,8 @@ export interface RuntimeTargetControlHost {
248
304
  pair(input: {
249
305
  offer: unknown;
250
306
  displayName?: string;
307
+ replaceExisting?: boolean;
308
+ expectedDaemonId?: string;
251
309
  }): RuntimeTargetPairResult | Promise<RuntimeTargetPairResult>;
252
310
  test(selector: string): RuntimeTargetTestResult | Promise<RuntimeTargetTestResult>;
253
311
  forget(daemonId: string): {
@@ -281,6 +339,10 @@ export interface RuntimeConnectionLease {
281
339
  signal?: AbortSignal;
282
340
  timeoutMs?: number;
283
341
  }): Promise<RuntimeBrowserSurfaceConnection>;
342
+ openBrowserInspect(target: RuntimeBrowserInspectTarget, options?: {
343
+ signal?: AbortSignal;
344
+ timeoutMs?: number;
345
+ }): Promise<RuntimeBrowserInspectConnection>;
284
346
  openEmulatorSurface(sessionId: string, bindingId: string, options?: {
285
347
  signal?: AbortSignal;
286
348
  timeoutMs?: number;
@@ -295,6 +357,12 @@ export interface RuntimeBrowserSurfaceConnection extends AsyncIterable<RuntimeBr
295
357
  close(): Promise<void>;
296
358
  }
297
359
  export type RuntimeBrowserSurfaceEvent = Exclude<RuntimeBrowserSurfaceServerFrame, RuntimeBrowserSurfaceReadyFrame> | RuntimeBrowserSurfaceImageFrame;
360
+ /** Dedicated transparent CDP stream owned by one selected Runtime page. */
361
+ export interface RuntimeBrowserInspectConnection extends AsyncIterable<RuntimeBrowserInspectMessage> {
362
+ readonly daemonInstanceId: string;
363
+ send(message: RuntimeBrowserInspectMessage): Promise<void>;
364
+ close(): Promise<void>;
365
+ }
298
366
  export interface RuntimeEmulatorSurfaceConnection extends AsyncIterable<RuntimeEmulatorSurfaceImageFrame> {
299
367
  readonly ready: RuntimeEmulatorSurfaceReadyFrame;
300
368
  sendTouch(point: {
@@ -318,6 +386,8 @@ export interface RuntimeConnectionResolverHost {
318
386
  }
319
387
  /** HTTP server plus an idempotent join point for all daemon-owned resources. */
320
388
  export interface RynxServer extends HttpServer {
389
+ /** Synchronously stop new HTTP admission without closing upgraded Hosts. */
390
+ stopAccepting(): void;
321
391
  shutdown(): Promise<void>;
322
392
  }
323
393
  /** Preserve one session's mirror order without serializing unrelated sessions. */
@@ -344,5 +414,5 @@ export declare function createSessionRuntimeServices(input: {
344
414
  * Lark bot reaches its server over an outbound WebSocket long connection), so
345
415
  * no agent request / response / SSE endpoints are exposed here.
346
416
  */
347
- export declare function createApp({ control }?: CreateAppOptions): Koa<Koa.DefaultState, Koa.DefaultContext>;
348
- export declare function startServer({ config, channelInstances, loadInstances, control, sessionLog, sessionRegistry, pluginRuntime, daemonManagement, remoteRuntime, remoteRuntimeAdmin, runtimeTargetControl, runtimeConnectionResolver, sessionEmulators, sessionRuntimeServices, sessionLifecycle, runtimeLocalBrowser, providerClis, desktopBrowserHost, }?: StartServerOptions): Promise<RynxServer>;
417
+ export declare function createApp({ config, control }?: CreateAppOptions): Koa<Koa.DefaultState, Koa.DefaultContext>;
418
+ export declare function startServer({ config, channelInstances, loadInstances, control, sessionLog, sessionRegistry, pluginRuntime, daemonManagement, remoteRuntime, remoteRuntimeAdmin, runtimeTargetControl, runtimeConnectionResolver, localSessionResources, sessionEmulators, sessionRuntimeServices, sessionLifecycle, sessionTerminals, runtimeLocalBrowser, providerClis, desktopBrowserHost, }?: StartServerOptions): Promise<RynxServer>;
package/dist/server.js CHANGED
@@ -12,7 +12,8 @@ import { attachEmulatorSurfaceWs } from "./emulator-surface-ws.js";
12
12
  import { attachDesktopBrowserHostServer, } from "./desktop-browser-host.js";
13
13
  import { resolveControlWebDist, sendSpaFile } from "./control-web-dist.js";
14
14
  import { SessionRuntimeIndex } from "./session-runtime-index.js";
15
- import { createRunnerSessionTerminalHost } from "./session-terminal-host.js";
15
+ import { createRunnerSessionTerminalHost, } from "./session-terminal-host.js";
16
+ import { runtimeWebAccessPolicyForBindHost, } from "./runtime-web-auth.js";
16
17
  export { ChannelManager } from "./channel-manager.js";
17
18
  export { MachineSessionService, MachineSessionServiceFailure, MachineSessionServiceInputError, synthesizeSessionTitle, } from "./machine-session-service.js";
18
19
  export { SessionBrowserHostError, SessionBrowserService, SessionBrowserServiceError, SessionBrowserSurfaceUnsupportedError, } from "./session-browser-service.js";
@@ -22,6 +23,7 @@ export { attachDesktopBrowserHostServer, createDesktopFirstSessionBrowserHost, D
22
23
  export { createDaemonRuntimeHost, encodeDaemonStatus } from "./remote-runtime.js";
23
24
  export { DIRECT_RUNTIME_CONTROL_PATH, DirectRuntimeConnectionHub, startDirectRuntimeServer, } from "./direct-runtime-server.js";
24
25
  export { attachDirectRuntimeBrowserSurfaceServer, DirectRuntimeBrowserSurfaceHostError, } from "./direct-runtime-browser-surface-server.js";
26
+ export { attachDirectRuntimeBrowserInspectServer, DirectRuntimeBrowserInspectHostError, } from "./direct-runtime-browser-inspect-server.js";
25
27
  export { RemoteRuntimeDispatcher } from "./remote-runtime-dispatcher.js";
26
28
  export { createRunnerSessionTerminalHost, SessionTerminalOpenError, SessionTerminalStreamError, } from "./session-terminal-host.js";
27
29
  /** Preserve one session's mirror order without serializing unrelated sessions. */
@@ -87,7 +89,7 @@ export function createSessionRuntimeServices(input) {
87
89
  * Lark bot reaches its server over an outbound WebSocket long connection), so
88
90
  * no agent request / response / SSE endpoints are exposed here.
89
91
  */
90
- export function createApp({ control } = {}) {
92
+ export function createApp({ config = loadConfig(), control } = {}) {
91
93
  const app = new Koa();
92
94
  const router = new Router();
93
95
  router.get("/health", (ctx) => {
@@ -96,7 +98,11 @@ export function createApp({ control } = {}) {
96
98
  app.use(router.routes());
97
99
  app.use(router.allowedMethods());
98
100
  if (control) {
99
- const controlRouter = createControlRouter(control);
101
+ const controlRouter = createControlRouter({
102
+ ...control,
103
+ runtimeWebAccess: control.runtimeWebAccess ??
104
+ runtimeWebAccessPolicyForBindHost(config.HOST),
105
+ });
100
106
  app.use(controlRouter.routes());
101
107
  app.use(controlRouter.allowedMethods());
102
108
  }
@@ -125,7 +131,8 @@ export function createApp({ control } = {}) {
125
131
  }
126
132
  return app;
127
133
  }
128
- export async function startServer({ config = loadConfig(), channelInstances, loadInstances, control, sessionLog, sessionRegistry, pluginRuntime, daemonManagement, remoteRuntime, remoteRuntimeAdmin, runtimeTargetControl, runtimeConnectionResolver, sessionEmulators, sessionRuntimeServices, sessionLifecycle, runtimeLocalBrowser, providerClis, desktopBrowserHost, } = {}) {
134
+ export async function startServer({ config = loadConfig(), channelInstances, loadInstances, control, sessionLog, sessionRegistry, pluginRuntime, daemonManagement, remoteRuntime, remoteRuntimeAdmin, runtimeTargetControl, runtimeConnectionResolver, localSessionResources, sessionEmulators, sessionRuntimeServices, sessionLifecycle, sessionTerminals, runtimeLocalBrowser, providerClis, desktopBrowserHost, } = {}) {
135
+ const runtimeWebAccess = runtimeWebAccessPolicyForBindHost(config.HOST);
129
136
  const desktopBrowserManagementToken = desktopBrowserHost
130
137
  ? requireDaemonManagementToken(daemonManagement)
131
138
  : undefined;
@@ -137,15 +144,16 @@ export async function startServer({ config = loadConfig(), channelInstances, loa
137
144
  },
138
145
  });
139
146
  const { sessionStore, runnerManager, sessionBus, sessionRuntimeIndex, conversationRuntime, } = sessionServices;
140
- const legacyLocalTerminalHost = createRunnerSessionTerminalHost({
141
- runnerManager,
142
- resolveLiveSession: async (sessionId) => {
143
- const session = await sessionStore.get(sessionId);
144
- if (!session || !runnerManager.hasLiveSession(sessionId))
145
- return undefined;
146
- return { cwd: session.cwd };
147
- },
148
- });
147
+ const legacyLocalTerminalHost = sessionTerminals ??
148
+ createRunnerSessionTerminalHost({
149
+ runnerManager,
150
+ resolveLiveSession: async (sessionId) => {
151
+ const session = await sessionStore.get(sessionId);
152
+ if (!session || !runnerManager.hasLiveSession(sessionId))
153
+ return undefined;
154
+ return { cwd: session.cwd };
155
+ },
156
+ });
149
157
  if (pluginRuntime) {
150
158
  if (!sessionRegistry)
151
159
  throw new Error("plugin runtime requires a machine session registry");
@@ -203,6 +211,7 @@ export async function startServer({ config = loadConfig(), channelInstances, loa
203
211
  loadInstances: resolveInstances,
204
212
  });
205
213
  const app = createApp({
214
+ config,
206
215
  control: control
207
216
  ? {
208
217
  manager,
@@ -226,6 +235,7 @@ export async function startServer({ config = loadConfig(), channelInstances, loa
226
235
  remoteRuntimeAdmin,
227
236
  runtimeTargetControl,
228
237
  runtimeConnectionResolver,
238
+ localSessionResources,
229
239
  sessionEmulators,
230
240
  shutdownSignal: controlShutdown.signal,
231
241
  sessionRuntimeIndex,
@@ -262,9 +272,10 @@ export async function startServer({ config = loadConfig(), channelInstances, loa
262
272
  attachTerminalWs(server, {
263
273
  runtimeConnectionResolver,
264
274
  legacyLocalTerminalHost,
275
+ runtimeWebAccess,
265
276
  }),
266
- attachBrowserSurfaceWs(server, { runtimeConnectionResolver }),
267
- attachEmulatorSurfaceWs(server, { runtimeConnectionResolver }),
277
+ attachBrowserSurfaceWs(server, { runtimeConnectionResolver, runtimeWebAccess }),
278
+ attachEmulatorSurfaceWs(server, { runtimeConnectionResolver, runtimeWebAccess }),
268
279
  ];
269
280
  if (desktopBrowserHost && desktopBrowserManagementToken) {
270
281
  webSocketServers.push(attachDesktopBrowserHostServer(server, {
@@ -276,14 +287,17 @@ export async function startServer({ config = loadConfig(), channelInstances, loa
276
287
  webSocketServers.push(attachEmulatorTouchWs(server, { emulator: control.emulator }));
277
288
  }
278
289
  resolve(bindServerLifecycle(server, {
279
- closeUpgrades: async () => {
290
+ fence: () => {
280
291
  controlShutdown.abort(new Error("Rynx server is shutting down"));
292
+ },
293
+ closeUpgrades: async () => {
281
294
  await closeWebSocketServers(webSocketServers);
282
295
  },
283
296
  cleanup: async () => {
284
297
  await runCleanupSteps([
285
298
  () => startup.catch(() => undefined),
286
299
  () => manager.stopAll(),
300
+ () => Promise.resolve(daemonManagement?.pluginManagement?.dispose?.()),
287
301
  () => pluginRuntime?.dispose() ?? Promise.resolve(),
288
302
  () => runnerManager.stop(),
289
303
  ]);
@@ -330,20 +344,31 @@ function requireDaemonManagementToken(host) {
330
344
  }
331
345
  function bindServerLifecycle(server, lifecycle) {
332
346
  let closed = false;
347
+ let acceptanceClosePromise;
333
348
  let shutdownPromise;
334
349
  const nativeClose = server.close.bind(server);
335
350
  server.once("close", () => {
336
351
  closed = true;
337
352
  });
338
353
  const managed = server;
354
+ managed.stopAccepting = () => {
355
+ if (acceptanceClosePromise)
356
+ return;
357
+ lifecycle.fence?.();
358
+ acceptanceClosePromise = closeHttpServer(server, nativeClose, () => closed);
359
+ // The full shutdown joins this promise immediately; retain a rejection
360
+ // handler so a caller cannot create an unhandled rejection in between.
361
+ void acceptanceClosePromise.catch(() => undefined);
362
+ };
339
363
  managed.shutdown = () => {
340
364
  if (shutdownPromise)
341
365
  return shutdownPromise;
366
+ managed.stopAccepting();
342
367
  shutdownPromise = (async () => {
343
368
  // Stop accepting first, close upgraded sockets so they cannot hold the
344
369
  // HTTP drain open, then keep runtime dependencies alive until every
345
370
  // in-flight HTTP request has completed.
346
- const closeResult = closeHttpServer(server, nativeClose, () => closed);
371
+ const closeResult = acceptanceClosePromise;
347
372
  const upgradeResult = lifecycle.closeUpgrades?.() ?? Promise.resolve();
348
373
  const drainResults = await Promise.allSettled([upgradeResult, closeResult]);
349
374
  const errors = drainResults
@@ -79,6 +79,20 @@ export interface SessionBrowserSurfaceOpenInput {
79
79
  signal?: AbortSignal;
80
80
  }
81
81
  export type SessionBrowserSurfaceSource = Omit<SessionBrowserHostSurfaceSource, "hostPageId">;
82
+ /** One already-running semantic Page that can be exposed by a local inspection gateway. */
83
+ export interface SessionBrowserInspectionTarget {
84
+ sessionId: string;
85
+ browserGeneration: number;
86
+ pageId: string;
87
+ executionBackend: RuntimeBrowserExecutionBackend;
88
+ url: string;
89
+ title: string;
90
+ }
91
+ /** Exact loopback Page endpoint resolved only after the semantic tuple is fenced. */
92
+ export interface SessionBrowserInspectionEndpoint {
93
+ endpoint: string;
94
+ engineVersion: string;
95
+ }
82
96
  export declare class SessionBrowserSurfaceUnsupportedError extends Error {
83
97
  constructor();
84
98
  }
@@ -105,7 +119,10 @@ export interface SessionBrowserHostHandle {
105
119
  getCdpEndpoint(): Promise<{
106
120
  endpoint: string;
107
121
  engineVersion: string;
122
+ pageTargetId?: string;
108
123
  }>;
124
+ /** Optional exact physical Page handoff for the daemon-local inspection gateway. */
125
+ getPageCdpEndpoint?(hostPageId: string): Promise<SessionBrowserInspectionEndpoint>;
109
126
  /** Optional physical presentation primitive; it never projects native CDP. */
110
127
  openSurface?(input: SessionBrowserHostSurfaceOpenInput): Promise<SessionBrowserHostSurfaceSource>;
111
128
  snapshot(): Promise<SessionBrowserHostSnapshot>;
@@ -167,6 +184,19 @@ export declare class SessionBrowserService {
167
184
  private shuttingDown;
168
185
  private closeAllPromise?;
169
186
  constructor(ports: SessionBrowserServicePorts, options?: SessionBrowserServiceOptions);
187
+ /** Number of Session Browsers that still own a physical Host handle. */
188
+ activeBrowserCount(): number;
189
+ /**
190
+ * Snapshot the current in-memory inspection inventory. Discovery is
191
+ * deliberately passive: it neither creates Browsers nor asks a Host to
192
+ * reconcile physical state.
193
+ */
194
+ listInspectionTargets(): SessionBrowserInspectionTarget[];
195
+ /**
196
+ * Resolve one semantic inspection target to an exact Runtime-local Page
197
+ * endpoint. The physical Page identity never enters discovery or Direct RPC.
198
+ */
199
+ getInspectionPageEndpoint(input: RuntimeBrowserPageMutationParams): Promise<SessionBrowserInspectionEndpoint>;
170
200
  getState(input: RuntimeBrowserStateGetParams): Promise<RuntimeBrowserState | null>;
171
201
  /**
172
202
  * Runtime-local automation handoff. This method is deliberately absent from
@@ -4,6 +4,7 @@ import { parseRuntimeBrowserEndpointDescriptor, } from "@rynx-ai/protocol/runtim
4
4
  const MAX_HOST_PAGE_ID_CHARS = 2_048;
5
5
  const MAX_PAGE_ID_FACTORY_ATTEMPTS = 64;
6
6
  const MAX_RETIRED_HOST_PAGE_IDS = 64;
7
+ const INSPECTION_PAGE_CDP_PATH_PATTERN = /^\/devtools\/page\/[A-Za-z0-9._~%-]+$/;
7
8
  export class SessionBrowserSurfaceUnsupportedError extends Error {
8
9
  constructor() {
9
10
  super("Browser Host does not support presentation");
@@ -53,6 +54,81 @@ export class SessionBrowserService {
53
54
  throw new Error("Browser boot generation seed must be a nonnegative safe integer");
54
55
  }
55
56
  }
57
+ /** Number of Session Browsers that still own a physical Host handle. */
58
+ activeBrowserCount() {
59
+ return this.records.size;
60
+ }
61
+ /**
62
+ * Snapshot the current in-memory inspection inventory. Discovery is
63
+ * deliberately passive: it neither creates Browsers nor asks a Host to
64
+ * reconcile physical state.
65
+ */
66
+ listInspectionTargets() {
67
+ const targets = [];
68
+ for (const record of this.records.values()) {
69
+ if (record.status !== "ready" || !record.handle.getPageCdpEndpoint)
70
+ continue;
71
+ for (const pageId of record.pageOrder) {
72
+ const page = record.pagesById.get(pageId);
73
+ if (!page)
74
+ continue;
75
+ targets.push({
76
+ sessionId: record.sessionId,
77
+ browserGeneration: record.browserGeneration,
78
+ pageId,
79
+ executionBackend: record.executionBackend,
80
+ url: page.url,
81
+ title: page.title,
82
+ });
83
+ }
84
+ }
85
+ return targets;
86
+ }
87
+ /**
88
+ * Resolve one semantic inspection target to an exact Runtime-local Page
89
+ * endpoint. The physical Page identity never enters discovery or Direct RPC.
90
+ */
91
+ async getInspectionPageEndpoint(input) {
92
+ const params = parseInput(() => parseRuntimeBrowserPageMutationParams(input, "Browser inspection"), "Browser inspection request is invalid");
93
+ return this.exclusive(params.sessionId, async () => {
94
+ this.ensureRunning();
95
+ await this.ensureSessionExists(params.sessionId);
96
+ const record = this.requireReadyRecord(params.sessionId, params.browserGeneration);
97
+ await this.reconcileForMutation(record);
98
+ const page = record.pagesById.get(params.pageId);
99
+ if (!page) {
100
+ throw new SessionBrowserServiceError("not_found", "Browser Page was not found");
101
+ }
102
+ const resolveEndpoint = record.handle.getPageCdpEndpoint;
103
+ if (!resolveEndpoint) {
104
+ throw new SessionBrowserServiceError("unavailable", "Browser Host does not support inspection");
105
+ }
106
+ try {
107
+ const endpoint = await resolveEndpoint.call(record.handle, page.hostPageId);
108
+ const parsed = parseRuntimeBrowserEndpointDescriptor({
109
+ sessionId: record.sessionId,
110
+ browserGeneration: record.browserGeneration,
111
+ executionBackend: record.executionBackend,
112
+ endpoint: endpoint.endpoint,
113
+ engineVersion: endpoint.engineVersion,
114
+ });
115
+ if (!INSPECTION_PAGE_CDP_PATH_PATTERN.test(new URL(parsed.endpoint).pathname)) {
116
+ throw new Error("Browser Host returned a non-Page inspection endpoint");
117
+ }
118
+ return {
119
+ endpoint: parsed.endpoint,
120
+ engineVersion: parsed.engineVersion,
121
+ };
122
+ }
123
+ catch (error) {
124
+ if (error instanceof SessionBrowserHostError &&
125
+ (error.code === "unavailable" || error.code === "outcome_unknown")) {
126
+ record.status = "unavailable";
127
+ }
128
+ throw mapHostError(error, "Browser inspection endpoint is unavailable");
129
+ }
130
+ });
131
+ }
56
132
  async getState(input) {
57
133
  const params = parseInput(() => parseRuntimeBrowserStateGetParams(input), "Browser state request is invalid");
58
134
  return this.exclusive(params.sessionId, async () => {
@@ -88,6 +164,7 @@ export class SessionBrowserService {
88
164
  executionBackend: record.executionBackend,
89
165
  endpoint: endpoint.endpoint,
90
166
  engineVersion: endpoint.engineVersion,
167
+ ...(endpoint.pageTargetId ? { pageTargetId: endpoint.pageTargetId } : {}),
91
168
  });
92
169
  }
93
170
  catch (error) {
@@ -152,11 +229,20 @@ export class SessionBrowserService {
152
229
  this.ensureRunning();
153
230
  await this.ensureSessionExists(params.sessionId);
154
231
  const existing = this.records.get(params.sessionId);
155
- if (existing?.status === "ready" || existing?.status === "opening") {
156
- if (existing.status === "ready")
157
- await this.reconcileForRead(existing);
232
+ if (existing?.status === "opening") {
158
233
  return this.project(existing);
159
234
  }
235
+ if (existing?.status === "ready") {
236
+ try {
237
+ await this.reconcileForRead(existing);
238
+ return this.project(existing);
239
+ }
240
+ catch {
241
+ // An App Host may have gone away immediately before this open. The
242
+ // failed reconciliation marks the old generation unavailable, so an
243
+ // idempotent open can recreate it on the current preferred Host.
244
+ }
245
+ }
160
246
  if (existing)
161
247
  await this.closeUnavailableForRecreate(existing);
162
248
  return this.createBrowser(params);
@@ -7,12 +7,13 @@ export interface SessionBrowserSurfaceCoordinatorOptions {
7
7
  maxPendingEventBytes?: number;
8
8
  }
9
9
  /**
10
- * Owns the one-stream-per-Page lease, frame acknowledgement, and human-driver
11
- * rules above physical Browser capture. It never exposes a Host Page ID or CDP.
10
+ * Owns one physical capture stream per Page, fans it out to bounded logical
11
+ * subscribers, and arbitrates the single human-driver lease. It never exposes a
12
+ * Host Page ID or CDP.
12
13
  */
13
14
  export declare class SessionBrowserSurfaceCoordinator implements DirectRuntimeBrowserSurfaceHost {
14
15
  private readonly browsers;
15
- private readonly attachments;
16
+ private readonly pages;
16
17
  private readonly pageQueues;
17
18
  private readonly frameAcknowledgeTimeoutMs;
18
19
  private readonly maxPendingEvents;