@elizaos/plugin-browser 2.0.0-alpha.9 → 2.0.3-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 (256) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -83
  3. package/auto-enable.ts +24 -0
  4. package/dist/actions/browser-autofill-login.d.ts +43 -0
  5. package/dist/actions/browser-autofill-login.d.ts.map +1 -0
  6. package/dist/actions/browser-autofill-login.js +278 -0
  7. package/dist/actions/browser-autofill-login.js.map +1 -0
  8. package/dist/actions/browser.d.ts +11 -0
  9. package/dist/actions/browser.d.ts.map +1 -0
  10. package/dist/actions/browser.js +412 -0
  11. package/dist/actions/browser.js.map +1 -0
  12. package/dist/actions/manage-browser-bridge.d.ts +34 -0
  13. package/dist/actions/manage-browser-bridge.d.ts.map +1 -0
  14. package/dist/actions/manage-browser-bridge.js +572 -0
  15. package/dist/actions/manage-browser-bridge.js.map +1 -0
  16. package/dist/bridge-policy.d.ts +10 -0
  17. package/dist/bridge-policy.d.ts.map +1 -0
  18. package/dist/bridge-policy.js +37 -0
  19. package/dist/bridge-policy.js.map +1 -0
  20. package/dist/bridge-readiness.d.ts +16 -0
  21. package/dist/bridge-readiness.d.ts.map +1 -0
  22. package/dist/bridge-readiness.js +82 -0
  23. package/dist/bridge-readiness.js.map +1 -0
  24. package/dist/bridge-records.d.ts +9 -0
  25. package/dist/bridge-records.d.ts.map +1 -0
  26. package/dist/bridge-records.js +37 -0
  27. package/dist/bridge-records.js.map +1 -0
  28. package/dist/browser-capture-hooks.d.ts +9 -0
  29. package/dist/browser-capture-hooks.d.ts.map +1 -0
  30. package/dist/browser-capture-hooks.js +15 -0
  31. package/dist/browser-capture-hooks.js.map +1 -0
  32. package/dist/browser-service.d.ts +103 -0
  33. package/dist/browser-service.d.ts.map +1 -0
  34. package/dist/browser-service.js +186 -0
  35. package/dist/browser-service.js.map +1 -0
  36. package/dist/browser-workspace-hooks.d.ts +14 -0
  37. package/dist/browser-workspace-hooks.d.ts.map +1 -0
  38. package/dist/browser-workspace-hooks.js +15 -0
  39. package/dist/browser-workspace-hooks.js.map +1 -0
  40. package/dist/companion-auth.d.ts +34 -0
  41. package/dist/companion-auth.d.ts.map +1 -0
  42. package/dist/companion-auth.js +98 -0
  43. package/dist/companion-auth.js.map +1 -0
  44. package/dist/contracts.d.ts +284 -0
  45. package/dist/contracts.d.ts.map +1 -0
  46. package/dist/contracts.js +56 -0
  47. package/dist/contracts.js.map +1 -0
  48. package/dist/index.d.ts +30 -16
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +76 -90
  51. package/dist/index.js.map +1 -1
  52. package/dist/lifeops-session-contracts.d.ts +46 -0
  53. package/dist/lifeops-session-contracts.d.ts.map +1 -0
  54. package/dist/lifeops-session-contracts.js +1 -0
  55. package/dist/lifeops-session-contracts.js.map +1 -0
  56. package/dist/message-adapter.d.ts +9 -0
  57. package/dist/message-adapter.d.ts.map +1 -0
  58. package/dist/message-adapter.js +104 -0
  59. package/dist/message-adapter.js.map +1 -0
  60. package/dist/packaging.d.ts +27 -0
  61. package/dist/packaging.d.ts.map +1 -0
  62. package/dist/packaging.js +571 -0
  63. package/dist/packaging.js.map +1 -0
  64. package/dist/password-manager-bridge.d.ts +50 -0
  65. package/dist/password-manager-bridge.d.ts.map +1 -0
  66. package/dist/password-manager-bridge.js +437 -0
  67. package/dist/password-manager-bridge.js.map +1 -0
  68. package/dist/plugin.d.ts +10 -0
  69. package/dist/plugin.d.ts.map +1 -0
  70. package/dist/plugin.js +168 -0
  71. package/dist/plugin.js.map +1 -0
  72. package/dist/providers/workspace.d.ts +13 -0
  73. package/dist/providers/workspace.d.ts.map +1 -0
  74. package/dist/providers/workspace.js +64 -0
  75. package/dist/providers/workspace.js.map +1 -0
  76. package/dist/routes/bridge.d.ts +37 -0
  77. package/dist/routes/bridge.d.ts.map +1 -0
  78. package/dist/routes/bridge.js +844 -0
  79. package/dist/routes/bridge.js.map +1 -0
  80. package/dist/routes/workspace-account-gate.d.ts +29 -0
  81. package/dist/routes/workspace-account-gate.d.ts.map +1 -0
  82. package/dist/routes/workspace-account-gate.js +147 -0
  83. package/dist/routes/workspace-account-gate.js.map +1 -0
  84. package/dist/routes/workspace-setup.d.ts +10 -0
  85. package/dist/routes/workspace-setup.d.ts.map +1 -0
  86. package/dist/routes/workspace-setup.js +65 -0
  87. package/dist/routes/workspace-setup.js.map +1 -0
  88. package/dist/routes/workspace.d.ts +20 -0
  89. package/dist/routes/workspace.d.ts.map +1 -0
  90. package/dist/routes/workspace.js +276 -0
  91. package/dist/routes/workspace.js.map +1 -0
  92. package/dist/schema.d.ts +2326 -0
  93. package/dist/schema.d.ts.map +1 -0
  94. package/dist/schema.js +133 -0
  95. package/dist/schema.js.map +1 -0
  96. package/dist/service.d.ts +30 -0
  97. package/dist/service.d.ts.map +1 -0
  98. package/dist/service.js +5 -0
  99. package/dist/service.js.map +1 -0
  100. package/dist/targets/bridge-target.d.ts +31 -0
  101. package/dist/targets/bridge-target.d.ts.map +1 -0
  102. package/dist/targets/bridge-target.js +98 -0
  103. package/dist/targets/bridge-target.js.map +1 -0
  104. package/dist/targets/stagehand-target.d.ts +3 -0
  105. package/dist/targets/stagehand-target.d.ts.map +1 -0
  106. package/dist/targets/stagehand-target.js +187 -0
  107. package/dist/targets/stagehand-target.js.map +1 -0
  108. package/dist/workspace/browser-capture.d.ts +41 -0
  109. package/dist/workspace/browser-capture.d.ts.map +1 -0
  110. package/dist/workspace/browser-capture.js +159 -0
  111. package/dist/workspace/browser-capture.js.map +1 -0
  112. package/dist/workspace/browser-workspace-desktop.d.ts +19 -0
  113. package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -0
  114. package/dist/workspace/browser-workspace-desktop.js +1578 -0
  115. package/dist/workspace/browser-workspace-desktop.js.map +1 -0
  116. package/dist/workspace/browser-workspace-elements.d.ts +42 -0
  117. package/dist/workspace/browser-workspace-elements.d.ts.map +1 -0
  118. package/dist/workspace/browser-workspace-elements.js +547 -0
  119. package/dist/workspace/browser-workspace-elements.js.map +1 -0
  120. package/dist/workspace/browser-workspace-forms.d.ts +19 -0
  121. package/dist/workspace/browser-workspace-forms.d.ts.map +1 -0
  122. package/dist/workspace/browser-workspace-forms.js +277 -0
  123. package/dist/workspace/browser-workspace-forms.js.map +1 -0
  124. package/dist/workspace/browser-workspace-helpers.d.ts +32 -0
  125. package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -0
  126. package/dist/workspace/browser-workspace-helpers.js +232 -0
  127. package/dist/workspace/browser-workspace-helpers.js.map +1 -0
  128. package/dist/workspace/browser-workspace-jsdom.d.ts +16 -0
  129. package/dist/workspace/browser-workspace-jsdom.d.ts.map +1 -0
  130. package/dist/workspace/browser-workspace-jsdom.js +233 -0
  131. package/dist/workspace/browser-workspace-jsdom.js.map +1 -0
  132. package/dist/workspace/browser-workspace-network.d.ts +7 -0
  133. package/dist/workspace/browser-workspace-network.d.ts.map +1 -0
  134. package/dist/workspace/browser-workspace-network.js +145 -0
  135. package/dist/workspace/browser-workspace-network.js.map +1 -0
  136. package/dist/workspace/browser-workspace-snapshots.d.ts +14 -0
  137. package/dist/workspace/browser-workspace-snapshots.d.ts.map +1 -0
  138. package/dist/workspace/browser-workspace-snapshots.js +144 -0
  139. package/dist/workspace/browser-workspace-snapshots.js.map +1 -0
  140. package/dist/workspace/browser-workspace-state.d.ts +24 -0
  141. package/dist/workspace/browser-workspace-state.d.ts.map +1 -0
  142. package/dist/workspace/browser-workspace-state.js +155 -0
  143. package/dist/workspace/browser-workspace-state.js.map +1 -0
  144. package/dist/workspace/browser-workspace-types.d.ts +345 -0
  145. package/dist/workspace/browser-workspace-types.d.ts.map +1 -0
  146. package/dist/workspace/browser-workspace-types.js +11 -0
  147. package/dist/workspace/browser-workspace-types.js.map +1 -0
  148. package/dist/workspace/browser-workspace-web.d.ts +8 -0
  149. package/dist/workspace/browser-workspace-web.d.ts.map +1 -0
  150. package/dist/workspace/browser-workspace-web.js +1342 -0
  151. package/dist/workspace/browser-workspace-web.js.map +1 -0
  152. package/dist/workspace/browser-workspace.d.ts +39 -0
  153. package/dist/workspace/browser-workspace.d.ts.map +1 -0
  154. package/dist/workspace/browser-workspace.js +958 -0
  155. package/dist/workspace/browser-workspace.js.map +1 -0
  156. package/dist/workspace/index.d.ts +26 -0
  157. package/dist/workspace/index.d.ts.map +1 -0
  158. package/dist/workspace/index.js +3 -0
  159. package/dist/workspace/index.js.map +1 -0
  160. package/dist/workspace.d.ts +2 -0
  161. package/dist/workspace.d.ts.map +1 -0
  162. package/dist/workspace.js +2 -0
  163. package/dist/workspace.js.map +1 -0
  164. package/package.json +71 -110
  165. package/dist/actions/click.d.ts +0 -3
  166. package/dist/actions/click.d.ts.map +0 -1
  167. package/dist/actions/click.js +0 -158
  168. package/dist/actions/click.js.map +0 -1
  169. package/dist/actions/extract.d.ts +0 -3
  170. package/dist/actions/extract.d.ts.map +0 -1
  171. package/dist/actions/extract.js +0 -168
  172. package/dist/actions/extract.js.map +0 -1
  173. package/dist/actions/index.d.ts +0 -7
  174. package/dist/actions/index.d.ts.map +0 -1
  175. package/dist/actions/index.js +0 -7
  176. package/dist/actions/index.js.map +0 -1
  177. package/dist/actions/navigate.d.ts +0 -3
  178. package/dist/actions/navigate.d.ts.map +0 -1
  179. package/dist/actions/navigate.js +0 -187
  180. package/dist/actions/navigate.js.map +0 -1
  181. package/dist/actions/screenshot.d.ts +0 -3
  182. package/dist/actions/screenshot.d.ts.map +0 -1
  183. package/dist/actions/screenshot.js +0 -167
  184. package/dist/actions/screenshot.js.map +0 -1
  185. package/dist/actions/select.d.ts +0 -3
  186. package/dist/actions/select.d.ts.map +0 -1
  187. package/dist/actions/select.js +0 -167
  188. package/dist/actions/select.js.map +0 -1
  189. package/dist/actions/type.d.ts +0 -3
  190. package/dist/actions/type.d.ts.map +0 -1
  191. package/dist/actions/type.js +0 -167
  192. package/dist/actions/type.js.map +0 -1
  193. package/dist/cli/index.d.ts +0 -8
  194. package/dist/cli/index.d.ts.map +0 -1
  195. package/dist/cli/index.js +0 -13
  196. package/dist/cli/index.js.map +0 -1
  197. package/dist/cli/register.d.ts +0 -20
  198. package/dist/cli/register.d.ts.map +0 -1
  199. package/dist/cli/register.js +0 -403
  200. package/dist/cli/register.js.map +0 -1
  201. package/dist/providerRelevance.d.ts +0 -4
  202. package/dist/providerRelevance.d.ts.map +0 -1
  203. package/dist/providerRelevance.js +0 -33
  204. package/dist/providerRelevance.js.map +0 -1
  205. package/dist/providers/browser-state.d.ts +0 -3
  206. package/dist/providers/browser-state.d.ts.map +0 -1
  207. package/dist/providers/browser-state.js +0 -72
  208. package/dist/providers/browser-state.js.map +0 -1
  209. package/dist/providers/index.d.ts +0 -2
  210. package/dist/providers/index.d.ts.map +0 -1
  211. package/dist/providers/index.js +0 -2
  212. package/dist/providers/index.js.map +0 -1
  213. package/dist/services/browser-service.d.ts +0 -32
  214. package/dist/services/browser-service.d.ts.map +0 -1
  215. package/dist/services/browser-service.js +0 -213
  216. package/dist/services/browser-service.js.map +0 -1
  217. package/dist/services/index.d.ts +0 -4
  218. package/dist/services/index.d.ts.map +0 -1
  219. package/dist/services/index.js +0 -4
  220. package/dist/services/index.js.map +0 -1
  221. package/dist/services/process-manager.d.ts +0 -24
  222. package/dist/services/process-manager.d.ts.map +0 -1
  223. package/dist/services/process-manager.js +0 -270
  224. package/dist/services/process-manager.js.map +0 -1
  225. package/dist/services/websocket-client.d.ts +0 -35
  226. package/dist/services/websocket-client.d.ts.map +0 -1
  227. package/dist/services/websocket-client.js +0 -221
  228. package/dist/services/websocket-client.js.map +0 -1
  229. package/dist/types.d.ts +0 -101
  230. package/dist/types.d.ts.map +0 -1
  231. package/dist/types.js +0 -2
  232. package/dist/types.js.map +0 -1
  233. package/dist/utils/captcha.d.ts +0 -33
  234. package/dist/utils/captcha.d.ts.map +0 -1
  235. package/dist/utils/captcha.js +0 -219
  236. package/dist/utils/captcha.js.map +0 -1
  237. package/dist/utils/errors.d.ts +0 -37
  238. package/dist/utils/errors.d.ts.map +0 -1
  239. package/dist/utils/errors.js +0 -81
  240. package/dist/utils/errors.js.map +0 -1
  241. package/dist/utils/index.d.ts +0 -5
  242. package/dist/utils/index.d.ts.map +0 -1
  243. package/dist/utils/index.js +0 -5
  244. package/dist/utils/index.js.map +0 -1
  245. package/dist/utils/retry.d.ts +0 -26
  246. package/dist/utils/retry.d.ts.map +0 -1
  247. package/dist/utils/retry.js +0 -55
  248. package/dist/utils/retry.js.map +0 -1
  249. package/dist/utils/security.d.ts +0 -27
  250. package/dist/utils/security.d.ts.map +0 -1
  251. package/dist/utils/security.js +0 -139
  252. package/dist/utils/security.js.map +0 -1
  253. package/dist/utils/url.d.ts +0 -12
  254. package/dist/utils/url.d.ts.map +0 -1
  255. package/dist/utils/url.js +0 -39
  256. package/dist/utils/url.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser-service.d.ts","sourceRoot":"","sources":["../../src/services/browser-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAElB,OAAO,EAEP,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,qBAAa,OAAQ,YAAW,cAAc;IAErC,EAAE,EAAE,MAAM;IACV,SAAS,EAAE,IAAI;gBADf,EAAE,EAAE,MAAM,EACV,SAAS,GAAE,IAAiB;CAEpC;AAED,qBAAa,cAAe,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,YAAuB;IACzC,qBAAqB,SAAgC;IAErD,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,aAAa,CAAS;IAE9B,gEAAgE;IAChE,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,CAAC,EAAE,aAAa;WAgCtB,KAAK,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;WAyDtD,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAYrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC3B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBlD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAI3D,iBAAiB,IAAI,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAOjD,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC;IAUtC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatD,SAAS,IAAI,sBAAsB;YAOrB,YAAY;CA8B1B"}
