@parall/daemon 1.50.0 → 1.50.1

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 (38) hide show
  1. package/bundle/manifest.json +11 -11
  2. package/bundle/parall-browser-pod.js +267 -104
  3. package/bundle/parall-claude-agent.js +25 -18
  4. package/bundle/parall-codex-agent.js +25 -18
  5. package/bundle/parall-daemon.js +317 -184
  6. package/dist/browser-pod.d.ts.map +1 -1
  7. package/dist/browser-pod.js +9 -14
  8. package/dist/browser-profile-viewer-control.d.ts +15 -0
  9. package/dist/browser-profile-viewer-control.d.ts.map +1 -0
  10. package/dist/browser-profile-viewer-control.js +27 -0
  11. package/dist/clip-runtime/bb-viewer-command-client.d.ts +19 -0
  12. package/dist/clip-runtime/bb-viewer-command-client.d.ts.map +1 -0
  13. package/dist/clip-runtime/bb-viewer-command-client.js +89 -0
  14. package/dist/clip-runtime/browser-profile-manager.d.ts +3 -1
  15. package/dist/clip-runtime/browser-profile-manager.d.ts.map +1 -1
  16. package/dist/clip-runtime/browser-profile-manager.js +2 -2
  17. package/dist/clip-runtime/browser-viewer-streamer.d.ts +7 -7
  18. package/dist/clip-runtime/browser-viewer-streamer.d.ts.map +1 -1
  19. package/dist/clip-runtime/browser-viewer-streamer.js +39 -47
  20. package/dist/clip-runtime/clip-provider.d.ts +3 -2
  21. package/dist/clip-runtime/clip-provider.d.ts.map +1 -1
  22. package/dist/clip-runtime/clip-provider.js +13 -6
  23. package/dist/clip-runtime/hosted-viewer-command-queue.d.ts +43 -0
  24. package/dist/clip-runtime/hosted-viewer-command-queue.d.ts.map +1 -0
  25. package/dist/clip-runtime/hosted-viewer-command-queue.js +72 -0
  26. package/dist/clip-runtime/index.d.ts +1 -0
  27. package/dist/clip-runtime/index.d.ts.map +1 -1
  28. package/dist/clip-runtime/index.js +1 -0
  29. package/dist/clip-runtime/viewer-command-deadline.d.ts +14 -0
  30. package/dist/clip-runtime/viewer-command-deadline.d.ts.map +1 -0
  31. package/dist/clip-runtime/viewer-command-deadline.js +29 -0
  32. package/dist/clip-runtime/viewer-command-error.d.ts +18 -0
  33. package/dist/clip-runtime/viewer-command-error.d.ts.map +1 -0
  34. package/dist/clip-runtime/viewer-command-error.js +23 -0
  35. package/dist/supervisor.d.ts +0 -8
  36. package/dist/supervisor.d.ts.map +1 -1
  37. package/dist/supervisor.js +3 -32
  38. package/package.json +6 -6
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.50.0",
3
- "built_at": "2026-07-27T10:07:52.208Z",
2
+ "version": "1.50.1",
3
+ "built_at": "2026-07-28T15:25:57.441Z",
4
4
  "min_node_version": "20.0.0",
5
5
  "files": {
6
6
  "bb-browser-daemon.js": {
@@ -16,29 +16,29 @@
16
16
  "size": 18
17
17
  },
18
18
  "parall-browser-pod.js": {
19
- "sha256": "0025fc6f85af4dcfe22a6d532c322bd2bf064f83378d88c77cbcca00a469ed82",
20
- "size": 2901740
19
+ "sha256": "f20c74453ddfbef10528afc1d9b6c4de48fd4a780ddb715431d61185c3454b20",
20
+ "size": 2908552
21
21
  },
22
22
  "parall-channel-exec.js": {
23
23
  "sha256": "7c2a6e12483a45e9eb4a42cd7d4cdd3c4fa21dd09ac1347d9a3e177b4ddee930",
24
24
  "size": 7220
25
25
  },
26
26
  "parall-claude-agent.js": {
27
- "sha256": "3786edb7e4d2dc22a95f2789416ee1fa1bf191e166d443c868cd8772a6033278",
28
- "size": 2737538
27
+ "sha256": "38048b9d69561a7d92ddc97b6322ae215e2e59dbcbbb6353bfa371632683a17c",
28
+ "size": 2737754
29
29
  },
30
30
  "parall-codex-agent.js": {
31
- "sha256": "ba13d01de7a89860d75bbc1abd5ea5c9c605cc9104161a8d7960c38f84f7870c",
32
- "size": 2779278
31
+ "sha256": "c65c89982b58f6e1aea155991d364f1325eef166fe0fb92ab989ea477dfe3dd3",
32
+ "size": 2779494
33
33
  },
34
34
  "parall-daemon.js": {
35
- "sha256": "a135d16586ea01a0ed3aa811dac509827efc76d2eb14de6430e1421590afc70e",
36
- "size": 2963977
35
+ "sha256": "fd0bf688bcf0df4227c7eef61907276437b2f40961e4ebba28c12d2dda34de73",
36
+ "size": 2969136
37
37
  },
38
38
  "parall-openclaw-agent.js": {
39
39
  "sha256": "856a1c3a9ae0ffef8efe2481fa1171dbeb1d67cccb88616aa9bf16da96a69355",
40
40
  "size": 9923
41
41
  }
42
42
  },
