@rynx-ai/daemon 0.1.11-beta.45 → 0.1.11-beta.49

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.
@@ -20946,7 +20946,7 @@ var require_websocket = __commonJS({
20946
20946
  var http = __require("http");
20947
20947
  var net = __require("net");
20948
20948
  var tls = __require("tls");
20949
- var { randomBytes, createHash: createHash3 } = __require("crypto");
20949
+ var { randomBytes, createHash: createHash4 } = __require("crypto");
20950
20950
  var { Duplex, Readable } = __require("stream");
20951
20951
  var { URL: URL2 } = __require("url");
20952
20952
  var PerMessageDeflate = require_permessage_deflate();
@@ -21614,7 +21614,7 @@ var require_websocket = __commonJS({
21614
21614
  abortHandshake(websocket, socket, "Invalid Upgrade header");
21615
21615
  return;
21616
21616
  }
21617
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
21617
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
21618
21618
  if (res.headers["sec-websocket-accept"] !== digest) {
21619
21619
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
21620
21620
  return;
@@ -21983,7 +21983,7 @@ var require_websocket_server = __commonJS({
21983
21983
  var EventEmitter = __require("events");
21984
21984
  var http = __require("http");
21985
21985
  var { Duplex } = __require("stream");
21986
- var { createHash: createHash3 } = __require("crypto");
21986
+ var { createHash: createHash4 } = __require("crypto");
21987
21987
  var extension = require_extension();
21988
21988
  var PerMessageDeflate = require_permessage_deflate();
21989
21989
  var subprotocol = require_subprotocol();
@@ -22290,7 +22290,7 @@ var require_websocket_server = __commonJS({
22290
22290
  );
22291
22291
  }
22292
22292
  if (this._state > RUNNING) return abortHandshake(socket, 503);
22293
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
22293
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
22294
22294
  const headers = [
22295
22295
  "HTTP/1.1 101 Switching Protocols",
22296
22296
  "Upgrade: websocket",
@@ -111472,7 +111472,7 @@ import path9 from "node:path";
111472
111472
 
111473
111473
  // src/host-adapters.ts
111474
111474
  import { AsyncLocalStorage } from "node:async_hooks";
111475
- import { createHash as createHash2 } from "node:crypto";
111475
+ import { createHash as createHash3 } from "node:crypto";
111476
111476
 
111477
111477
  // ../../packages/protocol/dist/session-interaction.js
111478
111478
  var SESSION_INTERACTION_STRUCTURAL_LIMITS = {
@@ -126107,6 +126107,8 @@ var envSchema = external_exports.object({
126107
126107
  RYNX_SESSION_PORTAL_HOST: external_exports.string().default("127.0.0.1"),
126108
126108
  RYNX_SESSION_PORTAL_PORT: external_exports.coerce.number().int().positive().optional(),
126109
126109
  LOG_LEVEL: external_exports.string().default("info"),
126110
+ /** Operator-selected native helper; omit to use the bundled pinned engine. */
126111
+ RYNX_AGENT_BROWSER_EXECUTABLE: external_exports.string().optional(),
126110
126112
  /**
126111
126113
  * Default agent runtime for conversations that haven't picked one via the
126112
126114
  * `/runtime` card. `codex` keeps the legacy behaviour; `traex` targets the
@@ -126323,6 +126325,10 @@ async function collectLiveRun(generator) {
126323
126325
  return answer || deltas.join("");
126324
126326
  }
126325
126327
 
126328
+ // ../../packages/core/dist/diagnostic-log.js
126329
+ import { createHash, randomUUID } from "node:crypto";
126330
+ var processInstance = randomUUID();
126331
+
126326
126332
  // ../../packages/core/dist/steer.js
126327
126333
  var SteerController = class {
126328
126334
  listeners = /* @__PURE__ */ new Set();
@@ -126352,10 +126358,10 @@ function toErrorMessage(error51) {
126352
126358
  }
126353
126359
 
126354
126360
  // ../../packages/core/dist/session-id.js
126355
- import { randomUUID } from "node:crypto";
126361
+ import { randomUUID as randomUUID2 } from "node:crypto";
126356
126362
  var SESSION_ID_PREFIX = "sess_";
126357
126363
  function newSessionId() {
126358
- return `${SESSION_ID_PREFIX}${randomUUID()}`;
126364
+ return `${SESSION_ID_PREFIX}${randomUUID2()}`;
126359
126365
  }
126360
126366
 
126361
126367
  // ../../packages/protocol/dist/control.js
@@ -126501,11 +126507,11 @@ var MAX_TOTAL_BYTES = 1024 * 1024 * 1024;
126501
126507
  var STREAM_BYTES = 256 * 1024;
126502
126508
 
126503
126509
  // ../../packages/core/dist/conversation-directory.js
126504
- import { createHash, randomUUID as randomUUID2 } from "node:crypto";
126510
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
126505
126511
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
126506
126512
  import path4 from "node:path";
126507
126513
  function deriveConversationShortId(key) {
126508
- return createHash("sha256").update(key).digest("hex").slice(0, 6);
126514
+ return createHash2("sha256").update(key).digest("hex").slice(0, 6);
126509
126515
  }
126510
126516
  var FileConversationDirectory = class {
126511
126517
  filePath;
@@ -126584,7 +126590,7 @@ var FileConversationDirectory = class {
126584
126590
  }
126585
126591
  async writeAll(data) {
126586
126592
  await mkdir(path4.dirname(this.filePath), { recursive: true });
126587
- const tmp = `${this.filePath}.${randomUUID2()}.tmp`;
126593
+ const tmp = `${this.filePath}.${randomUUID3()}.tmp`;
126588
126594
  await writeFile(tmp, `${JSON.stringify(data, null, 2)}
126589
126595
  `, "utf8");
126590
126596
  await rename(tmp, this.filePath);
@@ -127251,7 +127257,7 @@ function hostErrorCode(error51) {
127251
127257
  return error51 && typeof error51 === "object" && "code" in error51 && typeof error51.code === "string" ? error51.code : void 0;
127252
127258
  }
127253
127259
  function stableOperationId(kind, ...parts) {
127254
- const digest = createHash2("sha256").update(parts.join("\0")).digest("hex");
127260
+ const digest = createHash3("sha256").update(parts.join("\0")).digest("hex");
127255
127261
  return `${kind}-${digest}`;
127256
127262
  }
127257
127263
  var AsyncEventQueue = class {
@@ -127346,7 +127352,7 @@ function isRecord(value) {
127346
127352
  }
127347
127353
 
127348
127354
  // src/lark-config-store.ts
127349
- import { randomUUID as randomUUID3 } from "node:crypto";
127355
+ import { randomUUID as randomUUID4 } from "node:crypto";
127350
127356
  import {
127351
127357
  chmodSync,
127352
127358
  existsSync,
@@ -127373,7 +127379,7 @@ var LarkConfigStore = class {
127373
127379
  }
127374
127380
  upsert(input) {
127375
127381
  const state = this.read();
127376
- const id = input.id ?? `instance-${randomUUID3().slice(0, 8)}`;
127382
+ const id = input.id ?? `instance-${randomUUID4().slice(0, 8)}`;
127377
127383
  if (!INSTANCE_ID_PATTERN.test(id)) throw new Error("Lark instance id is invalid");
127378
127384
  const existing = state.instances.find((instance2) => instance2.id === id);
127379
127385
  const secret = input.appSecret?.trim() || existing?.appSecret;
@@ -127430,7 +127436,7 @@ var LarkConfigStore = class {
127430
127436
  return parseState(JSON.parse(readFileSync(this.file, "utf8")));
127431
127437
  }
127432
127438
  write(state) {
127433
- const temporary = `${this.file}.tmp-${randomUUID3()}`;
127439
+ const temporary = `${this.file}.tmp-${randomUUID4()}`;
127434
127440
  try {
127435
127441
  writeFileSync(temporary, `${JSON.stringify(state, null, 2)}
127436
127442
  `, {
@@ -127575,7 +127581,7 @@ import {
127575
127581
  writeFileSync as writeFileSync2
127576
127582
  } from "node:fs";
127577
127583
  import path7 from "node:path";
127578
- import { randomUUID as randomUUID4 } from "node:crypto";
127584
+ import { randomUUID as randomUUID5 } from "node:crypto";
127579
127585
  var LarkRuntimeStateStore = class {
127580
127586
  file;
127581
127587
  constructor(dataDir) {
@@ -127605,7 +127611,7 @@ var LarkRuntimeStateStore = class {
127605
127611
  }
127606
127612
  }
127607
127613
  write(state) {
127608
- const temporary = `${this.file}.tmp-${randomUUID4()}`;
127614
+ const temporary = `${this.file}.tmp-${randomUUID5()}`;
127609
127615
  try {
127610
127616
  writeFileSync2(temporary, `${JSON.stringify(state)}
127611
127617
  `, {
@@ -127664,13 +127670,13 @@ function parseHealth(value) {
127664
127670
 
127665
127671
  // src/lark.ts
127666
127672
  import { execFile } from "node:child_process";
127667
- import { randomUUID as randomUUID6 } from "node:crypto";
127673
+ import { randomUUID as randomUUID7 } from "node:crypto";
127668
127674
  import path8 from "node:path";
127669
127675
  import { promisify } from "node:util";
127670
127676
 
127671
127677
  // src/lark-card-stream.ts
127672
127678
  import { Buffer as Buffer2 } from "node:buffer";
127673
- import { randomUUID as randomUUID5 } from "node:crypto";
127679
+ import { randomUUID as randomUUID6 } from "node:crypto";
127674
127680
  var OUTPUT_MAX_BYTES = 2048;
127675
127681
  var REASONING_MAX_BYTES = 4096;
127676
127682
  var AGENT_MESSAGE_MAX_BYTES = 8192;
@@ -127931,7 +127937,7 @@ var LarkResponseCardController = class {
127931
127937
  this.mounted.add(ELEMENT_IDS.status_row);
127932
127938
  this.stopButtonMounted = Boolean(this.stopButton);
127933
127939
  this.lastRendered.set(ELEMENT_IDS.status, renderSessionStatus("running", this.meta));
127934
- const uuid3 = randomUUID5();
127940
+ const uuid3 = randomUUID6();
127935
127941
  if (replyTo.messageId) {
127936
127942
  const { messageId: messageId2 } = await this.sender.replyInteractive({
127937
127943
  messageId: replyTo.messageId,
@@ -128138,7 +128144,7 @@ var LarkResponseCardController = class {
128138
128144
  cardId,
128139
128145
  sequence,
128140
128146
  actions: JSON.stringify(actions),
128141
- uuid: randomUUID5()
128147
+ uuid: randomUUID6()
128142
128148
  });
128143
128149
  } catch (error51) {
128144
128150
  this.logger?.log({
@@ -129495,7 +129501,7 @@ var LarkMessageIngestor = class {
129495
129501
  threadId: sourceThreadId,
129496
129502
  receiveId,
129497
129503
  receiveIdType,
129498
- uuid: randomUUID6()
129504
+ uuid: randomUUID7()
129499
129505
  });
129500
129506
  this.logger.log({
129501
129507
  event: "resume.forwarded",
@@ -130030,7 +130036,7 @@ ${list}`;
130030
130036
  threadId: record2.threadId,
130031
130037
  receiveId: target.receiveId,
130032
130038
  receiveIdType: target.receiveIdType,
130033
- uuid: randomUUID6()
130039
+ uuid: randomUUID7()
130034
130040
  });
130035
130041
  await this.sendReplyText(event, `\u5DF2\u628A\u8BDD\u9898\u300C${record2.title}\u300D\u8F6C\u53D1\u5230\u5F53\u524D\u4F1A\u8BDD\u3002`);
130036
130042
  } catch (error51) {
@@ -130049,7 +130055,7 @@ ${list}`;
130049
130055
  throw new Error("card sender unavailable");
130050
130056
  }
130051
130057
  const { cardId } = await sender.createCard({ cardJson });
130052
- const uuid3 = randomUUID6();
130058
+ const uuid3 = randomUUID7();
130053
130059
  if (event.message.thread_id && sender.replyInteractive) {
130054
130060
  const { messageId } = await sender.replyInteractive({
130055
130061
  messageId: event.message.message_id,
@@ -130135,7 +130141,7 @@ ${transcript}` : header;
130135
130141
  const sent = await sender.sendText({
130136
130142
  chatId: event.message.chat_id,
130137
130143
  text: body,
130138
- uuid: randomUUID6()
130144
+ uuid: randomUUID7()
130139
130145
  });
130140
130146
  if (!sent.threadId) {
130141
130147
  await this.sendReplyText(event, "fork \u5931\u8D25\uFF1A\u672A\u80FD\u521B\u5EFA\u65B0\u8BDD\u9898\u3002");
@@ -130151,9 +130157,9 @@ ${transcript}` : header;
130151
130157
  const created = await sender.createChat({
130152
130158
  name: `${baseName} - fork`,
130153
130159
  userIdList,
130154
- uuid: randomUUID6()
130160
+ uuid: randomUUID7()
130155
130161
  });
130156
- await sender.sendText({ chatId: created.chatId, text: body, uuid: randomUUID6() });
130162
+ await sender.sendText({ chatId: created.chatId, text: body, uuid: randomUUID7() });
130157
130163
  newSessionKey = `lark:${tenantKey}:chat:${created.chatId}`;
130158
130164
  newChatId = created.chatId;
130159
130165
  }
@@ -20946,7 +20946,7 @@ var require_websocket = __commonJS({
20946
20946
  var http = __require("http");
20947
20947
  var net = __require("net");
20948
20948
  var tls = __require("tls");
20949
- var { randomBytes, createHash } = __require("crypto");
20949
+ var { randomBytes, createHash: createHash2 } = __require("crypto");
20950
20950
  var { Duplex, Readable } = __require("stream");
20951
20951
  var { URL: URL2 } = __require("url");
20952
20952
  var PerMessageDeflate = require_permessage_deflate();
@@ -21614,7 +21614,7 @@ var require_websocket = __commonJS({
21614
21614
  abortHandshake(websocket, socket, "Invalid Upgrade header");
21615
21615
  return;
21616
21616
  }
21617
- const digest = createHash("sha1").update(key + GUID).digest("base64");
21617
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
21618
21618
  if (res.headers["sec-websocket-accept"] !== digest) {
21619
21619
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
21620
21620
  return;
@@ -21983,7 +21983,7 @@ var require_websocket_server = __commonJS({
21983
21983
  var EventEmitter = __require("events");
21984
21984
  var http = __require("http");
21985
21985
  var { Duplex } = __require("stream");
21986
- var { createHash } = __require("crypto");
21986
+ var { createHash: createHash2 } = __require("crypto");
21987
21987
  var extension = require_extension();
21988
21988
  var PerMessageDeflate = require_permessage_deflate();
21989
21989
  var subprotocol = require_subprotocol();
@@ -22290,7 +22290,7 @@ var require_websocket_server = __commonJS({
22290
22290
  );
22291
22291
  }
22292
22292
  if (this._state > RUNNING) return abortHandshake(socket, 503);
22293
- const digest = createHash("sha1").update(key + GUID).digest("base64");
22293
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
22294
22294
  const headers = [
22295
22295
  "HTTP/1.1 101 Switching Protocols",
22296
22296
  "Upgrade: websocket",
@@ -111467,7 +111467,7 @@ ${lines.join("\n")}
111467
111467
  });
111468
111468
 
111469
111469
  // src/settings.ts
111470
- import { randomUUID as randomUUID3 } from "node:crypto";
111470
+ import { randomUUID as randomUUID4 } from "node:crypto";
111471
111471
 
111472
111472
  // ../../packages/protocol/dist/session-interaction.js
111473
111473
  var SESSION_INTERACTION_STRUCTURAL_LIMITS = {
@@ -126043,6 +126043,8 @@ var envSchema = external_exports.object({
126043
126043
  RYNX_SESSION_PORTAL_HOST: external_exports.string().default("127.0.0.1"),
126044
126044
  RYNX_SESSION_PORTAL_PORT: external_exports.coerce.number().int().positive().optional(),
126045
126045
  LOG_LEVEL: external_exports.string().default("info"),
126046
+ /** Operator-selected native helper; omit to use the bundled pinned engine. */
126047
+ RYNX_AGENT_BROWSER_EXECUTABLE: external_exports.string().optional(),
126046
126048
  /**
126047
126049
  * Default agent runtime for conversations that haven't picked one via the
126048
126050
  * `/runtime` card. `codex` keeps the legacy behaviour; `traex` targets the
@@ -126226,6 +126228,10 @@ var agentSpecSchema = external_exports.object({
126226
126228
  params: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
126227
126229
  });
126228
126230
 
126231
+ // ../../packages/core/dist/diagnostic-log.js
126232
+ import { createHash, randomUUID } from "node:crypto";
126233
+ var processInstance = randomUUID();
126234
+
126229
126235
  // ../../packages/protocol/dist/control.js
126230
126236
  var BROWSER_PROGRESS_MAX_MESSAGE_BYTES = 2 * 1024;
126231
126237
  var BROWSER_PROGRESS_MAX_TOTAL_BYTES = 32 * 1024;
@@ -126387,7 +126393,7 @@ var HostAgentCatalog = class {
126387
126393
  };
126388
126394
 
126389
126395
  // src/lark-config-store.ts
126390
- import { randomUUID } from "node:crypto";
126396
+ import { randomUUID as randomUUID2 } from "node:crypto";
126391
126397
  import {
126392
126398
  chmodSync,
126393
126399
  existsSync,
@@ -126414,7 +126420,7 @@ var LarkConfigStore = class {
126414
126420
  }
126415
126421
  upsert(input) {
126416
126422
  const state = this.read();
126417
- const id = input.id ?? `instance-${randomUUID().slice(0, 8)}`;
126423
+ const id = input.id ?? `instance-${randomUUID2().slice(0, 8)}`;
126418
126424
  if (!INSTANCE_ID_PATTERN.test(id)) throw new Error("Lark instance id is invalid");
126419
126425
  const existing = state.instances.find((instance2) => instance2.id === id);
126420
126426
  const secret = input.appSecret?.trim() || existing?.appSecret;
@@ -126471,7 +126477,7 @@ var LarkConfigStore = class {
126471
126477
  return parseState(JSON.parse(readFileSync(this.file, "utf8")));
126472
126478
  }
126473
126479
  write(state) {
126474
- const temporary = `${this.file}.tmp-${randomUUID()}`;
126480
+ const temporary = `${this.file}.tmp-${randomUUID2()}`;
126475
126481
  try {
126476
126482
  writeFileSync(temporary, `${JSON.stringify(state, null, 2)}
126477
126483
  `, {
@@ -126522,7 +126528,7 @@ import {
126522
126528
  writeFileSync as writeFileSync2
126523
126529
  } from "node:fs";
126524
126530
  import path5 from "node:path";
126525
- import { randomUUID as randomUUID2 } from "node:crypto";
126531
+ import { randomUUID as randomUUID3 } from "node:crypto";
126526
126532
  var LarkRuntimeStateStore = class {
126527
126533
  file;
126528
126534
  constructor(dataDir) {
@@ -126552,7 +126558,7 @@ var LarkRuntimeStateStore = class {
126552
126558
  }
126553
126559
  }
126554
126560
  write(state) {
126555
- const temporary = `${this.file}.tmp-${randomUUID2()}`;
126561
+ const temporary = `${this.file}.tmp-${randomUUID3()}`;
126556
126562
  try {
126557
126563
  writeFileSync2(temporary, `${JSON.stringify(state)}
126558
126564
  `, {
@@ -126790,7 +126796,7 @@ async function createLarkPluginSettings(context, options = {}) {
126790
126796
  if (method === "authorization.start") {
126791
126797
  if (authorization?.state === "waiting") authorization.controller.abort();
126792
126798
  const session = {
126793
- id: randomUUID3(),
126799
+ id: randomUUID4(),
126794
126800
  state: "waiting",
126795
126801
  controller: new AbortController(),
126796
126802
  status: "Preparing QR code\u2026"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/plugin-channel-lark",
3
- "version": "0.1.11-beta.45",
3
+ "version": "0.1.11-beta.49",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -1,5 +1,7 @@
1
1
  import { spawn, } from "node:child_process";
2
2
  import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { rynxHome, teeDiagnosticStream } from "@rynx-ai/core";
3
5
  export const APP_BROWSER_HOST_SIDECAR_FLAG = "--rynx-browser-host-sidecar";
4
6
  export const APP_BROWSER_HOST_BOOTSTRAP_TYPE = "rynx.browser-host.bootstrap";
5
7
  export const APP_BROWSER_HOST_READY_TYPE = "rynx.browser-host.ready";
@@ -182,13 +184,16 @@ export class AppBrowserHostSupervisor {
182
184
  try {
183
185
  child = this.spawnProcess(this.launch.executable, args, {
184
186
  env: { ...this.childEnv },
185
- stdio: ["ignore", "ignore", "ignore", "ipc"],
187
+ stdio: ["ignore", "pipe", "pipe", "ipc"],
186
188
  });
187
189
  }
188
190
  catch (error) {
189
191
  throw supervisorError("failed to spawn App browser host", error);
190
192
  }
191
193
  this.child = child;
194
+ const logRoot = path.join(rynxHome(), "logs", "browser", "host", randomUUID());
195
+ teeDiagnosticStream(child.stdout, path.join(logRoot, "stdout.log"));
196
+ teeDiagnosticStream(child.stderr, path.join(logRoot, "stderr.log"));
192
197
  this.connectedChild = undefined;
193
198
  const onLifecycleError = () => {
194
199
  if (this.connectedChild === child)
@@ -29,6 +29,7 @@ import { installedDaemonVersion } from "./entry-path.js";
29
29
  import { isChromeForTestingHostSupported } from "./chrome-for-testing-store.js";
30
30
  import { ChromeInspectionManager, } from "./chrome-inspection-manager.js";
31
31
  import { createHeadlessBrowserHost } from "./headless-browser-host.js";
32
+ import { PageAutomationManager } from "./page-automation-manager.js";
32
33
  import { db } from "./db.js";
33
34
  import { acquireDaemonOwner } from "./daemon-owner.js";
34
35
  import { DaemonDirectRuntimeAuthenticator } from "./direct-runtime-authenticator.js";
@@ -131,7 +132,8 @@ function toMarketplaceItem(record) {
131
132
  }
132
133
  export function daemonActivityBlocksShutdown(activity) {
133
134
  return activity.runningTurns > 0
134
- || activity.pendingInteractions > 0;
135
+ || activity.pendingInteractions > 0
136
+ || (activity.pendingRuntimeOperations ?? 0) > 0;
135
137
  }
136
138
  function defaultWarn(message) {
137
139
  console.warn(JSON.stringify({ level: "warn", type: "channel-registry", msg: message }));
@@ -383,6 +385,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
383
385
  };
384
386
  let machineSessions;
385
387
  let sessionBrowsers;
388
+ let pageAutomation;
386
389
  const pluginRuntime = {
387
390
  bindHostServices: (services) => pluginSupervisor.bindHostServices({
388
391
  ...services,
@@ -466,6 +469,11 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
466
469
  },
467
470
  }, {
468
471
  admissionReserve: reserveAdmission,
472
+ onObservationError: (_error, target) => warn(`Browser observation temporarily stale: Session ${target.sessionId}, generation ${target.browserGeneration}`),
473
+ });
474
+ pageAutomation = new PageAutomationManager(sessionBrowsers, {
475
+ onCleanupError: () => warn("Browser page helper cleanup failed"),
476
+ isHumanControlled: (binding) => sessionBrowserSurfaces.isBrowserHumanControlled(binding.sessionId, binding.browserGeneration),
469
477
  });
470
478
  const sessionEmulators = control.emulator
471
479
  ? new SessionEmulatorService({
@@ -610,12 +618,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
610
618
  const runtimeActivity = sessionRuntimeServices.sessionRuntimeIndex.activitySnapshot();
611
619
  const activity = {
612
620
  ...runtimeActivity,
613
- // A terminal submission keeps its own admission reservation until the
614
- // first response or native rotation is visible. Failed process-tree
615
- // cleanup releases the reservation but remains pinned here, so an
616
- // idle check returns busy instead of hanging or killing hidden work.
617
- runningTurns: runtimeActivity.runningTurns
618
- + sessionRuntimeServices.runnerManager.pendingTerminalInputCount(),
621
+ pendingRuntimeOperations: sessionRuntimeServices.runnerManager.pendingNativeOperationCount(),
619
622
  activeTerminals: sessionTerminals.activeTerminalCount(),
620
623
  activeBrowsers: sessionBrowsers.activeBrowserCount(),
621
624
  };
@@ -750,6 +753,7 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
750
753
  sessionLifecycle: sessionResourceLifecycle,
751
754
  sessionTerminals,
752
755
  runtimeLocalBrowser: {
756
+ executeForSession: (sessionId, command) => pageAutomation.execute(sessionId, command),
753
757
  authorizeCredential: (credential) => sessionBrowserCapabilities.verify(credential.sessionId, credential.capability),
754
758
  endpointForCredential: async (credential) => {
755
759
  if (!sessionBrowserCapabilities.verify(credential.sessionId, credential.capability))
@@ -805,6 +809,12 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
805
809
  catch (startupError) {
806
810
  const rollbackErrors = [startupError];
807
811
  server?.stopAccepting();
812
+ try {
813
+ await pageAutomation?.shutdown();
814
+ }
815
+ catch (error) {
816
+ rollbackErrors.push(error);
817
+ }
808
818
  if (chromeInspectionManager) {
809
819
  try {
810
820
  await chromeInspectionManager.shutdown();
@@ -872,6 +882,12 @@ export async function startRynxDaemonServer({ config, warn = defaultWarn, onShut
872
882
  let shutdownComplete = false;
873
883
  try {
874
884
  const shutdownErrors = [];
885
+ try {
886
+ await pageAutomation.shutdown();
887
+ }
888
+ catch (error) {
889
+ shutdownErrors.push(error);
890
+ }
875
891
  try {
876
892
  await chromeInspectionManager.shutdown();
877
893
  }