@@ -1,213 +0,0 @@
1
- import { logger, Service, ServiceType, } from "@elizaos/core";
2
- import { BrowserProcessManager } from "./process-manager.js";
3
- import { BrowserWebSocketClient } from "./websocket-client.js";
4
- export class Session {
5
- id;
6
- createdAt;
7
- constructor(id, createdAt = new Date()) {
8
- this.id = id;
9
- this.createdAt = createdAt;
10
- }
11
- }
12
- export class BrowserService extends Service {
13
- static serviceType = ServiceType.BROWSER;
14
- capabilityDescription = "Browser automation service";
15
- sessions = new Map();
16
- currentSessionId = null;
17
- processManager;
18
- client;
19
- isInitialized = false;
20
- /** Whether this service is operating in sandbox remote mode. */
21
- sandboxMode = false;
22
- constructor(runtime) {
23
- super(runtime);
24
- if (!runtime) {
25
- throw new Error("BrowserService requires a runtime");
26
- }
27
- this.runtime = runtime;
28
- // Detect sandbox mode from runtime
29
- this.sandboxMode = Boolean(runtime.sandboxMode);
30
- const portSetting = runtime.getSetting("BROWSER_SERVER_PORT");
31
- const port = typeof portSetting === "string" ? parseInt(portSetting, 10) : 3456;
32
- // In sandbox mode, connect to remote endpoint instead of local process
33
- if (this.sandboxMode) {
34
- const remoteWsUrl = runtime.getSetting("SANDBOX_BROWSER_WS_URL") ??
35
- `ws://localhost:${port}`;
36
- this.processManager = new BrowserProcessManager(port);
37
- this.client = new BrowserWebSocketClient(remoteWsUrl);
38
- logger.info(`Browser service: sandbox mode, remote endpoint: ${remoteWsUrl}`);
39
- }
40
- else {
41
- this.processManager = new BrowserProcessManager(port);
42
- this.client = new BrowserWebSocketClient(`ws://localhost:${port}`);
43
- }
44
- }
45
- static async start(runtime) {
46
- logger.info("Starting browser automation service");
47
- try {
48
- const service = new BrowserService(runtime);
49
- // In sandbox mode, do NOT start a local browser server process
50
- if (service.sandboxMode) {
51
- logger.info("Browser service: sandbox mode — skipping local server spawn");
52
- logger.info("Connecting to remote browser server...");
53
- try {
54
- await service.initialize();
55
- }
56
- catch (error) {
57
- const errorMessage = error instanceof Error ? error.message : String(error);
58
- logger.warn(`Remote browser not reachable: ${errorMessage}`);
59
- logger.warn("Browser plugin will be in degraded state");
60
- }
61
- return service;
62
- }
63
- logger.info("Starting browser server process...");
64
- let serverStarted = false;
65
- try {
66
- await service.processManager.start();
67
- serverStarted = true;
68
- logger.info("Browser server started successfully");
69
- }
70
- catch (error) {
71
- const errorMessage = error instanceof Error ? error.message : String(error);
72
- logger.error(`Failed to start browser server: ${errorMessage}`);
73
- logger.warn("Browser plugin will be available but automation will not work");
74
- logger.warn("To fix this, run: cd packages/plugin-browser && npm run build");
75
- }
76
- // Only attempt WebSocket initialization if the server actually started.
77
- // Otherwise we'd retry processManager.start() inside initialize() and
78
- // throw again, which crashes service registration.
79
- if (serverStarted) {
80
- logger.info("Initializing WebSocket client...");
81
- await service.initialize();
82
- }
83
- return service;
84
- }
85
- catch (error) {
86
- const errorMessage = error instanceof Error ? error.message : String(error);
87
- logger.error(`Failed to start browser service: ${errorMessage}`);
88
- throw error;
89
- }
90
- }
91
- static async stopRuntime(runtime) {
92
- logger.info("Stopping browser automation service");
93
- const service = runtime.getService(BrowserService.serviceType);
94
- if (!service) {
95
- throw new Error("Browser service not found");
96
- }
97
- await service.stop();
98
- }
99
- async stop() {
100
- logger.info("Cleaning up browser sessions");
101
- for (const sessionId of this.sessions.keys()) {
102
- await this.destroySession(sessionId);
103
- }
104
- this.client.disconnect();
105
- await this.processManager.stop();
106
- this.isInitialized = false;
107
- }
108
- async initialize() {
109
- if (this.isInitialized) {
110
- return;
111
- }
112
- try {
113
- if (!this.processManager.isServerRunning()) {
114
- logger.warn("Browser server is not running, attempting to start...");
115
- try {
116
- await this.processManager.start();
117
- await new Promise((resolve) => setTimeout(resolve, 2000));
118
- }
119
- catch (startError) {
120
- const msg = startError instanceof Error
121
- ? startError.message
122
- : String(startError);
123
- logger.error(`Failed to initialize browser service: ${msg}`);
124
- // Don't throw — allow the service to exist in a degraded state
125
- // so other plugins can still function.
126
- return;
127
- }
128
- }
129
- logger.info("Connecting to browser server...");
130
- await this.client.connect();
131
- await this.waitForReady();
132
- this.isInitialized = true;
133
- logger.info("Browser service initialized successfully");
134
- }
135
- catch (error) {
136
- const errorMessage = error instanceof Error ? error.message : String(error);
137
- logger.error(`Failed to initialize browser service: ${errorMessage}`);
138
- throw error;
139
- }
140
- }
141
- async createSession(sessionId) {
142
- if (!this.isInitialized) {
143
- throw new Error("Browser service not initialized");
144
- }
145
- const response = await this.client.sendMessage("createSession", {});
146
- const serverSessionId = response.data
147
- ?.sessionId;
148
- if (!serverSessionId) {
149
- throw new Error("Failed to create session on server");
150
- }
151
- const session = new Session(serverSessionId);
152
- this.sessions.set(sessionId, session);
153
- this.currentSessionId = sessionId;
154
- return session;
155
- }
156
- async getSession(sessionId) {
157
- return this.sessions.get(sessionId);
158
- }
159
- async getCurrentSession() {
160
- if (!this.currentSessionId) {
161
- return undefined;
162
- }
163
- return this.sessions.get(this.currentSessionId);
164
- }
165
- async getOrCreateSession() {
166
- const currentSession = await this.getCurrentSession();
167
- if (currentSession) {
168
- return currentSession;
169
- }
170
- const sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(7)}`;
171
- return this.createSession(sessionId);
172
- }
173
- async destroySession(sessionId) {
174
- const session = this.sessions.get(sessionId);
175
- if (session) {
176
- await this.client.sendMessage("destroySession", {
177
- sessionId: session.id,
178
- });
179
- this.sessions.delete(sessionId);
180
- if (this.currentSessionId === sessionId) {
181
- this.currentSessionId = null;
182
- }
183
- }
184
- }
185
- getClient() {
186
- if (!this.isInitialized) {
187
- throw new Error("Browser service not initialized");
188
- }
189
- return this.client;
190
- }
191
- async waitForReady(maxAttempts = 60, delayMs = 3000) {
192
- logger.info("Waiting for browser server to be ready...");
193
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
194
- try {
195
- const isHealthy = await this.client.health();
196
- if (isHealthy) {
197
- logger.info("Browser server is ready");
198
- return;
199
- }
200
- }
201
- catch (error) {
202
- const errorMessage = error instanceof Error ? error.message : String(error);
203
- logger.debug(`Health check attempt ${attempt}/${maxAttempts} failed: ${errorMessage}`);
204
- }
205
- if (attempt < maxAttempts) {
206
- logger.info(`Server not ready yet, retrying in ${delayMs / 1000}s... (attempt ${attempt}/${maxAttempts})`);
207
- await new Promise((resolve) => setTimeout(resolve, delayMs));
208
- }
209
- }
210
- throw new Error(`Browser server did not become ready after ${maxAttempts} attempts`);
211
- }
212
- }
213
- //# sourceMappingURL=browser-service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser-service.js","sourceRoot":"","sources":["../../src/services/browser-service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype IAgentRuntime,\n\tlogger,\n\tService,\n\tServiceType,\n} from \"@elizaos/core\";\nimport type { BrowserSession } from \"../types.js\";\nimport { BrowserProcessManager } from \"./process-manager.js\";\nimport { BrowserWebSocketClient } from \"./websocket-client.js\";\n\nexport class Session implements BrowserSession {\n\tconstructor(\n\t\tpublic id: string,\n\t\tpublic createdAt: Date = new Date(),\n\t) {}\n}\n\nexport class BrowserService extends Service {\n\tstatic serviceType = ServiceType.BROWSER;\n\tcapabilityDescription = \"Browser automation service\";\n\n\tprivate sessions = new Map<string, Session>();\n\tprivate currentSessionId: string | null = null;\n\tprivate processManager: BrowserProcessManager;\n\tprivate client: BrowserWebSocketClient;\n\tprivate isInitialized = false;\n\n\t/** Whether this service is operating in sandbox remote mode. */\n\tprivate sandboxMode = false;\n\n\tconstructor(runtime?: IAgentRuntime) {\n\t\tsuper(runtime);\n\t\tif (!runtime) {\n\t\t\tthrow new Error(\"BrowserService requires a runtime\");\n\t\t}\n\t\tthis.runtime = runtime;\n\n\t\t// Detect sandbox mode from runtime\n\t\tthis.sandboxMode = Boolean(\n\t\t\t(runtime as unknown as Record<string, unknown>).sandboxMode,\n\t\t);\n\n\t\tconst portSetting = runtime.getSetting(\"BROWSER_SERVER_PORT\");\n\t\tconst port =\n\t\t\ttypeof portSetting === \"string\" ? parseInt(portSetting, 10) : 3456;\n\n\t\t// In sandbox mode, connect to remote endpoint instead of local process\n\t\tif (this.sandboxMode) {\n\t\t\tconst remoteWsUrl =\n\t\t\t\t(runtime.getSetting(\"SANDBOX_BROWSER_WS_URL\") as string | null) ??\n\t\t\t\t`ws://localhost:${port}`;\n\t\t\tthis.processManager = new BrowserProcessManager(port);\n\t\t\tthis.client = new BrowserWebSocketClient(remoteWsUrl);\n\t\t\tlogger.info(\n\t\t\t\t`Browser service: sandbox mode, remote endpoint: ${remoteWsUrl}`,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.processManager = new BrowserProcessManager(port);\n\t\t\tthis.client = new BrowserWebSocketClient(`ws://localhost:${port}`);\n\t\t}\n\t}\n\n\tstatic async start(runtime: IAgentRuntime): Promise<BrowserService> {\n\t\tlogger.info(\"Starting browser automation service\");\n\t\ttry {\n\t\t\tconst service = new BrowserService(runtime);\n\n\t\t\t// In sandbox mode, do NOT start a local browser server process\n\t\t\tif (service.sandboxMode) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t\"Browser service: sandbox mode — skipping local server spawn\",\n\t\t\t\t);\n\t\t\t\tlogger.info(\"Connecting to remote browser server...\");\n\t\t\t\ttry {\n\t\t\t\t\tawait service.initialize();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\t\tlogger.warn(`Remote browser not reachable: ${errorMessage}`);\n\t\t\t\t\tlogger.warn(\"Browser plugin will be in degraded state\");\n\t\t\t\t}\n\t\t\t\treturn service;\n\t\t\t}\n\n\t\t\tlogger.info(\"Starting browser server process...\");\n\t\t\tlet serverStarted = false;\n\t\t\ttry {\n\t\t\t\tawait service.processManager.start();\n\t\t\t\tserverStarted = true;\n\t\t\t\tlogger.info(\"Browser server started successfully\");\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tlogger.error(`Failed to start browser server: ${errorMessage}`);\n\t\t\t\tlogger.warn(\n\t\t\t\t\t\"Browser plugin will be available but automation will not work\",\n\t\t\t\t);\n\t\t\t\tlogger.warn(\n\t\t\t\t\t\"To fix this, run: cd packages/plugin-browser && npm run build\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Only attempt WebSocket initialization if the server actually started.\n\t\t\t// Otherwise we'd retry processManager.start() inside initialize() and\n\t\t\t// throw again, which crashes service registration.\n\t\t\tif (serverStarted) {\n\t\t\t\tlogger.info(\"Initializing WebSocket client...\");\n\t\t\t\tawait service.initialize();\n\t\t\t}\n\n\t\t\treturn service;\n\t\t} catch (error) {\n\t\t\tconst errorMessage =\n\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\tlogger.error(`Failed to start browser service: ${errorMessage}`);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tstatic async stopRuntime(runtime: IAgentRuntime): Promise<void> {\n\t\tlogger.info(\"Stopping browser automation service\");\n\t\tconst service = runtime.getService<BrowserService>(\n\t\t\tBrowserService.serviceType,\n\t\t);\n\t\tif (!service) {\n\t\t\tthrow new Error(\"Browser service not found\");\n\t\t}\n\t\tawait service.stop();\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tlogger.info(\"Cleaning up browser sessions\");\n\n\t\tfor (const sessionId of this.sessions.keys()) {\n\t\t\tawait this.destroySession(sessionId);\n\t\t}\n\n\t\tthis.client.disconnect();\n\t\tawait this.processManager.stop();\n\t\tthis.isInitialized = false;\n\t}\n\n\tasync initialize(): Promise<void> {\n\t\tif (this.isInitialized) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tif (!this.processManager.isServerRunning()) {\n\t\t\t\tlogger.warn(\"Browser server is not running, attempting to start...\");\n\t\t\t\ttry {\n\t\t\t\t\tawait this.processManager.start();\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 2000));\n\t\t\t\t} catch (startError) {\n\t\t\t\t\tconst msg =\n\t\t\t\t\t\tstartError instanceof Error\n\t\t\t\t\t\t\t? startError.message\n\t\t\t\t\t\t\t: String(startError);\n\t\t\t\t\tlogger.error(`Failed to initialize browser service: ${msg}`);\n\t\t\t\t\t// Don't throw — allow the service to exist in a degraded state\n\t\t\t\t\t// so other plugins can still function.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlogger.info(\"Connecting to browser server...\");\n\t\t\tawait this.client.connect();\n\n\t\t\tawait this.waitForReady();\n\n\t\t\tthis.isInitialized = true;\n\t\t\tlogger.info(\"Browser service initialized successfully\");\n\t\t} catch (error) {\n\t\t\tconst errorMessage =\n\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\tlogger.error(`Failed to initialize browser service: ${errorMessage}`);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync createSession(sessionId: string): Promise<Session> {\n\t\tif (!this.isInitialized) {\n\t\t\tthrow new Error(\"Browser service not initialized\");\n\t\t}\n\n\t\tconst response = await this.client.sendMessage(\"createSession\", {});\n\t\tconst serverSessionId = (response.data as { sessionId?: string })\n\t\t\t?.sessionId;\n\t\tif (!serverSessionId) {\n\t\t\tthrow new Error(\"Failed to create session on server\");\n\t\t}\n\n\t\tconst session = new Session(serverSessionId);\n\t\tthis.sessions.set(sessionId, session);\n\t\tthis.currentSessionId = sessionId;\n\n\t\treturn session;\n\t}\n\n\tasync getSession(sessionId: string): Promise<Session | undefined> {\n\t\treturn this.sessions.get(sessionId);\n\t}\n\n\tasync getCurrentSession(): Promise<Session | undefined> {\n\t\tif (!this.currentSessionId) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.sessions.get(this.currentSessionId);\n\t}\n\n\tasync getOrCreateSession(): Promise<Session> {\n\t\tconst currentSession = await this.getCurrentSession();\n\t\tif (currentSession) {\n\t\t\treturn currentSession;\n\t\t}\n\n\t\tconst sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(7)}`;\n\t\treturn this.createSession(sessionId);\n\t}\n\n\tasync destroySession(sessionId: string): Promise<void> {\n\t\tconst session = this.sessions.get(sessionId);\n\t\tif (session) {\n\t\t\tawait this.client.sendMessage(\"destroySession\", {\n\t\t\t\tsessionId: session.id,\n\t\t\t});\n\t\t\tthis.sessions.delete(sessionId);\n\t\t\tif (this.currentSessionId === sessionId) {\n\t\t\t\tthis.currentSessionId = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tgetClient(): BrowserWebSocketClient {\n\t\tif (!this.isInitialized) {\n\t\t\tthrow new Error(\"Browser service not initialized\");\n\t\t}\n\t\treturn this.client;\n\t}\n\n\tprivate async waitForReady(maxAttempts = 60, delayMs = 3000): Promise<void> {\n\t\tlogger.info(\"Waiting for browser server to be ready...\");\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\tconst isHealthy = await this.client.health();\n\t\t\t\tif (isHealthy) {\n\t\t\t\t\tlogger.info(\"Browser server is ready\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tlogger.debug(\n\t\t\t\t\t`Health check attempt ${attempt}/${maxAttempts} failed: ${errorMessage}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (attempt < maxAttempts) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t`Server not ready yet, retrying in ${delayMs / 1000}s... (attempt ${attempt}/${maxAttempts})`,\n\t\t\t\t);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`Browser server did not become ready after ${maxAttempts} attempts`,\n\t\t);\n\t}\n}\n"]}
@@ -1,4 +0,0 @@
1
- export { BrowserService, Session } from "./browser-service.js";
2
- export { BrowserProcessManager } from "./process-manager.js";
3
- export { BrowserWebSocketClient } from "./websocket-client.js";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,4 +0,0 @@
1
- export { BrowserService, Session } from "./browser-service.js";
2
- export { BrowserProcessManager } from "./process-manager.js";
3
- export { BrowserWebSocketClient } from "./websocket-client.js";
4
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export { BrowserService, Session } from \"./browser-service.js\";\nexport { BrowserProcessManager } from \"./process-manager.js\";\nexport { BrowserWebSocketClient } from \"./websocket-client.js\";\n"]}
@@ -1,24 +0,0 @@
1
- export declare class BrowserProcessManager {
2
- private serverPort;
3
- private process;
4
- private isRunning;
5
- private binaryPath;
6
- constructor(serverPort?: number);
7
- private getBinaryName;
8
- private findBinary;
9
- /**
10
- * Probe the port for an existing stagehand-server.
11
- * Returns `true` if a WebSocket server is already listening and responds.
12
- */
13
- private probeExistingServer;
14
- /**
15
- * Kill whatever process is listening on `this.serverPort`.
16
- * Uses `lsof` on Unix / `netstat` on Windows. Best-effort.
17
- */
18
- private freePort;
19
- start(): Promise<void>;
20
- stop(): Promise<void>;
21
- isServerRunning(): boolean;
22
- getServerUrl(): string;
23
- }
24
- //# sourceMappingURL=process-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../src/services/process-manager.ts"],"names":[],"mappings":"AAQA,qBAAa,qBAAqB;IAKrB,OAAO,CAAC,UAAU;IAJ9B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAuB;gBAErB,UAAU,GAAE,MAAa;IAI7C,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,UAAU;IAyDlB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAuC3B;;;OAGG;YACW,QAAQ;IA4BhB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuHtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B,eAAe,IAAI,OAAO;IAI1B,YAAY,IAAI,MAAM;CAGtB"}
@@ -1,270 +0,0 @@
1
- import { execSync, spawn } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { platform } from "node:os";
4
- import { dirname, join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- import { logger } from "@elizaos/core";
7
- import WebSocket from "ws";
8
- export class BrowserProcessManager {
9
- serverPort;
10
- process = null;
11
- isRunning = false;
12
- binaryPath = null;
13
- constructor(serverPort = 3456) {
14
- this.serverPort = serverPort;
15
- this.binaryPath = this.findBinary();
16
- }
17
- getBinaryName() {
18
- const platformName = platform();
19
- const arch = process.arch;
20
- const ext = platformName === "win32" ? ".exe" : "";
21
- return {
22
- primary: `browser-server-${platformName}-${arch}${ext}`,
23
- fallback: `browser-server-${platformName}${ext}`,
24
- };
25
- }
26
- findBinary() {
27
- const moduleDir = dirname(fileURLToPath(import.meta.url));
28
- const isDocker = process.env.DOCKER_CONTAINER === "true" || existsSync("/.dockerenv");
29
- const binaryNames = this.getBinaryName();
30
- const possiblePaths = [
31
- ...(isDocker
32
- ? [
33
- "/usr/local/bin/browser-server",
34
- "/usr/local/bin/browser-server-linux",
35
- "/app/browser-server",
36
- `/app/binaries/${binaryNames.primary}`,
37
- `/app/binaries/${binaryNames.fallback}`,
38
- ]
39
- : []),
40
- ...(!isDocker ? [join(moduleDir, "../server/dist/index.js")] : []),
41
- join(moduleDir, "../server/binaries", binaryNames.primary),
42
- join(moduleDir, "../server/binaries", binaryNames.fallback),
43
- join(moduleDir, "../../../browser-server", binaryNames.primary),
44
- join(moduleDir, "../../../browser-server", binaryNames.fallback),
45
- join(moduleDir, "../../.bin", "browser-server"),
46
- join(moduleDir, "../server/dist/index.js"),
47
- ...(isDocker
48
- ? [
49
- "/app/packages/plugin-browser/server/dist/index.js",
50
- "/app/browser-server/dist/index.js",
51
- ]
52
- : []),
53
- ];
54
- for (const p of possiblePaths) {
55
- if (existsSync(p)) {
56
- logger.info(`Found browser server at: ${p}`);
57
- return p;
58
- }
59
- }
60
- const srcPath = join(moduleDir, "../server/src/index.ts");
61
- if (existsSync(srcPath)) {
62
- logger.warn("No compiled binary found, will try to run from source with tsx");
63
- return srcPath;
64
- }
65
- logger.error("Could not find browser server binary or source files");
66
- logger.error(`Searched paths: ${possiblePaths.join(", ")}`);
67
- return null;
68
- }
69
- // ---------------------------------------------------------------------------
70
- // Port management
71
- // ---------------------------------------------------------------------------
72
- /**
73
- * Probe the port for an existing stagehand-server.
74
- * Returns `true` if a WebSocket server is already listening and responds.
75
- */
76
- probeExistingServer() {
77
- return new Promise((resolve) => {
78
- const timeout = setTimeout(() => {
79
- conn.close();
80
- resolve(false);
81
- }, 2_000);
82
- const conn = new WebSocket(`ws://localhost:${this.serverPort}`);
83
- conn.on("message", (data) => {
84
- try {
85
- const msg = JSON.parse(data.toString());
86
- // The stagehand-server sends { type: "connected", ... } on connect.
87
- if (msg.type === "connected") {
88
- clearTimeout(timeout);
89
- conn.close();
90
- resolve(true);
91
- return;
92
- }
93
- }
94
- catch {
95
- // Not valid JSON — not our server.
96
- }
97
- clearTimeout(timeout);
98
- conn.close();
99
- resolve(false);
100
- });
101
- conn.on("open", () => {
102
- // Connection opened — wait for the "connected" message (handled above).
103
- // If no message arrives within the timeout, we'll resolve(false).
104
- });
105
- conn.on("error", () => {
106
- clearTimeout(timeout);
107
- resolve(false);
108
- });
109
- });
110
- }
111
- /**
112
- * Kill whatever process is listening on `this.serverPort`.
113
- * Uses `lsof` on Unix / `netstat` on Windows. Best-effort.
114
- */
115
- async freePort() {
116
- const port = this.serverPort;
117
- try {
118
- if (process.platform === "win32") {
119
- // netstat → find PID → taskkill
120
- const out = execSync(`netstat -ano | findstr :${port} | findstr LISTENING`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] });
121
- const pid = out.trim().split(/\s+/).pop();
122
- if (pid && /^\d+$/.test(pid)) {
123
- execSync(`taskkill /F /PID ${pid}`, { stdio: "ignore" });
124
- }
125
- }
126
- else {
127
- execSync(`lsof -ti :${port} | xargs kill -9`, { stdio: "ignore" });
128
- }
129
- // Give the OS a moment to release the port.
130
- await new Promise((r) => setTimeout(r, 500));
131
- logger.info(`Freed port ${port}`);
132
- }
133
- catch {
134
- // Nothing on the port, or kill failed — either way it's fine.
135
- }
136
- }
137
- // ---------------------------------------------------------------------------
138
- // Start / stop
139
- // ---------------------------------------------------------------------------
140
- async start() {
141
- if (this.isRunning) {
142
- logger.warn("Browser server is already running");
143
- return;
144
- }
145
- // ── 1. Check for an existing stagehand-server on the port ──────────────
146
- if (await this.probeExistingServer()) {
147
- logger.info(`Reusing existing browser server on port ${this.serverPort}`);
148
- this.isRunning = true;
149
- return;
150
- }
151
- // ── 2. Something else is on the port — try to free it ──────────────────
152
- await this.freePort();
153
- // ── 3. Spawn a new server ──────────────────────────────────────────────
154
- if (!this.binaryPath) {
155
- throw new Error("Browser server binary not found - please ensure server is built");
156
- }
157
- const binaryPath = this.binaryPath;
158
- return new Promise((resolve, reject) => {
159
- let settled = false;
160
- const startupTimeout = setTimeout(() => {
161
- if (!settled) {
162
- settled = true;
163
- if (this.process)
164
- this.process.kill("SIGTERM");
165
- reject(new Error("Browser server startup timed out after 30s"));
166
- }
167
- }, 30_000);
168
- const ok = () => {
169
- if (!settled) {
170
- settled = true;
171
- clearTimeout(startupTimeout);
172
- resolve();
173
- }
174
- };
175
- const fail = (err) => {
176
- if (!settled) {
177
- settled = true;
178
- clearTimeout(startupTimeout);
179
- reject(err);
180
- }
181
- };
182
- // Pass through the parent env as-is; only override port + NODE_ENV.
183
- const env = {
184
- ...process.env,
185
- BROWSER_SERVER_PORT: this.serverPort.toString(),
186
- NODE_ENV: process.env.NODE_ENV ?? "production",
187
- };
188
- const isBinary = !binaryPath.endsWith(".js") && !binaryPath.endsWith(".ts");
189
- const isTypeScript = binaryPath.endsWith(".ts");
190
- if (isBinary) {
191
- this.process = spawn(binaryPath, [], { env });
192
- }
193
- else if (isTypeScript) {
194
- try {
195
- const tsxPath = require.resolve("tsx/cli", {
196
- paths: [process.cwd()],
197
- });
198
- this.process = spawn("node", [tsxPath, binaryPath], { env });
199
- }
200
- catch {
201
- logger.warn("tsx not found, falling back to node --import tsx");
202
- this.process = spawn("node", ["--import", "tsx", binaryPath], {
203
- env,
204
- });
205
- }
206
- }
207
- else {
208
- this.process = spawn("node", [binaryPath], { env });
209
- }
210
- this.process.stdout?.on("data", (data) => {
211
- const message = data.toString().trim();
212
- logger.debug(`[BrowserServer] ${message}`);
213
- if (message.includes("listening on port")) {
214
- this.isRunning = true;
215
- ok();
216
- }
217
- });
218
- this.process.stderr?.on("data", (data) => {
219
- const text = data.toString().trim();
220
- if (text.includes("Error") ||
221
- text.includes("EADDRINUSE") ||
222
- text.includes("FATAL")) {
223
- logger.error(`[BrowserServer] ${text}`);
224
- }
225
- else {
226
- logger.debug(`[BrowserServer stderr] ${text}`);
227
- }
228
- });
229
- this.process.on("error", (error) => {
230
- logger.error(`Failed to start browser server: ${error.message}`);
231
- this.isRunning = false;
232
- fail(error);
233
- });
234
- this.process.on("exit", (code) => {
235
- this.isRunning = false;
236
- if (code !== 0 && code !== null) {
237
- logger.warn(`Browser server exited with code ${code}`);
238
- fail(new Error(`Browser server exited with code ${code}`));
239
- }
240
- else {
241
- logger.info("Browser server stopped");
242
- }
243
- });
244
- });
245
- }
246
- async stop() {
247
- if (!this.process || !this.isRunning) {
248
- return;
249
- }
250
- return new Promise((resolve) => {
251
- this.process?.on("exit", () => {
252
- this.isRunning = false;
253
- resolve();
254
- });
255
- this.process?.kill("SIGTERM");
256
- setTimeout(() => {
257
- if (this.isRunning && this.process) {
258
- this.process.kill("SIGKILL");
259
- }
260
- }, 5000);
261
- });
262
- }
263
- isServerRunning() {
264
- return this.isRunning;
265
- }
266
- getServerUrl() {
267
- return `ws://localhost:${this.serverPort}`;
268
- }
269
- }
270
- //# sourceMappingURL=process-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../../src/services/process-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, execSync, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { platform } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"@elizaos/core\";\nimport WebSocket from \"ws\";\n\nexport class BrowserProcessManager {\n\tprivate process: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate binaryPath: string | null = null;\n\n\tconstructor(private serverPort: number = 3456) {\n\t\tthis.binaryPath = this.findBinary();\n\t}\n\n\tprivate getBinaryName(): { primary: string; fallback: string } {\n\t\tconst platformName = platform();\n\t\tconst arch = process.arch;\n\t\tconst ext = platformName === \"win32\" ? \".exe\" : \"\";\n\n\t\treturn {\n\t\t\tprimary: `browser-server-${platformName}-${arch}${ext}`,\n\t\t\tfallback: `browser-server-${platformName}${ext}`,\n\t\t};\n\t}\n\n\tprivate findBinary(): string | null {\n\t\tconst moduleDir = dirname(fileURLToPath(import.meta.url));\n\t\tconst isDocker =\n\t\t\tprocess.env.DOCKER_CONTAINER === \"true\" || existsSync(\"/.dockerenv\");\n\t\tconst binaryNames = this.getBinaryName();\n\n\t\tconst possiblePaths = [\n\t\t\t...(isDocker\n\t\t\t\t? [\n\t\t\t\t\t\t\"/usr/local/bin/browser-server\",\n\t\t\t\t\t\t\"/usr/local/bin/browser-server-linux\",\n\t\t\t\t\t\t\"/app/browser-server\",\n\t\t\t\t\t\t`/app/binaries/${binaryNames.primary}`,\n\t\t\t\t\t\t`/app/binaries/${binaryNames.fallback}`,\n\t\t\t\t\t]\n\t\t\t\t: []),\n\n\t\t\t...(!isDocker ? [join(moduleDir, \"../server/dist/index.js\")] : []),\n\t\t\tjoin(moduleDir, \"../server/binaries\", binaryNames.primary),\n\t\t\tjoin(moduleDir, \"../server/binaries\", binaryNames.fallback),\n\t\t\tjoin(moduleDir, \"../../../browser-server\", binaryNames.primary),\n\t\t\tjoin(moduleDir, \"../../../browser-server\", binaryNames.fallback),\n\t\t\tjoin(moduleDir, \"../../.bin\", \"browser-server\"),\n\t\t\tjoin(moduleDir, \"../server/dist/index.js\"),\n\n\t\t\t...(isDocker\n\t\t\t\t? [\n\t\t\t\t\t\t\"/app/packages/plugin-browser/server/dist/index.js\",\n\t\t\t\t\t\t\"/app/browser-server/dist/index.js\",\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t];\n\n\t\tfor (const p of possiblePaths) {\n\t\t\tif (existsSync(p)) {\n\t\t\t\tlogger.info(`Found browser server at: ${p}`);\n\t\t\t\treturn p;\n\t\t\t}\n\t\t}\n\n\t\tconst srcPath = join(moduleDir, \"../server/src/index.ts\");\n\t\tif (existsSync(srcPath)) {\n\t\t\tlogger.warn(\n\t\t\t\t\"No compiled binary found, will try to run from source with tsx\",\n\t\t\t);\n\t\t\treturn srcPath;\n\t\t}\n\n\t\tlogger.error(\"Could not find browser server binary or source files\");\n\t\tlogger.error(`Searched paths: ${possiblePaths.join(\", \")}`);\n\t\treturn null;\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Port management\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Probe the port for an existing stagehand-server.\n\t * Returns `true` if a WebSocket server is already listening and responds.\n\t */\n\tprivate probeExistingServer(): Promise<boolean> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tconn.close();\n\t\t\t\tresolve(false);\n\t\t\t}, 2_000);\n\n\t\t\tconst conn = new WebSocket(`ws://localhost:${this.serverPort}`);\n\n\t\t\tconn.on(\"message\", (data) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst msg = JSON.parse(data.toString());\n\t\t\t\t\t// The stagehand-server sends { type: \"connected\", ... } on connect.\n\t\t\t\t\tif (msg.type === \"connected\") {\n\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\tconn.close();\n\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Not valid JSON — not our server.\n\t\t\t\t}\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tconn.close();\n\t\t\t\tresolve(false);\n\t\t\t});\n\n\t\t\tconn.on(\"open\", () => {\n\t\t\t\t// Connection opened — wait for the \"connected\" message (handled above).\n\t\t\t\t// If no message arrives within the timeout, we'll resolve(false).\n\t\t\t});\n\n\t\t\tconn.on(\"error\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve(false);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Kill whatever process is listening on `this.serverPort`.\n\t * Uses `lsof` on Unix / `netstat` on Windows. Best-effort.\n\t */\n\tprivate async freePort(): Promise<void> {\n\t\tconst port = this.serverPort;\n\t\ttry {\n\t\t\tif (process.platform === \"win32\") {\n\t\t\t\t// netstat → find PID → taskkill\n\t\t\t\tconst out = execSync(\n\t\t\t\t\t`netstat -ano | findstr :${port} | findstr LISTENING`,\n\t\t\t\t\t{ encoding: \"utf8\", stdio: [\"pipe\", \"pipe\", \"ignore\"] },\n\t\t\t\t);\n\t\t\t\tconst pid = out.trim().split(/\\s+/).pop();\n\t\t\t\tif (pid && /^\\d+$/.test(pid)) {\n\t\t\t\t\texecSync(`taskkill /F /PID ${pid}`, { stdio: \"ignore\" });\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\texecSync(`lsof -ti :${port} | xargs kill -9`, { stdio: \"ignore\" });\n\t\t\t}\n\t\t\t// Give the OS a moment to release the port.\n\t\t\tawait new Promise((r) => setTimeout(r, 500));\n\t\t\tlogger.info(`Freed port ${port}`);\n\t\t} catch {\n\t\t\t// Nothing on the port, or kill failed — either way it's fine.\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Start / stop\n\t// ---------------------------------------------------------------------------\n\n\tasync start(): Promise<void> {\n\t\tif (this.isRunning) {\n\t\t\tlogger.warn(\"Browser server is already running\");\n\t\t\treturn;\n\t\t}\n\n\t\t// ── 1. Check for an existing stagehand-server on the port ──────────────\n\t\tif (await this.probeExistingServer()) {\n\t\t\tlogger.info(`Reusing existing browser server on port ${this.serverPort}`);\n\t\t\tthis.isRunning = true;\n\t\t\treturn;\n\t\t}\n\n\t\t// ── 2. Something else is on the port — try to free it ──────────────────\n\t\tawait this.freePort();\n\n\t\t// ── 3. Spawn a new server ──────────────────────────────────────────────\n\t\tif (!this.binaryPath) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Browser server binary not found - please ensure server is built\",\n\t\t\t);\n\t\t}\n\n\t\tconst binaryPath = this.binaryPath;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst startupTimeout = setTimeout(() => {\n\t\t\t\tif (!settled) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tif (this.process) this.process.kill(\"SIGTERM\");\n\t\t\t\t\treject(new Error(\"Browser server startup timed out after 30s\"));\n\t\t\t\t}\n\t\t\t}, 30_000);\n\t\t\tconst ok = () => {\n\t\t\t\tif (!settled) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tclearTimeout(startupTimeout);\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst fail = (err: Error) => {\n\t\t\t\tif (!settled) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tclearTimeout(startupTimeout);\n\t\t\t\t\treject(err);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Pass through the parent env as-is; only override port + NODE_ENV.\n\t\t\tconst env: Record<string, string | undefined> = {\n\t\t\t\t...process.env,\n\t\t\t\tBROWSER_SERVER_PORT: this.serverPort.toString(),\n\t\t\t\tNODE_ENV: process.env.NODE_ENV ?? \"production\",\n\t\t\t};\n\n\t\t\tconst isBinary =\n\t\t\t\t!binaryPath.endsWith(\".js\") && !binaryPath.endsWith(\".ts\");\n\t\t\tconst isTypeScript = binaryPath.endsWith(\".ts\");\n\n\t\t\tif (isBinary) {\n\t\t\t\tthis.process = spawn(binaryPath, [], { env });\n\t\t\t} else if (isTypeScript) {\n\t\t\t\ttry {\n\t\t\t\t\tconst tsxPath = require.resolve(\"tsx/cli\", {\n\t\t\t\t\t\tpaths: [process.cwd()],\n\t\t\t\t\t});\n\t\t\t\t\tthis.process = spawn(\"node\", [tsxPath, binaryPath], { env });\n\t\t\t\t} catch {\n\t\t\t\t\tlogger.warn(\"tsx not found, falling back to node --import tsx\");\n\t\t\t\t\tthis.process = spawn(\"node\", [\"--import\", \"tsx\", binaryPath], {\n\t\t\t\t\t\tenv,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.process = spawn(\"node\", [binaryPath], { env });\n\t\t\t}\n\n\t\t\tthis.process.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\t\tconst message = data.toString().trim();\n\t\t\t\tlogger.debug(`[BrowserServer] ${message}`);\n\n\t\t\t\tif (message.includes(\"listening on port\")) {\n\t\t\t\t\tthis.isRunning = true;\n\t\t\t\t\tok();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.process.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\t\tconst text = data.toString().trim();\n\t\t\t\tif (\n\t\t\t\t\ttext.includes(\"Error\") ||\n\t\t\t\t\ttext.includes(\"EADDRINUSE\") ||\n\t\t\t\t\ttext.includes(\"FATAL\")\n\t\t\t\t) {\n\t\t\t\t\tlogger.error(`[BrowserServer] ${text}`);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.debug(`[BrowserServer stderr] ${text}`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.process.on(\"error\", (error: Error) => {\n\t\t\t\tlogger.error(`Failed to start browser server: ${error.message}`);\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tfail(error);\n\t\t\t});\n\n\t\t\tthis.process.on(\"exit\", (code) => {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tif (code !== 0 && code !== null) {\n\t\t\t\t\tlogger.warn(`Browser server exited with code ${code}`);\n\t\t\t\t\tfail(new Error(`Browser server exited with code ${code}`));\n\t\t\t\t} else {\n\t\t\t\t\tlogger.info(\"Browser server stopped\");\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tif (!this.process || !this.isRunning) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.process?.on(\"exit\", () => {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tresolve();\n\t\t\t});\n\n\t\t\tthis.process?.kill(\"SIGTERM\");\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (this.isRunning && this.process) {\n\t\t\t\t\tthis.process.kill(\"SIGKILL\");\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t});\n\t}\n\n\tisServerRunning(): boolean {\n\t\treturn this.isRunning;\n\t}\n\n\tgetServerUrl(): string {\n\t\treturn `ws://localhost:${this.serverPort}`;\n\t}\n}\n"]}
@@ -1,35 +0,0 @@
1
- import type { NavigationResult, WebSocketResponse } from "../types.js";
2
- export declare class BrowserWebSocketClient {
3
- private serverUrl;
4
- private ws;
5
- private messageHandlers;
6
- private connected;
7
- private reconnectAttempts;
8
- private maxReconnectAttempts;
9
- private reconnectDelay;
10
- constructor(serverUrl: string);
11
- connect(): Promise<void>;
12
- private rawDataToString;
13
- private attemptReconnect;
14
- sendMessage(type: string, data: Record<string, unknown>): Promise<WebSocketResponse>;
15
- disconnect(): void;
16
- isConnected(): boolean;
17
- navigate(sessionId: string, url: string): Promise<NavigationResult>;
18
- getState(sessionId: string): Promise<{
19
- url: string;
20
- title: string;
21
- sessionId: string;
22
- createdAt: Date;
23
- }>;
24
- goBack(sessionId: string): Promise<NavigationResult>;
25
- goForward(sessionId: string): Promise<NavigationResult>;
26
- refresh(sessionId: string): Promise<NavigationResult>;
27
- click(sessionId: string, description: string): Promise<WebSocketResponse>;
28
- type(sessionId: string, text: string, field: string): Promise<WebSocketResponse>;
29
- select(sessionId: string, option: string, dropdown: string): Promise<WebSocketResponse>;
30
- extract(sessionId: string, instruction: string): Promise<WebSocketResponse>;
31
- screenshot(sessionId: string): Promise<WebSocketResponse>;
32
- solveCaptcha(sessionId: string): Promise<WebSocketResponse>;
33
- health(): Promise<boolean>;
34
- }
35
- //# sourceMappingURL=websocket-client.d.ts.map