43
- "signature": "KflWD7Xe1CWN7YZuBW3BTXirw4TfZITSwiKrRO+SU/OXNfXf3IC0nm4OWsR5zHb9J+y8cmqzpK2Zz8vXXSgwDw=="
43
+ "signature": "VOZtJbTWb3YvTHoc3hGgfBw3bnL4JM9jdTXmPW6rdc3YpZXCunf//CcfviSu0Acn/p6vnHSEizSX00RAJbrCAw=="
44
44
  }
@@ -63495,6 +63495,17 @@ function clearAllProviderCreds(env) {
63495
63495
  delete env.PRLL_CLAUDE_ALLOW_API_KEY;
63496
63496
  }
63497
63497
 
63498
+ // ts/sdk/dist/browser-viewer.js
63499
+ var BROWSER_VIEWER_READINESS_TIMEOUT_MS = 6e4;
63500
+ function browserViewerRequestOptions(command, opts) {
63501
+ if (command !== "stream.answer" && command !== "stream.switch")
63502
+ return opts;
63503
+ return {
63504
+ ...opts,
63505
+ timeoutMs: Math.max(opts?.timeoutMs ?? 0, BROWSER_VIEWER_READINESS_TIMEOUT_MS)
63506
+ };
63507
+ }
63508
+
63498
63509
  // ts/sdk/dist/constants.js
63499
63510
  var API_BASE = "/api/v1";
63500
63511
  var WIKI_BASE = "/wiki/v1";
@@ -64838,11 +64849,7 @@ var ParallClient = class _ParallClient {
64838
64849
  async postBrowseResponse(requestId, response) {
64839
64850
  return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSE_RESPONSE(requestId), response);
64840
64851
  }
64841
- /**
64842
- * `POST /machines/me/browser-profiles/viewer-response/{requestId}` — daemon
64843
- * reply to a `machine.browser_profile.viewer` control command. Wakes the
64844
- * api-server request/reply bridge (mirrors {@link postBrowseResponse}).
64845
- */
64852
+ /** Reply to `machine.browser_profile.viewer` and wake its request/reply bridge. */
64846
64853
  async postBrowserProfileViewerResponse(requestId, response) {
64847
64854
  return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_VIEWER_RESPONSE(requestId), response);
64848
64855
  }
@@ -64852,7 +64859,7 @@ var ParallClient = class _ParallClient {
64852
64859
  * owner or org admin. api-server brokers the command to the host daemon.
64853
64860
  */
64854
64861
  async browserViewerCommand(orgId, profileId, req, opts) {
64855
- return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, opts);
64862
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, browserViewerRequestOptions(req.command, opts));
64856
64863
  }
64857
64864
  /**
64858
64865
  * Drive the Cloud Edge live viewer (V1b, design §6): WebRTC signaling + input +
@@ -66880,8 +66887,113 @@ function comparableUrl(url) {
66880
66887
 
66881
66888
  // ts/daemon/dist/clip-runtime/browser-viewer-streamer.js
66882
66889
  import { spawn } from "node:child_process";
66883
- var BB_VIEWER_HEALTH_TIMEOUT_MS = 1e4;
66890
+
66891
+ // ts/daemon/dist/clip-runtime/viewer-command-error.js
66892
+ var ViewerCommandError = class extends Error {
66893
+ code;
66894
+ constructor(message, code) {
66895
+ super(message);
66896
+ this.code = code;
66897
+ this.name = "ViewerCommandError";
66898
+ }
66899
+ };
66900
+ function viewerCommandFailure(error2) {
66901
+ const message = error2 instanceof Error ? error2.message : String(error2);
66902
+ if (error2 instanceof ViewerCommandError && error2.code) {
66903
+ return { code: error2.code, message };
66904
+ }
66905
+ return { message };
66906
+ }
66907
+
66908
+ // ts/daemon/dist/clip-runtime/viewer-command-deadline.js
66909
+ var HOSTED_VIEWER_READINESS_POD_BUDGET_MS = 3e4;
66910
+ var HOSTED_VIEWER_REPLY_RESERVE_MS = 5e3;
66911
+ function isViewerReadinessCommand(command) {
66912
+ return command === "stream.answer" || command === "stream.switch";
66913
+ }
66914
+ function parseViewerDispatchDeadlineUnixMs(value) {
66915
+ let parsed;
66916
+ if (typeof value === "number") {
66917
+ parsed = value;
66918
+ } else if (typeof value === "string" && /^[1-9]\d*$/.test(value)) {
66919
+ parsed = Number(value);
66920
+ } else {
66921
+ return void 0;
66922
+ }
66923
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : void 0;
66924
+ }
66925
+ function viewerReadinessDeadlineError(phase) {
66926
+ return new ViewerCommandError(`viewer readiness deadline elapsed ${phase}`, "VIEWER_STREAM_CANCELLED");
66927
+ }
66928
+
66929
+ // ts/daemon/dist/clip-runtime/bb-viewer-command-client.js
66884
66930
  var BB_VIEWER_COMMAND_TIMEOUT_MS = 15e3;
66931
+ var BB_VIEWER_READINESS_COMMAND_TIMEOUT_MS = 3e4;
66932
+ function bbViewerCommandTimeoutMs(method) {
66933
+ return method === "answer" || method === "switch" ? BB_VIEWER_READINESS_COMMAND_TIMEOUT_MS : BB_VIEWER_COMMAND_TIMEOUT_MS;
66934
+ }
66935
+ function bbViewerCommandEffectiveTimeoutMs(method, deadlineUnixMs, now = Date.now()) {
66936
+ const configured = bbViewerCommandTimeoutMs(method);
66937
+ if (deadlineUnixMs === void 0)
66938
+ return configured;
66939
+ const remaining = deadlineUnixMs - now;
66940
+ if (remaining <= 0) {
66941
+ throw viewerReadinessDeadlineError(`before bb-viewer ${method}`);
66942
+ }
66943
+ return Math.max(1, Math.min(configured, remaining));
66944
+ }
66945
+ async function sendBBViewerCommand(port, method, params, deadlineUnixMs) {
66946
+ const controller = new AbortController();
66947
+ const timeoutMs = bbViewerCommandEffectiveTimeoutMs(method, deadlineUnixMs);
66948
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
66949
+ try {
66950
+ const resp = await fetch(`http://127.0.0.1:${port}/command`, {
66951
+ method: "POST",
66952
+ headers: { "Content-Type": "application/json" },
66953
+ body: JSON.stringify({ method, params }),
66954
+ signal: controller.signal
66955
+ });
66956
+ const text = await resp.text();
66957
+ return parseBBViewerCommandResponse(resp.status, text, method);
66958
+ } catch (err) {
66959
+ if (controller.signal.aborted && (method === "answer" || method === "switch")) {
66960
+ throw viewerReadinessDeadlineError(`while waiting for bb-viewer ${method}`);
66961
+ }
66962
+ throw err;
66963
+ } finally {
66964
+ clearTimeout(timer);
66965
+ }
66966
+ }
66967
+ function parseBBViewerCommandResponse(status, text, method) {
66968
+ let parsed;
66969
+ try {
66970
+ parsed = text ? JSON.parse(text) : {};
66971
+ } catch {
66972
+ throw new ViewerCommandError(`bb-viewer ${method} returned invalid JSON`);
66973
+ }
66974
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
66975
+ throw new ViewerCommandError(`bb-viewer ${method} returned an invalid response`);
66976
+ }
66977
+ const envelope = parsed;
66978
+ if (envelope.error) {
66979
+ const code = typeof envelope.error.code === "string" && envelope.error.code.trim() ? envelope.error.code.trim() : void 0;
66980
+ const message = typeof envelope.error.message === "string" && envelope.error.message.trim() ? envelope.error.message : `bb-viewer ${method} failed`;
66981
+ throw new ViewerCommandError(message, code);
66982
+ }
66983
+ if (status < 200 || status >= 300) {
66984
+ throw new ViewerCommandError(`bb-viewer ${method} returned ${status}`);
66985
+ }
66986
+ if (envelope.result === void 0 || envelope.result === null) {
66987
+ return {};
66988
+ }
66989
+ if (typeof envelope.result !== "object" || Array.isArray(envelope.result)) {
66990
+ throw new ViewerCommandError(`bb-viewer ${method} returned an invalid result`);
66991
+ }
66992
+ return envelope.result;
66993
+ }
66994
+
66995
+ // ts/daemon/dist/clip-runtime/browser-viewer-streamer.js
66996
+ var BB_VIEWER_HEALTH_TIMEOUT_MS = 1e4;
66885
66997
  var BB_VIEWER_UNANSWERED_REAP_MS = 9e4;
66886
66998
  var BB_VIEWER_TERM_GRACE_MS = 5e3;
66887
66999
  function isLoopbackBindHost(host) {
@@ -66918,7 +67030,7 @@ var BrowserViewerStreamer = class {
66918
67030
  * partial result. `data.input` / `data.turn` / `data.session_id` come from
66919
67031
  * MachineBrowserProfileViewerData.
66920
67032
  */
66921
- async handleViewerCommand(profileId, sessionId, command, input, turn) {
67033
+ async handleViewerCommand(profileId, sessionId, command, input, turn, execution) {
66922
67034
  if (!profileId)
66923
67035
  throw new Error("browser profile id is required");
66924
67036
  if (command !== "stream.start" && sessionId && this.kickedSessions.get(profileId) === sessionId) {
@@ -66928,11 +67040,11 @@ var BrowserViewerStreamer = class {
66928
67040
  case "stream.start":
66929
67041
  return this.viewerStreamStart(profileId, sessionId, turn);
66930
67042
  case "stream.answer":
66931
- return this.viewerStreamAnswer(profileId, sessionId, input);
67043
+ return this.viewerStreamAnswer(profileId, sessionId, input, execution?.deadlineUnixMs);
66932
67044
  case "stream.close":
66933
67045
  return this.viewerStreamClose(profileId, sessionId, input);
66934
67046
  case "stream.switch":
66935
- return this.viewerStreamSwitch(profileId, sessionId, input);
67047
+ return this.viewerStreamSwitch(profileId, sessionId, input, execution?.deadlineUnixMs);
66936
67048
  case "kick":
66937
67049
  return this.viewerKick(profileId, sessionId, input);
66938
67050
  case "close":
@@ -66984,7 +67096,7 @@ var BrowserViewerStreamer = class {
66984
67096
  await this.bringTargetToFront(cdpUrl);
66985
67097
  const streamer = await this.spawnStreamer(profileId, sessionId, turn);
66986
67098
  try {
66987
- const result = await this.streamerCommand(streamer, "connect", { cdpUrl });
67099
+ const result = await sendBBViewerCommand(streamer.port, "connect", { cdpUrl });
66988
67100
  streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
66989
67101
  const reapTimer = setTimeout(() => {
66990
67102
  const current = this.streamers.get(profileId);
@@ -67005,14 +67117,17 @@ var BrowserViewerStreamer = class {
67005
67117
  * Rejects if the streamer's sessionId no longer matches (a stale viewer
67006
67118
  * session from a superseded stream.start).
67007
67119
  */
67008
- async viewerStreamAnswer(profileId, sessionId, input) {
67120
+ async viewerStreamAnswer(profileId, sessionId, input, deadlineUnixMs) {
67009
67121
  const streamer = this.streamers.get(profileId);
67010
67122
  if (!streamer)
67011
67123
  throw new Error("no active viewer streamer for profile");
67012
67124
  if (streamer.sessionId !== sessionId)
67013
67125
  throw new Error("stale viewer session");
67126
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "before bb-viewer answer");
67014
67127
  streamer.answered = true;
67015
- return this.streamerCommand(streamer, "answer", input ?? {});
67128
+ const result = await sendBBViewerCommand(streamer.port, "answer", input ?? {}, deadlineUnixMs);
67129
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "after bb-viewer answer");
67130
+ return result;
67016
67131
  }
67017
67132
  /**
67018
67133
  * stream.close — best-effort stop the streamer, then kill + remove it. A
@@ -67033,7 +67148,7 @@ var BrowserViewerStreamer = class {
67033
67148
  return { ok: true, stale: true };
67034
67149
  }
67035
67150
  try {
67036
- await this.streamerCommand(streamer, "stop", {});
67151
+ await sendBBViewerCommand(streamer.port, "stop", {});
67037
67152
  } catch (err) {
67038
67153
  this.host.log.warn(`[bb-viewer] stop command failed for ${profileId} (killing anyway): ${formatErrorForLog(err)}`);
67039
67154
  }
@@ -67050,7 +67165,7 @@ var BrowserViewerStreamer = class {
67050
67165
  * the stream.start response), so a session-less switch is by definition not
67051
67166
  * the current viewer.
67052
67167
  */
67053
- async viewerStreamSwitch(profileId, sessionId, input) {
67168
+ async viewerStreamSwitch(profileId, sessionId, input, deadlineUnixMs) {
67054
67169
  const streamer = this.streamers.get(profileId);
67055
67170
  if (!streamer)
67056
67171
  throw new Error("no active viewer streamer for profile");
@@ -67060,9 +67175,13 @@ var BrowserViewerStreamer = class {
67060
67175
  if (tab === void 0 || tab === null || tab === "") {
67061
67176
  throw new Error("stream.switch requires input.tab");
67062
67177
  }
67178
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "before resolving the switch target");
67063
67179
  const cdpUrl = await this.host.withDaemonRecovery(() => this.resolveAccountPageCdpUrl(profileId, tab), `viewer stream.switch ${profileId}`);
67064
- await this.bringTargetToFront(cdpUrl);
67065
- const result = await this.streamerCommand(streamer, "switch", { cdpUrl });
67180
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "after resolving the switch target");
67181
+ await this.bringTargetToFront(cdpUrl, deadlineUnixMs);
67182
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "before bb-viewer switch");
67183
+ const result = await sendBBViewerCommand(streamer.port, "switch", { cdpUrl }, deadlineUnixMs);
67184
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "after bb-viewer switch");
67066
67185
  streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
67067
67186
  return { ...result, streamed_tab_id: streamer.streamedTabId };
67068
67187
  }
@@ -67086,7 +67205,7 @@ var BrowserViewerStreamer = class {
67086
67205
  }
67087
67206
  const cdpUrl = await this.host.withDaemonRecovery(() => this.resolveAccountPageCdpUrl(profileId), `viewer close re-switch ${profileId}`);
67088
67207
  await this.bringTargetToFront(cdpUrl);
67089
- const sw = await this.streamerCommand(streamer, "switch", { cdpUrl });
67208
+ const sw = await sendBBViewerCommand(streamer.port, "switch", { cdpUrl });
67090
67209
  streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
67091
67210
  return { ...result, ...sw, streamed_tab_id: streamer.streamedTabId };
67092
67211
  }
@@ -67098,15 +67217,17 @@ var BrowserViewerStreamer = class {
67098
67217
  * must not block the stream. host:port + targetId are parsed from the cdpUrl
67099
67218
  * (`ws://host:port/devtools/page/<targetId>`) to avoid an extra /status call.
67100
67219
  */
67101
- async bringTargetToFront(cdpUrl) {
67220
+ async bringTargetToFront(cdpUrl, deadlineUnixMs) {
67102
67221
  const m3 = /^ws:\/\/([^/]+)\/devtools\/page\/(.+)$/.exec(cdpUrl);
67103
67222
  if (!m3)
67104
67223
  return;
67105
67224
  const [, hostPort, targetId] = m3;
67225
+ this.assertViewerExecutionDeadline(deadlineUnixMs, "before foregrounding the switch target");
67226
+ const timeoutMs = deadlineUnixMs === void 0 ? 5e3 : Math.max(1, Math.min(5e3, deadlineUnixMs - Date.now()));
67106
67227
  try {
67107
67228
  const resp = await fetch(`http://${hostPort}/json/activate/${targetId}`, {
67108
67229
  method: "GET",
67109
- signal: AbortSignal.timeout(5e3)
67230
+ signal: AbortSignal.timeout(timeoutMs)
67110
67231
  });
67111
67232
  if (!resp.ok) {
67112
67233
  this.host.log.warn(`[bb-viewer] activate target ${targetId} returned ${resp.status} (continuing)`);
@@ -67115,6 +67236,11 @@ var BrowserViewerStreamer = class {
67115
67236
  this.host.log.warn(`[bb-viewer] activate target ${targetId} failed (continuing): ${formatErrorForLog(err)}`);
67116
67237
  }
67117
67238
  }
67239
+ assertViewerExecutionDeadline(deadlineUnixMs, phase) {
67240
+ if (deadlineUnixMs !== void 0 && Date.now() >= deadlineUnixMs) {
67241
+ throw viewerReadinessDeadlineError(phase);
67242
+ }
67243
+ }
67118
67244
  /**
67119
67245
  * Forward a navigation command (tab_list/tab_new/open/reload/back/forward/
67120
67246
  * close) to bb-browser scoped to the profile's account. This lets the human
@@ -67315,34 +67441,6 @@ var BrowserViewerStreamer = class {
67315
67441
  killTimer.unref?.();
67316
67442
  child.once("exit", () => clearTimeout(killTimer));
67317
67443
  }
67318
- /**
67319
- * POST a command to the profile's bb-viewer `/command` endpoint. Parses the
67320
- * `{result}` / `{error:{message}}` envelope (bb-viewer api.go) and returns
67321
- * the inner result, throwing the error message on failure.
67322
- */
67323
- async streamerCommand(streamer, method, params) {
67324
- const controller = new AbortController();
67325
- const timer = setTimeout(() => controller.abort(), BB_VIEWER_COMMAND_TIMEOUT_MS);
67326
- try {
67327
- const resp = await fetch(`http://127.0.0.1:${streamer.port}/command`, {
67328
- method: "POST",
67329
- headers: { "Content-Type": "application/json" },
67330
- body: JSON.stringify({ method, params }),
67331
- signal: controller.signal
67332
- });
67333
- const text = await resp.text();
67334
- const parsed = text ? JSON.parse(text) : {};
67335
- if (parsed.error) {
67336
- throw new Error(parsed.error.message || `bb-viewer ${method} failed`);
67337
- }
67338
- if (!resp.ok) {
67339
- throw new Error(`bb-viewer ${method} returned ${resp.status}: ${text}`);
67340
- }
67341
- return parsed.result ?? {};
67342
- } finally {
67343
- clearTimeout(timer);
67344
- }
67345
- }
67346
67444
  /**
67347
67445
  * Kill + remove the profile's bb-viewer streamer, if any. Idempotent. Also
67348
67446
  * clears any kick marker for the profile: a (re)kill establishes a clean
@@ -67602,8 +67700,8 @@ var BrowserProfileManager = class {
67602
67700
  * (browser-viewer-streamer.ts), which owns the per-profile bb-viewer
67603
67701
  * subprocesses and viewer tab navigation.
67604
67702
  */
67605
- async handleViewerCommand(profileId, sessionId, command, input, turn) {
67606
- return this.viewer.handleViewerCommand(profileId, sessionId, command, input, turn);
67703
+ async handleViewerCommand(profileId, sessionId, command, input, turn, execution) {
67704
+ return this.viewer.handleViewerCommand(profileId, sessionId, command, input, turn, execution);
67607
67705
  }
67608
67706
  /** Read cdpHost/cdpPort from the bb-browser daemon `GET /status`. */
67609
67707
  async cdpEndpoint() {
@@ -68453,6 +68551,46 @@ function errMsg(err) {
68453
68551
  // ts/daemon/dist/clip-runtime/clip-provider.js
68454
68552
  import * as http2 from "node:http2";
68455
68553
 
68554
+ // ts/daemon/dist/clip-runtime/browser-dependency.js
68555
+ var BROWSER_CAPABILITY_NAME = "browser";
68556
+ var BROWSER_CAPABILITY_PACKAGE = "@pinixai/bb-browser-pro";
68557
+ var BROWSER_DEPENDENCY_NAMES = /* @__PURE__ */ new Set([
68558
+ BROWSER_CAPABILITY_NAME,
68559
+ "@pinix/browser",
68560
+ "@pinixai/bb-browser-pro",
68561
+ "bb-browser"
68562
+ ]);
68563
+ function isBrowserDependencyName(name) {
68564
+ return !!name && BROWSER_DEPENDENCY_NAMES.has(name);
68565
+ }
68566
+ function browserCapabilityCommands() {
68567
+ return [
68568
+ { name: "eval", description: "Run JavaScript in a page context" },
68569
+ { name: "open", description: "Open a URL in a new tab" },
68570
+ { name: "snapshot", description: "Capture the accessibility/DOM snapshot of a page" },
68571
+ { name: "click", description: "Click an element" },
68572
+ { name: "type", description: "Type text into an element" }
68573
+ ];
68574
+ }
68575
+ function manifestDeclaresBrowserDependency(manifest) {
68576
+ return dependencyMaps(manifest).some((deps) => Object.entries(deps).some(([name, dep]) => isBrowserDependencyName(name) || isBrowserDependencyName(dep?.package)));
68577
+ }
68578
+ function manifestMapsDependencyToBrowser(manifest, dependencyName) {
68579
+ const maps = dependencyMaps(manifest);
68580
+ if (maps.length === 0)
68581
+ return false;
68582
+ for (const deps of maps) {
68583
+ const declared = deps[dependencyName];
68584
+ if (declared) {
68585
+ return isBrowserDependencyName(dependencyName) || isBrowserDependencyName(declared.package);
68586
+ }
68587
+ }
68588
+ return isBrowserDependencyName(dependencyName) && manifestDeclaresBrowserDependency(manifest);
68589
+ }
68590
+ function dependencyMaps(manifest) {
68591
+ return [manifest?.dependencies, manifest?.dependencySlots].filter((deps) => !!deps);
68592
+ }
68593
+
68456
68594
  // ts/daemon/dist/clip-runtime/process.js
68457
68595
  import { spawn as spawn4 } from "node:child_process";
68458
68596
  import { createInterface as createInterface2 } from "node:readline";
@@ -68709,46 +68847,6 @@ function finalizeManifest(manifest) {
68709
68847
  return m3;
68710
68848
  }
68711
68849
 
68712
- // ts/daemon/dist/clip-runtime/browser-dependency.js
68713
- var BROWSER_CAPABILITY_NAME = "browser";
68714
- var BROWSER_CAPABILITY_PACKAGE = "@pinixai/bb-browser-pro";
68715
- var BROWSER_DEPENDENCY_NAMES = /* @__PURE__ */ new Set([
68716
- BROWSER_CAPABILITY_NAME,
68717
- "@pinix/browser",
68718
- "@pinixai/bb-browser-pro",
68719
- "bb-browser"
68720
- ]);
68721
- function isBrowserDependencyName(name) {
68722
- return !!name && BROWSER_DEPENDENCY_NAMES.has(name);
68723
- }
68724
- function browserCapabilityCommands() {
68725
- return [
68726
- { name: "eval", description: "Run JavaScript in a page context" },
68727
- { name: "open", description: "Open a URL in a new tab" },
68728
- { name: "snapshot", description: "Capture the accessibility/DOM snapshot of a page" },
68729
- { name: "click", description: "Click an element" },
68730
- { name: "type", description: "Type text into an element" }
68731
- ];
68732
- }
68733
- function manifestDeclaresBrowserDependency(manifest) {
68734
- return dependencyMaps(manifest).some((deps) => Object.entries(deps).some(([name, dep]) => isBrowserDependencyName(name) || isBrowserDependencyName(dep?.package)));
68735
- }
68736
- function manifestMapsDependencyToBrowser(manifest, dependencyName) {
68737
- const maps = dependencyMaps(manifest);
68738
- if (maps.length === 0)
68739
- return false;
68740
- for (const deps of maps) {
68741
- const declared = deps[dependencyName];
68742
- if (declared) {
68743
- return isBrowserDependencyName(dependencyName) || isBrowserDependencyName(declared.package);
68744
- }
68745
- }
68746
- return isBrowserDependencyName(dependencyName) && manifestDeclaresBrowserDependency(manifest);
68747
- }
68748
- function dependencyMaps(manifest) {
68749
- return [manifest?.dependencies, manifest?.dependencySlots].filter((deps) => !!deps);
68750
- }
68751
-
68752
68850
  // ts/daemon/dist/clip-runtime/process.js
68753
68851
  var CLIP_REGISTER_TIMEOUT_MS = 1e4;
68754
68852
  var CLIP_STOP_TIMEOUT_MS = 5e3;
@@ -69503,8 +69601,8 @@ var ClipProvider = class _ClipProvider {
69503
69601
  /**
69504
69602
  * Handle a hosted-browser live-viewer command relayed by clip-service over the
69505
69603
  * stream and reply on the same stream (design §3.4). Always answers the
69506
- * request/reply bridge exactly once — `{result}` on success, `{error:{message}}`
69507
- * on failure — and never throws into the message loop, mirroring the BYOC
69604
+ * request/reply bridge exactly once — `{result}` on success,
69605
+ * `{error:{code?,message}}` on failure — and never throws into the message loop, mirroring the BYOC
69508
69606
  * daemon's handleBrowserProfileViewer (which replies over HTTP instead).
69509
69607
  */
69510
69608
  async handleViewerCommand(cmd) {
@@ -69517,6 +69615,10 @@ var ClipProvider = class _ClipProvider {
69517
69615
  return;
69518
69616
  }
69519
69617
  try {
69618
+ const dispatchDeadlineUnixMs = parseViewerDispatchDeadlineUnixMs(cmd.dispatchDeadlineUnixMs);
69619
+ if (isViewerReadinessCommand(cmd.command) && dispatchDeadlineUnixMs === void 0) {
69620
+ throw viewerReadinessDeadlineError("because the ProviderStream command has no authenticated deadline");
69621
+ }
69520
69622
  let input;
69521
69623
  if (cmd.input) {
69522
69624
  const decoded = Buffer.from(cmd.input, "base64").toString("utf-8");
@@ -69531,13 +69633,14 @@ var ClipProvider = class _ClipProvider {
69531
69633
  sessionId: cmd.sessionId,
69532
69634
  command: cmd.command,
69533
69635
  input,
69534
- turn: cmd.turn
69636
+ turn: cmd.turn,
69637
+ dispatchDeadlineUnixMs
69535
69638
  });
69536
69639
  await this.sendViewerReply(requestId, { result });
69537
69640
  } catch (err) {
69538
- const message = err instanceof Error ? err.message : String(err);
69539
- this.opts.log.warn(`[clip-provider] viewer command failed (profile=${cmd.profileId}, command=${cmd.command}): ${message}`);
69540
- await this.sendViewerReply(requestId, { error: { message } }).catch(() => {
69641
+ const failure = viewerCommandFailure(err);
69642
+ this.opts.log.warn(`[clip-provider] viewer command failed (profile=${cmd.profileId}, command=${cmd.command}): ${failure.message}`);
69643
+ await this.sendViewerReply(requestId, { error: failure }).catch(() => {
69541
69644
  });
69542
69645
  }
69543
69646
  }
@@ -69623,6 +69726,70 @@ var ClipProvider = class _ClipProvider {
69623
69726
  }
69624
69727
  };
69625
69728
 
69729
+ // ts/daemon/dist/clip-runtime/hosted-viewer-command-queue.js
69730
+ var HostedViewerCommandQueue = class {
69731
+ run;
69732
+ tail = Promise.resolve();
69733
+ now;
69734
+ readinessBudgetMs;
69735
+ replyReserveMs;
69736
+ schedule;
69737
+ constructor(run, opts = {}) {
69738
+ this.run = run;
69739
+ this.now = opts.now ?? Date.now;
69740
+ this.readinessBudgetMs = opts.readinessBudgetMs ?? HOSTED_VIEWER_READINESS_POD_BUDGET_MS;
69741
+ this.replyReserveMs = opts.replyReserveMs ?? HOSTED_VIEWER_REPLY_RESERVE_MS;
69742
+ this.schedule = opts.schedule ?? ((callback, delayMs) => {
69743
+ const handle = setTimeout(callback, delayMs);
69744
+ return {
69745
+ cancel: () => clearTimeout(handle),
69746
+ unref: () => handle.unref?.()
69747
+ };
69748
+ });
69749
+ }
69750
+ enqueue(command) {
69751
+ const receivedAt = this.now();
69752
+ const executionDeadline = this.executionDeadline(command, receivedAt);
69753
+ const run = this.tail.catch(() => {
69754
+ }).then(() => {
69755
+ if (executionDeadline !== void 0 && this.now() >= executionDeadline) {
69756
+ throw viewerReadinessDeadlineError("before hosted pod execution");
69757
+ }
69758
+ return this.run(command, executionDeadline);
69759
+ });
69760
+ this.tail = run.catch(() => {
69761
+ });
69762
+ if (executionDeadline === void 0) {
69763
+ return run;
69764
+ }
69765
+ let timer;
69766
+ const timeout = new Promise((_, reject) => {
69767
+ const delay = Math.max(0, executionDeadline - this.now());
69768
+ timer = this.schedule(() => {
69769
+ reject(viewerReadinessDeadlineError("inside the hosted pod queue"));
69770
+ }, delay);
69771
+ timer.unref?.();
69772
+ });
69773
+ return Promise.race([run, timeout]).finally(() => {
69774
+ timer?.cancel();
69775
+ });
69776
+ }
69777
+ executionDeadline(command, receivedAt) {
69778
+ if (!isViewerReadinessCommand(command.command)) {
69779
+ return void 0;
69780
+ }
69781
+ const dispatchDeadline = command.dispatchDeadlineUnixMs;
69782
+ if (!Number.isSafeInteger(dispatchDeadline) || dispatchDeadline === void 0) {
69783
+ throw viewerReadinessDeadlineError("because the authenticated deadline is missing");
69784
+ }
69785
+ const deadline = Math.min(receivedAt + this.readinessBudgetMs, dispatchDeadline - this.replyReserveMs);
69786
+ if (deadline <= receivedAt) {
69787
+ throw viewerReadinessDeadlineError("before hosted pod receipt");
69788
+ }
69789
+ return deadline;
69790
+ }
69791
+ };
69792
+
69626
69793
  // ts/daemon/dist/clip-runtime/process-manager.js
69627
69794
  import * as fs3 from "node:fs";
69628
69795
  import * as path5 from "node:path";
@@ -70599,14 +70766,10 @@ async function preparePodRuntime(config, env, log) {
70599
70766
  dataDir: path6.join(config.stateDir, "clip-data"),
70600
70767
  browserProfileManager: browser
70601
70768
  });
70602
- let viewerChain = Promise.resolve();
70603
- const onViewerCommand = (cmd) => {
70604
- const run = viewerChain.catch(() => {
70605
- }).then(() => browser.handleViewerCommand(cmd.profileId, cmd.sessionId, cmd.command, cmd.input, cmd.turn));
70606
- viewerChain = run.catch(() => {
70607
- });
70608
- return run;
70609
- };
70769
+ const viewerCommands = new HostedViewerCommandQueue((cmd, executionDeadlineUnixMs) => browser.handleViewerCommand(cmd.profileId, cmd.sessionId, cmd.command, cmd.input, cmd.turn, {
70770
+ deadlineUnixMs: executionDeadlineUnixMs
70771
+ }));
70772
+ const onViewerCommand = viewerCommands.enqueue.bind(viewerCommands);
70610
70773
  const provider = new ClipProvider({
70611
70774
  serviceUrl: config.clipRpcUrl,
70612
70775
  authKey: config.assignmentToken,
@@ -51291,18 +51291,15 @@ function laneContextFilePath(contextDir, targetUri, threadRootId) {
51291
51291
  return path.join(contextDir, `${laneKeyForTarget(targetUri, threadRootId)}.json`);
51292
51292
  }
51293
51293
 
51294
- // ts/sdk/dist/types.js
51295
- var MENTION_ALL_USER_ID = "all";
51296
- var MENTION_ALL_HUMANS_USER_ID = "allhuman";
51297
- var MENTION_ALL_AGENTS_USER_ID = "allagent";
51298
- function mentionTargetsUser(mentionUserId, userId, userType) {
51299
- if (mentionUserId === userId || mentionUserId === MENTION_ALL_USER_ID)
51300
- return true;
51301
- if (mentionUserId === MENTION_ALL_HUMANS_USER_ID)
51302
- return userType === "human";
51303
- if (mentionUserId === MENTION_ALL_AGENTS_USER_ID)
51304
- return userType === "agent";
51305
- return false;
51294
+ // ts/sdk/dist/browser-viewer.js
51295
+ var BROWSER_VIEWER_READINESS_TIMEOUT_MS = 6e4;
51296
+ function browserViewerRequestOptions(command, opts) {
51297
+ if (command !== "stream.answer" && command !== "stream.switch")
51298
+ return opts;
51299
+ return {
51300
+ ...opts,
51301
+ timeoutMs: Math.max(opts?.timeoutMs ?? 0, BROWSER_VIEWER_READINESS_TIMEOUT_MS)
51302
+ };
51306
51303
  }
51307
51304
 
51308
51305
  // ts/sdk/dist/constants.js
@@ -52734,11 +52731,7 @@ var ParallClient = class _ParallClient {
52734
52731
  async postBrowseResponse(requestId, response) {
52735
52732
  return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSE_RESPONSE(requestId), response);
52736
52733
  }
52737
- /**
52738
- * `POST /machines/me/browser-profiles/viewer-response/{requestId}` — daemon
52739
- * reply to a `machine.browser_profile.viewer` control command. Wakes the
52740
- * api-server request/reply bridge (mirrors {@link postBrowseResponse}).
52741
- */
52734
+ /** Reply to `machine.browser_profile.viewer` and wake its request/reply bridge. */
52742
52735
  async postBrowserProfileViewerResponse(requestId, response) {
52743
52736
  return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_VIEWER_RESPONSE(requestId), response);
52744
52737
  }
@@ -52748,7 +52741,7 @@ var ParallClient = class _ParallClient {
52748
52741
  * owner or org admin. api-server brokers the command to the host daemon.
52749
52742
  */
52750
52743
  async browserViewerCommand(orgId, profileId, req, opts) {
52751
- return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, opts);
52744
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, browserViewerRequestOptions(req.command, opts));
52752
52745
  }
52753
52746
  /**
52754
52747
  * Drive the Cloud Edge live viewer (V1b, design §6): WebRTC signaling + input +
@@ -53932,6 +53925,20 @@ function buildApiError(res, rawErrorBody) {
53932
53925
  return apiError;
53933
53926
  }
53934
53927
 
53928
+ // ts/sdk/dist/types.js
53929
+ var MENTION_ALL_USER_ID = "all";
53930
+ var MENTION_ALL_HUMANS_USER_ID = "allhuman";
53931
+ var MENTION_ALL_AGENTS_USER_ID = "allagent";
53932
+ function mentionTargetsUser(mentionUserId, userId, userType) {
53933
+ if (mentionUserId === userId || mentionUserId === MENTION_ALL_USER_ID)
53934
+ return true;
53935
+ if (mentionUserId === MENTION_ALL_HUMANS_USER_ID)
53936
+ return userType === "human";
53937
+ if (mentionUserId === MENTION_ALL_AGENTS_USER_ID)
53938
+ return userType === "agent";
53939
+ return false;
53940
+ }
53941
+
53935
53942
  // ts/sdk/dist/ws.js
53936
53943
  function isRetryableNetworkError(err) {
53937
53944
  return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;