@beeos-ai/device-agent 0.4.0

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 (398) hide show
  1. package/.pi/extensions/android-tools.ts +139 -0
  2. package/.pi/skills/.gitkeep +0 -0
  3. package/.pi/skills/ground-mobile-fallback/SKILL.md +50 -0
  4. package/LICENSE +201 -0
  5. package/dist/action/handler.d.ts +9 -0
  6. package/dist/action/handler.js +124 -0
  7. package/dist/action/handler.js.map +1 -0
  8. package/dist/adapters/agent-gateway-client.d.ts +256 -0
  9. package/dist/adapters/agent-gateway-client.js +332 -0
  10. package/dist/adapters/agent-gateway-client.js.map +1 -0
  11. package/dist/adapters/agentcore-inner-loop.d.ts +29 -0
  12. package/dist/adapters/agentcore-inner-loop.js +72 -0
  13. package/dist/adapters/agentcore-inner-loop.js.map +1 -0
  14. package/dist/adapters/agentcore-pi.d.ts +215 -0
  15. package/dist/adapters/agentcore-pi.js +464 -0
  16. package/dist/adapters/agentcore-pi.js.map +1 -0
  17. package/dist/adapters/agentcore-runner.d.ts +70 -0
  18. package/dist/adapters/agentcore-runner.js +255 -0
  19. package/dist/adapters/agentcore-runner.js.map +1 -0
  20. package/dist/adapters/device-android-adb.d.ts +41 -0
  21. package/dist/adapters/device-android-adb.js +279 -0
  22. package/dist/adapters/device-android-adb.js.map +1 -0
  23. package/dist/adapters/device-desktop.d.ts +37 -0
  24. package/dist/adapters/device-desktop.js +101 -0
  25. package/dist/adapters/device-desktop.js.map +1 -0
  26. package/dist/adapters/identity-file.d.ts +30 -0
  27. package/dist/adapters/identity-file.js +50 -0
  28. package/dist/adapters/identity-file.js.map +1 -0
  29. package/dist/adapters/transport-bridge-ws.d.ts +39 -0
  30. package/dist/adapters/transport-bridge-ws.js +49 -0
  31. package/dist/adapters/transport-bridge-ws.js.map +1 -0
  32. package/dist/adapters/vlm-inner-loop.d.ts +88 -0
  33. package/dist/adapters/vlm-inner-loop.js +199 -0
  34. package/dist/adapters/vlm-inner-loop.js.map +1 -0
  35. package/dist/agent-runtime/adapters/base.d.ts +145 -0
  36. package/dist/agent-runtime/adapters/base.js +29 -0
  37. package/dist/agent-runtime/adapters/base.js.map +1 -0
  38. package/dist/agent-runtime/adapters/index.d.ts +17 -0
  39. package/dist/agent-runtime/adapters/index.js +17 -0
  40. package/dist/agent-runtime/adapters/index.js.map +1 -0
  41. package/dist/agent-runtime/adapters/mock.d.ts +44 -0
  42. package/dist/agent-runtime/adapters/mock.js +54 -0
  43. package/dist/agent-runtime/adapters/mock.js.map +1 -0
  44. package/dist/agent-runtime/adapters/openai.d.ts +63 -0
  45. package/dist/agent-runtime/adapters/openai.js +302 -0
  46. package/dist/agent-runtime/adapters/openai.js.map +1 -0
  47. package/dist/agent-runtime/adapters/registry.d.ts +49 -0
  48. package/dist/agent-runtime/adapters/registry.js +129 -0
  49. package/dist/agent-runtime/adapters/registry.js.map +1 -0
  50. package/dist/agent-runtime/adapters/ui-tars.d.ts +13 -0
  51. package/dist/agent-runtime/adapters/ui-tars.js +22 -0
  52. package/dist/agent-runtime/adapters/ui-tars.js.map +1 -0
  53. package/dist/agent-runtime/agent-runner.d.ts +149 -0
  54. package/dist/agent-runtime/agent-runner.js +356 -0
  55. package/dist/agent-runtime/agent-runner.js.map +1 -0
  56. package/dist/agent-runtime/core.d.ts +170 -0
  57. package/dist/agent-runtime/core.js +624 -0
  58. package/dist/agent-runtime/core.js.map +1 -0
  59. package/dist/agent-runtime/index.d.ts +16 -0
  60. package/dist/agent-runtime/index.js +17 -0
  61. package/dist/agent-runtime/index.js.map +1 -0
  62. package/dist/agent-runtime/plan-executor.d.ts +118 -0
  63. package/dist/agent-runtime/plan-executor.js +501 -0
  64. package/dist/agent-runtime/plan-executor.js.map +1 -0
  65. package/dist/agent-runtime/planner/base.d.ts +128 -0
  66. package/dist/agent-runtime/planner/base.js +157 -0
  67. package/dist/agent-runtime/planner/base.js.map +1 -0
  68. package/dist/agent-runtime/planner/llm-planner.d.ts +58 -0
  69. package/dist/agent-runtime/planner/llm-planner.js +112 -0
  70. package/dist/agent-runtime/planner/llm-planner.js.map +1 -0
  71. package/dist/agent-runtime/planner/noop-planner.d.ts +13 -0
  72. package/dist/agent-runtime/planner/noop-planner.js +30 -0
  73. package/dist/agent-runtime/planner/noop-planner.js.map +1 -0
  74. package/dist/agent-runtime/planner/prompts.d.ts +33 -0
  75. package/dist/agent-runtime/planner/prompts.js +165 -0
  76. package/dist/agent-runtime/planner/prompts.js.map +1 -0
  77. package/dist/agent-runtime/reflection.d.ts +81 -0
  78. package/dist/agent-runtime/reflection.js +189 -0
  79. package/dist/agent-runtime/reflection.js.map +1 -0
  80. package/dist/agent-runtime/reflectors/action-reflector.d.ts +97 -0
  81. package/dist/agent-runtime/reflectors/action-reflector.js +233 -0
  82. package/dist/agent-runtime/reflectors/action-reflector.js.map +1 -0
  83. package/dist/agent-runtime/reflectors/policy.d.ts +53 -0
  84. package/dist/agent-runtime/reflectors/policy.js +106 -0
  85. package/dist/agent-runtime/reflectors/policy.js.map +1 -0
  86. package/dist/agent-runtime/reflectors/trajectory-reflector.d.ts +94 -0
  87. package/dist/agent-runtime/reflectors/trajectory-reflector.js +223 -0
  88. package/dist/agent-runtime/reflectors/trajectory-reflector.js.map +1 -0
  89. package/dist/agent-runtime/skills/embedding.d.ts +53 -0
  90. package/dist/agent-runtime/skills/embedding.js +134 -0
  91. package/dist/agent-runtime/skills/embedding.js.map +1 -0
  92. package/dist/agent-runtime/skills/fs-store.d.ts +88 -0
  93. package/dist/agent-runtime/skills/fs-store.js +483 -0
  94. package/dist/agent-runtime/skills/fs-store.js.map +1 -0
  95. package/dist/agent-runtime/skills/index.d.ts +10 -0
  96. package/dist/agent-runtime/skills/index.js +10 -0
  97. package/dist/agent-runtime/skills/index.js.map +1 -0
  98. package/dist/agent-runtime/skills/matcher-evolver.d.ts +88 -0
  99. package/dist/agent-runtime/skills/matcher-evolver.js +110 -0
  100. package/dist/agent-runtime/skills/matcher-evolver.js.map +1 -0
  101. package/dist/agent-runtime/skills/memory-store.d.ts +23 -0
  102. package/dist/agent-runtime/skills/memory-store.js +94 -0
  103. package/dist/agent-runtime/skills/memory-store.js.map +1 -0
  104. package/dist/agent-runtime/skills/normalise.d.ts +40 -0
  105. package/dist/agent-runtime/skills/normalise.js +152 -0
  106. package/dist/agent-runtime/skills/normalise.js.map +1 -0
  107. package/dist/agent-runtime/skills/replay.d.ts +46 -0
  108. package/dist/agent-runtime/skills/replay.js +106 -0
  109. package/dist/agent-runtime/skills/replay.js.map +1 -0
  110. package/dist/agent-runtime/skills/sqlite-store.d.ts +60 -0
  111. package/dist/agent-runtime/skills/sqlite-store.js +234 -0
  112. package/dist/agent-runtime/skills/sqlite-store.js.map +1 -0
  113. package/dist/agent-runtime/skills/types.d.ts +99 -0
  114. package/dist/agent-runtime/skills/types.js +14 -0
  115. package/dist/agent-runtime/skills/types.js.map +1 -0
  116. package/dist/agent.d.ts +110 -0
  117. package/dist/agent.js +162 -0
  118. package/dist/agent.js.map +1 -0
  119. package/dist/api.d.ts +27 -0
  120. package/dist/api.js +48 -0
  121. package/dist/api.js.map +1 -0
  122. package/dist/app/agent-host.d.ts +59 -0
  123. package/dist/app/agent-host.js +263 -0
  124. package/dist/app/agent-host.js.map +1 -0
  125. package/dist/app/device-manager.d.ts +28 -0
  126. package/dist/app/device-manager.js +64 -0
  127. package/dist/app/device-manager.js.map +1 -0
  128. package/dist/app/message-store.d.ts +55 -0
  129. package/dist/app/message-store.js +99 -0
  130. package/dist/app/message-store.js.map +1 -0
  131. package/dist/app/session-manager.d.ts +132 -0
  132. package/dist/app/session-manager.js +350 -0
  133. package/dist/app/session-manager.js.map +1 -0
  134. package/dist/bootstrap.d.ts +94 -0
  135. package/dist/bootstrap.js +459 -0
  136. package/dist/bootstrap.js.map +1 -0
  137. package/dist/chat.d.ts +16 -0
  138. package/dist/chat.js +175 -0
  139. package/dist/chat.js.map +1 -0
  140. package/dist/config/loader.d.ts +77 -0
  141. package/dist/config/loader.js +292 -0
  142. package/dist/config/loader.js.map +1 -0
  143. package/dist/config/schema.d.ts +162 -0
  144. package/dist/config/schema.js +243 -0
  145. package/dist/config/schema.js.map +1 -0
  146. package/dist/core/actions.d.ts +60 -0
  147. package/dist/core/actions.js +120 -0
  148. package/dist/core/actions.js.map +1 -0
  149. package/dist/core/errors.d.ts +8 -0
  150. package/dist/core/errors.js +9 -0
  151. package/dist/core/errors.js.map +1 -0
  152. package/dist/core/screen.d.ts +7 -0
  153. package/dist/core/screen.js +8 -0
  154. package/dist/core/screen.js.map +1 -0
  155. package/dist/core/session.d.ts +42 -0
  156. package/dist/core/session.js +29 -0
  157. package/dist/core/session.js.map +1 -0
  158. package/dist/debug/dump-system-prompt.d.ts +1 -0
  159. package/dist/debug/dump-system-prompt.js +34 -0
  160. package/dist/debug/dump-system-prompt.js.map +1 -0
  161. package/dist/device/android.d.ts +25 -0
  162. package/dist/device/android.js +231 -0
  163. package/dist/device/android.js.map +1 -0
  164. package/dist/device/apps.d.ts +3 -0
  165. package/dist/device/apps.js +77 -0
  166. package/dist/device/apps.js.map +1 -0
  167. package/dist/device/base.d.ts +20 -0
  168. package/dist/device/base.js +2 -0
  169. package/dist/device/base.js.map +1 -0
  170. package/dist/device/ui-xml.d.ts +29 -0
  171. package/dist/device/ui-xml.js +194 -0
  172. package/dist/device/ui-xml.js.map +1 -0
  173. package/dist/fleet/adapters/process/node-process-manager.d.ts +157 -0
  174. package/dist/fleet/adapters/process/node-process-manager.js +664 -0
  175. package/dist/fleet/adapters/process/node-process-manager.js.map +1 -0
  176. package/dist/fleet/adapters/sources/local-adb.d.ts +105 -0
  177. package/dist/fleet/adapters/sources/local-adb.js +353 -0
  178. package/dist/fleet/adapters/sources/local-adb.js.map +1 -0
  179. package/dist/fleet/adapters/sources/remote-adb.d.ts +97 -0
  180. package/dist/fleet/adapters/sources/remote-adb.js +138 -0
  181. package/dist/fleet/adapters/sources/remote-adb.js.map +1 -0
  182. package/dist/fleet/adapters/state/beeos-cli-store.d.ts +72 -0
  183. package/dist/fleet/adapters/state/beeos-cli-store.js +250 -0
  184. package/dist/fleet/adapters/state/beeos-cli-store.js.map +1 -0
  185. package/dist/fleet/adapters/state/port-allocator.d.ts +43 -0
  186. package/dist/fleet/adapters/state/port-allocator.js +173 -0
  187. package/dist/fleet/adapters/state/port-allocator.js.map +1 -0
  188. package/dist/fleet/domain/device.d.ts +138 -0
  189. package/dist/fleet/domain/device.js +49 -0
  190. package/dist/fleet/domain/device.js.map +1 -0
  191. package/dist/fleet/domain/events.d.ts +102 -0
  192. package/dist/fleet/domain/events.js +15 -0
  193. package/dist/fleet/domain/events.js.map +1 -0
  194. package/dist/fleet/domain/fsm.d.ts +122 -0
  195. package/dist/fleet/domain/fsm.js +475 -0
  196. package/dist/fleet/domain/fsm.js.map +1 -0
  197. package/dist/fleet/http/status-client.d.ts +31 -0
  198. package/dist/fleet/http/status-client.js +115 -0
  199. package/dist/fleet/http/status-client.js.map +1 -0
  200. package/dist/fleet/http/status-server.d.ts +64 -0
  201. package/dist/fleet/http/status-server.js +200 -0
  202. package/dist/fleet/http/status-server.js.map +1 -0
  203. package/dist/fleet/index.d.ts +27 -0
  204. package/dist/fleet/index.js +17 -0
  205. package/dist/fleet/index.js.map +1 -0
  206. package/dist/fleet/installer/index.d.ts +12 -0
  207. package/dist/fleet/installer/index.js +13 -0
  208. package/dist/fleet/installer/index.js.map +1 -0
  209. package/dist/fleet/installer/launchd-mac.d.ts +73 -0
  210. package/dist/fleet/installer/launchd-mac.js +291 -0
  211. package/dist/fleet/installer/launchd-mac.js.map +1 -0
  212. package/dist/fleet/installer/service-spec.d.ts +70 -0
  213. package/dist/fleet/installer/service-spec.js +43 -0
  214. package/dist/fleet/installer/service-spec.js.map +1 -0
  215. package/dist/fleet/installer/spawn-env.d.ts +45 -0
  216. package/dist/fleet/installer/spawn-env.js +224 -0
  217. package/dist/fleet/installer/spawn-env.js.map +1 -0
  218. package/dist/fleet/ports/clock.d.ts +19 -0
  219. package/dist/fleet/ports/clock.js +26 -0
  220. package/dist/fleet/ports/clock.js.map +1 -0
  221. package/dist/fleet/ports/device-source.d.ts +28 -0
  222. package/dist/fleet/ports/device-source.js +18 -0
  223. package/dist/fleet/ports/device-source.js.map +1 -0
  224. package/dist/fleet/ports/process-manager.d.ts +110 -0
  225. package/dist/fleet/ports/process-manager.js +27 -0
  226. package/dist/fleet/ports/process-manager.js.map +1 -0
  227. package/dist/fleet/ports/state-registry.d.ts +49 -0
  228. package/dist/fleet/ports/state-registry.js +12 -0
  229. package/dist/fleet/ports/state-registry.js.map +1 -0
  230. package/dist/fleet/supervisor.d.ts +107 -0
  231. package/dist/fleet/supervisor.js +508 -0
  232. package/dist/fleet/supervisor.js.map +1 -0
  233. package/dist/grounding/grounder.d.ts +46 -0
  234. package/dist/grounding/grounder.js +82 -0
  235. package/dist/grounding/grounder.js.map +1 -0
  236. package/dist/inbound/acp/handlers/device.d.ts +43 -0
  237. package/dist/inbound/acp/handlers/device.js +153 -0
  238. package/dist/inbound/acp/handlers/device.js.map +1 -0
  239. package/dist/inbound/acp/handlers/initialize.d.ts +71 -0
  240. package/dist/inbound/acp/handlers/initialize.js +53 -0
  241. package/dist/inbound/acp/handlers/initialize.js.map +1 -0
  242. package/dist/inbound/acp/handlers/models.d.ts +16 -0
  243. package/dist/inbound/acp/handlers/models.js +23 -0
  244. package/dist/inbound/acp/handlers/models.js.map +1 -0
  245. package/dist/inbound/acp/handlers/session.d.ts +51 -0
  246. package/dist/inbound/acp/handlers/session.js +61 -0
  247. package/dist/inbound/acp/handlers/session.js.map +1 -0
  248. package/dist/inbound/acp/handlers/skills.d.ts +8 -0
  249. package/dist/inbound/acp/handlers/skills.js +9 -0
  250. package/dist/inbound/acp/handlers/skills.js.map +1 -0
  251. package/dist/inbound/acp/notifier.d.ts +35 -0
  252. package/dist/inbound/acp/notifier.js +45 -0
  253. package/dist/inbound/acp/notifier.js.map +1 -0
  254. package/dist/inbound/acp/router.d.ts +67 -0
  255. package/dist/inbound/acp/router.js +179 -0
  256. package/dist/inbound/acp/router.js.map +1 -0
  257. package/dist/inbound/cli/fleet-command.d.ts +34 -0
  258. package/dist/inbound/cli/fleet-command.js +792 -0
  259. package/dist/inbound/cli/fleet-command.js.map +1 -0
  260. package/dist/inbound/cli/main.d.ts +38 -0
  261. package/dist/inbound/cli/main.js +364 -0
  262. package/dist/inbound/cli/main.js.map +1 -0
  263. package/dist/inbound/cli/run-command.d.ts +101 -0
  264. package/dist/inbound/cli/run-command.js +405 -0
  265. package/dist/inbound/cli/run-command.js.map +1 -0
  266. package/dist/inbound/cli/skills-command.d.ts +39 -0
  267. package/dist/inbound/cli/skills-command.js +333 -0
  268. package/dist/inbound/cli/skills-command.js.map +1 -0
  269. package/dist/inbound/http/server.d.ts +7 -0
  270. package/dist/inbound/http/server.js +8 -0
  271. package/dist/inbound/http/server.js.map +1 -0
  272. package/dist/index.d.ts +66 -0
  273. package/dist/index.js +48 -0
  274. package/dist/index.js.map +1 -0
  275. package/dist/logger/index.d.ts +37 -0
  276. package/dist/logger/index.js +84 -0
  277. package/dist/logger/index.js.map +1 -0
  278. package/dist/mcp-client/autospawn.d.ts +67 -0
  279. package/dist/mcp-client/autospawn.js +173 -0
  280. package/dist/mcp-client/autospawn.js.map +1 -0
  281. package/dist/mcp-client/client.d.ts +78 -0
  282. package/dist/mcp-client/client.js +168 -0
  283. package/dist/mcp-client/client.js.map +1 -0
  284. package/dist/mcp-client/index.d.ts +7 -0
  285. package/dist/mcp-client/index.js +4 -0
  286. package/dist/mcp-client/index.js.map +1 -0
  287. package/dist/mcp-client/inproc.d.ts +47 -0
  288. package/dist/mcp-client/inproc.js +229 -0
  289. package/dist/mcp-client/inproc.js.map +1 -0
  290. package/dist/mcp-client/runtime.d.ts +34 -0
  291. package/dist/mcp-client/runtime.js +15 -0
  292. package/dist/mcp-client/runtime.js.map +1 -0
  293. package/dist/model/adapters/autoglm.d.ts +31 -0
  294. package/dist/model/adapters/autoglm.js +409 -0
  295. package/dist/model/adapters/autoglm.js.map +1 -0
  296. package/dist/model/adapters/base.d.ts +13 -0
  297. package/dist/model/adapters/base.js +27 -0
  298. package/dist/model/adapters/base.js.map +1 -0
  299. package/dist/model/adapters/guiowl.d.ts +1 -0
  300. package/dist/model/adapters/guiowl.js +253 -0
  301. package/dist/model/adapters/guiowl.js.map +1 -0
  302. package/dist/model/adapters/index.d.ts +6 -0
  303. package/dist/model/adapters/index.js +8 -0
  304. package/dist/model/adapters/index.js.map +1 -0
  305. package/dist/model/adapters/maiui.d.ts +1 -0
  306. package/dist/model/adapters/maiui.js +117 -0
  307. package/dist/model/adapters/maiui.js.map +1 -0
  308. package/dist/model/adapters/qwenvl.d.ts +1 -0
  309. package/dist/model/adapters/qwenvl.js +108 -0
  310. package/dist/model/adapters/qwenvl.js.map +1 -0
  311. package/dist/model/adapters/showui.d.ts +1 -0
  312. package/dist/model/adapters/showui.js +132 -0
  313. package/dist/model/adapters/showui.js.map +1 -0
  314. package/dist/model/adapters/tool-call.d.ts +6 -0
  315. package/dist/model/adapters/tool-call.js +102 -0
  316. package/dist/model/adapters/tool-call.js.map +1 -0
  317. package/dist/model/adapters/uitars.d.ts +1 -0
  318. package/dist/model/adapters/uitars.js +180 -0
  319. package/dist/model/adapters/uitars.js.map +1 -0
  320. package/dist/model/base.d.ts +32 -0
  321. package/dist/model/base.js +2 -0
  322. package/dist/model/base.js.map +1 -0
  323. package/dist/model/client.d.ts +26 -0
  324. package/dist/model/client.js +300 -0
  325. package/dist/model/client.js.map +1 -0
  326. package/dist/model/image/compress.d.ts +53 -0
  327. package/dist/model/image/compress.js +89 -0
  328. package/dist/model/image/compress.js.map +1 -0
  329. package/dist/model/image/transport.d.ts +134 -0
  330. package/dist/model/image/transport.js +154 -0
  331. package/dist/model/image/transport.js.map +1 -0
  332. package/dist/orchestrator-system-prompt.d.ts +6 -0
  333. package/dist/orchestrator-system-prompt.js +81 -0
  334. package/dist/orchestrator-system-prompt.js.map +1 -0
  335. package/dist/pi-context.d.ts +82 -0
  336. package/dist/pi-context.js +62 -0
  337. package/dist/pi-context.js.map +1 -0
  338. package/dist/pi-local-skills.d.ts +17 -0
  339. package/dist/pi-local-skills.js +24 -0
  340. package/dist/pi-local-skills.js.map +1 -0
  341. package/dist/plugins/acp/index.d.ts +46 -0
  342. package/dist/plugins/acp/index.js +111 -0
  343. package/dist/plugins/acp/index.js.map +1 -0
  344. package/dist/plugins/agent-sync/index.d.ts +40 -0
  345. package/dist/plugins/agent-sync/index.js +98 -0
  346. package/dist/plugins/agent-sync/index.js.map +1 -0
  347. package/dist/plugins/http-debug/index.d.ts +30 -0
  348. package/dist/plugins/http-debug/index.js +64 -0
  349. package/dist/plugins/http-debug/index.js.map +1 -0
  350. package/dist/plugins/http-debug/server.d.ts +92 -0
  351. package/dist/plugins/http-debug/server.js +464 -0
  352. package/dist/plugins/http-debug/server.js.map +1 -0
  353. package/dist/ports/agent-core.d.ts +158 -0
  354. package/dist/ports/agent-core.js +2 -0
  355. package/dist/ports/agent-core.js.map +1 -0
  356. package/dist/ports/agent-host.d.ts +125 -0
  357. package/dist/ports/agent-host.js +23 -0
  358. package/dist/ports/agent-host.js.map +1 -0
  359. package/dist/ports/device.d.ts +53 -0
  360. package/dist/ports/device.js +13 -0
  361. package/dist/ports/device.js.map +1 -0
  362. package/dist/ports/identity.d.ts +22 -0
  363. package/dist/ports/identity.js +9 -0
  364. package/dist/ports/identity.js.map +1 -0
  365. package/dist/ports/plugin.d.ts +62 -0
  366. package/dist/ports/plugin.js +35 -0
  367. package/dist/ports/plugin.js.map +1 -0
  368. package/dist/ports/transport.d.ts +32 -0
  369. package/dist/ports/transport.js +12 -0
  370. package/dist/ports/transport.js.map +1 -0
  371. package/dist/ports/vlm.d.ts +59 -0
  372. package/dist/ports/vlm.js +14 -0
  373. package/dist/ports/vlm.js.map +1 -0
  374. package/dist/test-lan-autoglm.d.ts +7 -0
  375. package/dist/test-lan-autoglm.js +46 -0
  376. package/dist/test-lan-autoglm.js.map +1 -0
  377. package/dist/test-mem-breakdown.d.ts +1 -0
  378. package/dist/test-mem-breakdown.js +103 -0
  379. package/dist/test-mem-breakdown.js.map +1 -0
  380. package/dist/test-mem.d.ts +1 -0
  381. package/dist/test-mem.js +60 -0
  382. package/dist/test-mem.js.map +1 -0
  383. package/dist/test-mobile-use.d.ts +1 -0
  384. package/dist/test-mobile-use.js +18 -0
  385. package/dist/test-mobile-use.js.map +1 -0
  386. package/dist/test-screenshot-loop.d.ts +1 -0
  387. package/dist/test-screenshot-loop.js +43 -0
  388. package/dist/test-screenshot-loop.js.map +1 -0
  389. package/dist/test-screenshot.d.ts +1 -0
  390. package/dist/test-screenshot.js +10 -0
  391. package/dist/test-screenshot.js.map +1 -0
  392. package/dist/test-ui-xml-dump.d.ts +15 -0
  393. package/dist/test-ui-xml-dump.js +49 -0
  394. package/dist/test-ui-xml-dump.js.map +1 -0
  395. package/dist/types.d.ts +69 -0
  396. package/dist/types.js +23 -0
  397. package/dist/types.js.map +1 -0
  398. package/package.json +94 -0
@@ -0,0 +1,664 @@
1
+ /**
2
+ * Adapter — `IProcessManager` implementation backed by `child_process.spawn`.
3
+ *
4
+ * Spawns and supervises up to three long-running siblings per bound device:
5
+ *
6
+ * - **mcp** `device-mcp-server --backend <kind> --adb-serial <serial>
7
+ * --host 127.0.0.1 --port <mcpPort>`
8
+ * - **daemon** `device-agent --key <keyFile> --agent-gateway-url <url>
9
+ * --mcp-url http://127.0.0.1:<mcpPort> --adb <serial>
10
+ * [--http --http-port <httpPort>]`
11
+ * - **scrcpy** `scrcpy-bridge` (no args; configured via env mirroring
12
+ * `web/packages/core/src/runtime/scrcpy-bridge.ts` `buildEnv`).
13
+ * Optional — only spawned when the binding's `videoMode === "scrcpy"`.
14
+ *
15
+ * Lifecycle responsibilities:
16
+ *
17
+ * - `spawnMcp` waits for `GET /healthz` to return 200 (configurable timeout)
18
+ * before emitting `mcp_started`. If readiness times out the spawn is
19
+ * killed and an `mcp_exited` event is reported (so the FSM treats the
20
+ * attempt as a crash and either retries or backs off).
21
+ * - `spawnDaemon` emits `daemon_started` as soon as the child has a PID
22
+ * (the daemon's own readiness is observable through ACP traffic which is
23
+ * out of fleet scope; the daemon process itself dying is what we react to
24
+ * here). Optional `daemonHttpPort` is probed similarly when set.
25
+ * - `spawnScrcpy` is best-effort — a missing binary yields a synthetic
26
+ * `scrcpy_exited` event (with `reason`) instead of a thrown error.
27
+ * scrcpy-bridge has no `/healthz`, so readiness is degraded to
28
+ * "process still alive `scrcpyStartupGraceMs` after spawn"; before that
29
+ * window elapses we don't emit `scrcpy_started`. If the child exits
30
+ * within the grace, we emit `scrcpy_exited` instead.
31
+ * - `kill*` sends SIGTERM, then SIGKILL after `shutdownGraceMs`. When the
32
+ * supervisor initiates the kill we mark the resulting exit as `expected`
33
+ * so the pure FSM (`fsm.ts`) doesn't penalise restartCount.
34
+ * - When a child dies on its own (`expected=false`), we emit the matching
35
+ * `*_exited` event and let the supervisor (driving the FSM) decide whether
36
+ * to respawn. We never auto-restart from inside this adapter — the FSM
37
+ * owns the policy.
38
+ *
39
+ * Binary discovery:
40
+ * - mcp: `BEEOS_DEVICE_MCP_BIN` → `device-mcp-server` on PATH (override via opts.mcpBin).
41
+ * - daemon: `BEEOS_DEVICE_AGENT_BIN` → `device-agent` on PATH (override via opts.daemonBin).
42
+ * - scrcpy: `BEEOS_SCRCPY_BRIDGE_BIN` env → `~/.beeos/bin/scrcpy-bridge[.exe]` (managed install).
43
+ * Override via `opts.scrcpyBin` (absolute path) or `opts.findScrcpyBinFn` (test hook).
44
+ *
45
+ * The implementation deliberately exposes a hookable `spawnFn` /
46
+ * `httpProbeFn` / `findScrcpyBinFn` so unit tests can drive the manager with
47
+ * fake children and synthetic /healthz responses without touching the OS.
48
+ */
49
+ import { spawn as nodeSpawn } from "node:child_process";
50
+ import * as fs from "node:fs";
51
+ import * as http from "node:http";
52
+ import * as os from "node:os";
53
+ import * as path from "node:path";
54
+ const noopLogger = {
55
+ debug: () => { },
56
+ info: () => { },
57
+ warn: () => { },
58
+ error: () => { },
59
+ };
60
+ // ── NodeProcessManager ──────────────────────────────────────────────────────
61
+ export class NodeProcessManager {
62
+ mcpBin;
63
+ daemonBin;
64
+ scrcpyBinOverride;
65
+ mcpBackend;
66
+ mcpHost;
67
+ agentGatewayUrl;
68
+ bridgeUrl;
69
+ region;
70
+ mcpHealthTimeoutMs;
71
+ scrcpyStartupGraceMs;
72
+ shutdownGraceMs;
73
+ spawnFn;
74
+ httpProbeFn;
75
+ findScrcpyBinFn;
76
+ logger;
77
+ extraEnv;
78
+ slots = new Map();
79
+ listeners = new Set();
80
+ started = false;
81
+ constructor(opts = {}) {
82
+ this.mcpBin =
83
+ opts.mcpBin ?? process.env.BEEOS_DEVICE_MCP_BIN ?? "device-mcp-server";
84
+ this.daemonBin =
85
+ opts.daemonBin ?? process.env.BEEOS_DEVICE_AGENT_BIN ?? "device-agent";
86
+ this.scrcpyBinOverride = opts.scrcpyBin;
87
+ this.mcpBackend = opts.mcpBackend ?? process.env.BEEOS_MCP_BACKEND ?? "android";
88
+ this.mcpHost = opts.mcpHost ?? "127.0.0.1";
89
+ this.agentGatewayUrl = opts.agentGatewayUrl ?? process.env.AGENT_GATEWAY_URL;
90
+ this.bridgeUrl = opts.bridgeUrl ?? process.env.BRIDGE_URL;
91
+ this.region = opts.region ?? process.env.BEEOS_REGION;
92
+ this.mcpHealthTimeoutMs = opts.mcpHealthTimeoutMs ?? 10_000;
93
+ this.scrcpyStartupGraceMs = opts.scrcpyStartupGraceMs ?? 5_000;
94
+ this.shutdownGraceMs = opts.shutdownGraceMs ?? 5_000;
95
+ this.spawnFn = opts.spawnFn ?? defaultSpawnFn;
96
+ this.httpProbeFn = opts.httpProbeFn ?? defaultHttpProbeFn;
97
+ this.findScrcpyBinFn = opts.findScrcpyBinFn ?? (() => defaultFindScrcpyBin(this.scrcpyBinOverride));
98
+ this.logger = opts.logger ?? noopLogger;
99
+ this.extraEnv = opts.extraEnv ?? {};
100
+ }
101
+ async start() {
102
+ this.started = true;
103
+ }
104
+ async stop() {
105
+ this.started = false;
106
+ const serials = Array.from(this.slots.keys());
107
+ await Promise.all(serials.flatMap((s) => [
108
+ this.killMcp(s, { expected: true }),
109
+ this.killDaemon(s, { expected: true }),
110
+ this.killScrcpy(s, { expected: true }),
111
+ ]));
112
+ }
113
+ on(listener) {
114
+ this.listeners.add(listener);
115
+ return () => this.listeners.delete(listener);
116
+ }
117
+ isAlive(serial, which) {
118
+ const slot = this.slots.get(serial);
119
+ if (!slot)
120
+ return false;
121
+ return Boolean(this.slotFor(slot, which));
122
+ }
123
+ pid(serial, which) {
124
+ const slot = this.slots.get(serial);
125
+ if (!slot)
126
+ return null;
127
+ const childSlot = this.slotFor(slot, which);
128
+ return childSlot?.child.pid ?? null;
129
+ }
130
+ slotFor(slot, which) {
131
+ if (which === "mcp")
132
+ return slot.mcp;
133
+ if (which === "daemon")
134
+ return slot.daemon;
135
+ return slot.scrcpy;
136
+ }
137
+ setSlot(slot, which, value) {
138
+ if (which === "mcp")
139
+ slot.mcp = value;
140
+ else if (which === "daemon")
141
+ slot.daemon = value;
142
+ else
143
+ slot.scrcpy = value;
144
+ }
145
+ // ── Spawn paths ──────────────────────────────────────────────────────────
146
+ async spawnMcp(opts) {
147
+ const slot = this.ensureSlot(opts.serial);
148
+ if (slot.mcp) {
149
+ this.logger.warn("spawnMcp called while mcp already alive — ignoring", {
150
+ serial: opts.serial,
151
+ pid: slot.mcp.child.pid,
152
+ });
153
+ return;
154
+ }
155
+ // Per-device backend takes precedence over the constructor-time
156
+ // default. `devices.json#backend` flows here via `SpawnOptions`,
157
+ // so once self-attach lands the same code path serves ADB,
158
+ // macOS / Linux / Windows hosts.
159
+ const backend = opts.backend ?? this.mcpBackend;
160
+ const args = ["--backend", backend];
161
+ // `--adb-serial` is only meaningful for the ADB backend. Other
162
+ // backends rely on the host process (one device-mcp-server per
163
+ // host), so passing the serial there would be confusing.
164
+ if (isAdbBackend(backend)) {
165
+ args.push("--adb-serial", opts.serial);
166
+ }
167
+ args.push("--host", this.mcpHost, "--port", String(opts.mcpPort));
168
+ const env = {
169
+ ...process.env,
170
+ ...this.extraEnv,
171
+ DEVICEAGENT_BACKEND: backend,
172
+ ANDROID_SERIAL: opts.serial,
173
+ MCP_HOST: this.mcpHost,
174
+ MCP_PORT: String(opts.mcpPort),
175
+ };
176
+ let child;
177
+ try {
178
+ child = this.spawnFn(this.mcpBin, args, env);
179
+ }
180
+ catch (e) {
181
+ this.logger.error("failed to spawn mcp", {
182
+ serial: opts.serial,
183
+ error: String(e),
184
+ });
185
+ this.emit({
186
+ kind: "mcp_exited",
187
+ serial: opts.serial,
188
+ code: -1,
189
+ signal: null,
190
+ expected: false,
191
+ });
192
+ return;
193
+ }
194
+ const childSlot = {
195
+ child,
196
+ expectingKill: false,
197
+ spawnedAt: Date.now(),
198
+ bin: this.mcpBin,
199
+ args,
200
+ };
201
+ slot.mcp = childSlot;
202
+ this.logger.info("spawned device-mcp-server", {
203
+ serial: opts.serial,
204
+ pid: child.pid ?? null,
205
+ port: opts.mcpPort,
206
+ });
207
+ this.attachExitListener(opts.serial, "mcp", childSlot);
208
+ // Readiness probe (best-effort; in tests httpProbeFn returns true instantly).
209
+ const url = `http://${this.mcpHost}:${opts.mcpPort}/healthz`;
210
+ const ok = await this.httpProbeFn(url, this.mcpHealthTimeoutMs);
211
+ if (!ok) {
212
+ this.logger.warn("mcp /healthz did not return 200 within grace", {
213
+ serial: opts.serial,
214
+ url,
215
+ });
216
+ // Treat the readiness failure as a crash. Mark the upcoming exit as
217
+ // expected (we caused the kill) so the FSM won't double-count, but
218
+ // emit the synthetic exit AFTER the actual kill bookkeeping is done.
219
+ childSlot.expectingKill = true;
220
+ try {
221
+ child.kill("SIGTERM");
222
+ }
223
+ catch {
224
+ /* ignore */
225
+ }
226
+ this.emit({
227
+ kind: "mcp_exited",
228
+ serial: opts.serial,
229
+ code: null,
230
+ signal: "SIGTERM",
231
+ expected: false,
232
+ });
233
+ return;
234
+ }
235
+ this.emit({
236
+ kind: "mcp_started",
237
+ serial: opts.serial,
238
+ pid: child.pid ?? 0,
239
+ port: opts.mcpPort,
240
+ });
241
+ }
242
+ async spawnDaemon(opts) {
243
+ const slot = this.ensureSlot(opts.serial);
244
+ if (slot.daemon) {
245
+ this.logger.warn("spawnDaemon called while daemon already alive — ignoring", {
246
+ serial: opts.serial,
247
+ pid: slot.daemon.child.pid,
248
+ });
249
+ return;
250
+ }
251
+ const mcpUrl = `http://${this.mcpHost}:${opts.mcpPort}`;
252
+ const args = [
253
+ "--key",
254
+ opts.keyFile,
255
+ "--mcp-url",
256
+ mcpUrl,
257
+ "--adb",
258
+ opts.serial,
259
+ ];
260
+ const agw = opts.agentGatewayUrl ?? this.agentGatewayUrl;
261
+ if (agw) {
262
+ args.push("--agent-gateway-url", agw);
263
+ }
264
+ if (this.bridgeUrl) {
265
+ args.push("--bridge", this.bridgeUrl);
266
+ }
267
+ if (this.region) {
268
+ args.push("--region", this.region);
269
+ }
270
+ if (typeof opts.daemonHttpPort === "number" && opts.daemonHttpPort > 0) {
271
+ args.push("--http", "--http-port", String(opts.daemonHttpPort));
272
+ }
273
+ // Per-instance VLM / orchestrator config that the CLI's
274
+ // `persistAgentConfigBestEffort` writes during `beeos device attach`.
275
+ // Injected only when the file actually exists so daemons started for
276
+ // edge / staging deploys (where the CLI hasn't run) still come up
277
+ // with their built-in defaults.
278
+ if (opts.instanceId) {
279
+ const cfg = path.join(beeoHome(), `${opts.instanceId}.config.json`);
280
+ if (await fileExists(cfg)) {
281
+ args.push("--vlm-config-file", cfg);
282
+ }
283
+ }
284
+ const env = {
285
+ ...process.env,
286
+ ...this.extraEnv,
287
+ MCP_URL: mcpUrl,
288
+ ANDROID_SERIAL: opts.serial,
289
+ };
290
+ let child;
291
+ try {
292
+ child = this.spawnFn(this.daemonBin, args, env);
293
+ }
294
+ catch (e) {
295
+ this.logger.error("failed to spawn daemon", {
296
+ serial: opts.serial,
297
+ error: String(e),
298
+ });
299
+ this.emit({
300
+ kind: "daemon_exited",
301
+ serial: opts.serial,
302
+ code: -1,
303
+ signal: null,
304
+ expected: false,
305
+ });
306
+ return;
307
+ }
308
+ const childSlot = {
309
+ child,
310
+ expectingKill: false,
311
+ spawnedAt: Date.now(),
312
+ bin: this.daemonBin,
313
+ args,
314
+ };
315
+ slot.daemon = childSlot;
316
+ this.logger.info("spawned device-agent daemon", {
317
+ serial: opts.serial,
318
+ pid: child.pid ?? null,
319
+ mcpUrl,
320
+ });
321
+ this.attachExitListener(opts.serial, "daemon", childSlot);
322
+ this.emit({
323
+ kind: "daemon_started",
324
+ serial: opts.serial,
325
+ pid: child.pid ?? 0,
326
+ });
327
+ }
328
+ async spawnScrcpy(opts) {
329
+ const slot = this.ensureSlot(opts.serial);
330
+ if (slot.scrcpy) {
331
+ this.logger.warn("spawnScrcpy called while scrcpy already alive — ignoring", {
332
+ serial: opts.serial,
333
+ pid: slot.scrcpy.child.pid,
334
+ });
335
+ return;
336
+ }
337
+ const bin = await this.findScrcpyBinFn();
338
+ if (!bin) {
339
+ // Best-effort: missing binary must NOT block the device. Emit a
340
+ // synthetic exit (with a `reason`) so the supervisor records the
341
+ // degraded video state on the snapshot. mcp + daemon still come up.
342
+ this.logger.warn("scrcpy-bridge binary not found; video disabled", {
343
+ serial: opts.serial,
344
+ });
345
+ this.emit({
346
+ kind: "scrcpy_exited",
347
+ serial: opts.serial,
348
+ code: null,
349
+ signal: null,
350
+ expected: false,
351
+ reason: "binary_not_found",
352
+ });
353
+ return;
354
+ }
355
+ // Mirror `web/packages/core/src/runtime/scrcpy-bridge.ts` `buildEnv`
356
+ // (kept inline here to avoid a `@beeos/core` dependency in the
357
+ // device-agent package).
358
+ const env = {
359
+ ...process.env,
360
+ ...this.extraEnv,
361
+ DEVICE_ID: `device-${opts.instanceId}`,
362
+ ADB_SERIAL: opts.serial,
363
+ AGENT_GATEWAY_URL: opts.agentGatewayUrl,
364
+ BRIDGE_PRIVATE_KEY_FILE: opts.bridgePrivateKeyFile,
365
+ BRIDGE_PUBLIC_KEY_FILE: opts.bridgePublicKeyFile,
366
+ LOG_FORMAT: "json",
367
+ ...(opts.videoBitrateKbps != null
368
+ ? { VIDEO_BITRATE_KBPS: String(opts.videoBitrateKbps) }
369
+ : {}),
370
+ ...(opts.maxFps != null ? { MAX_FPS: String(opts.maxFps) } : {}),
371
+ ...(opts.iceUrls?.length ? { ICE_URLS: opts.iceUrls.join(",") } : {}),
372
+ ...(opts.turnUrls?.length ? { TURN_URLS: opts.turnUrls.join(",") } : {}),
373
+ ...(opts.turnUsername ? { TURN_USERNAME: opts.turnUsername } : {}),
374
+ ...(opts.turnCredential ? { TURN_CREDENTIAL: opts.turnCredential } : {}),
375
+ ...(opts.extraEnv ?? {}),
376
+ };
377
+ let child;
378
+ try {
379
+ child = this.spawnFn(bin, [], env);
380
+ }
381
+ catch (e) {
382
+ this.logger.error("failed to spawn scrcpy-bridge", {
383
+ serial: opts.serial,
384
+ error: String(e),
385
+ });
386
+ this.emit({
387
+ kind: "scrcpy_exited",
388
+ serial: opts.serial,
389
+ code: -1,
390
+ signal: null,
391
+ expected: false,
392
+ reason: "spawn_failed",
393
+ });
394
+ return;
395
+ }
396
+ const childSlot = {
397
+ child,
398
+ expectingKill: false,
399
+ spawnedAt: Date.now(),
400
+ bin,
401
+ args: [],
402
+ startedEmitted: false,
403
+ };
404
+ slot.scrcpy = childSlot;
405
+ this.logger.info("spawned scrcpy-bridge", {
406
+ serial: opts.serial,
407
+ pid: child.pid ?? null,
408
+ deviceId: env.DEVICE_ID,
409
+ });
410
+ this.attachExitListener(opts.serial, "scrcpy", childSlot);
411
+ // scrcpy-bridge has no /healthz endpoint (its readiness is the WebRTC
412
+ // signalling round-trip, which is per-session and out of fleet scope).
413
+ // We treat "still alive after `scrcpyStartupGraceMs`" as healthy. If
414
+ // the child exits earlier the exit listener emits `scrcpy_exited`
415
+ // BEFORE this timer fires and `startedEmitted` stays false.
416
+ const timer = setTimeout(() => {
417
+ if (childSlot.startedEmitted)
418
+ return;
419
+ // Re-check the slot is still ours (may have been replaced by a
420
+ // restart loop, in which case the new spawn owns the timer).
421
+ const current = this.slots.get(opts.serial)?.scrcpy;
422
+ if (current !== childSlot)
423
+ return;
424
+ childSlot.startedEmitted = true;
425
+ this.emit({
426
+ kind: "scrcpy_started",
427
+ serial: opts.serial,
428
+ pid: child.pid ?? 0,
429
+ });
430
+ }, this.scrcpyStartupGraceMs);
431
+ if (typeof timer === "object" && timer && "unref" in timer) {
432
+ try {
433
+ timer.unref();
434
+ }
435
+ catch {
436
+ /* ignore */
437
+ }
438
+ }
439
+ childSlot.startupTimer = timer;
440
+ }
441
+ // ── Kill paths ───────────────────────────────────────────────────────────
442
+ async killMcp(serial, opts = {}) {
443
+ await this.killChild(serial, "mcp", opts.expected ?? true);
444
+ }
445
+ async killDaemon(serial, opts = {}) {
446
+ await this.killChild(serial, "daemon", opts.expected ?? true);
447
+ }
448
+ async killScrcpy(serial, opts = {}) {
449
+ await this.killChild(serial, "scrcpy", opts.expected ?? true);
450
+ }
451
+ // ── Internals ────────────────────────────────────────────────────────────
452
+ ensureSlot(serial) {
453
+ let slot = this.slots.get(serial);
454
+ if (!slot) {
455
+ slot = { serial };
456
+ this.slots.set(serial, slot);
457
+ }
458
+ return slot;
459
+ }
460
+ attachExitListener(serial, which, childSlot) {
461
+ childSlot.child.once("exit", (code, signal) => {
462
+ const slot = this.slots.get(serial);
463
+ if (!slot)
464
+ return;
465
+ const previous = this.slotFor(slot, which);
466
+ if (previous !== childSlot) {
467
+ // Some other slot already replaced this one (rare race) — ignore.
468
+ return;
469
+ }
470
+ const expected = childSlot.expectingKill;
471
+ this.setSlot(slot, which, undefined);
472
+ // scrcpy startup-grace timer must be cleared regardless of how the
473
+ // child died — otherwise a delayed `scrcpy_started` could fire
474
+ // after `scrcpy_exited`, confusing the supervisor's snapshot.
475
+ if (childSlot.startupTimer) {
476
+ clearTimeout(childSlot.startupTimer);
477
+ childSlot.startupTimer = undefined;
478
+ }
479
+ this.logger.warn("child exited", {
480
+ serial,
481
+ which,
482
+ code,
483
+ signal,
484
+ expected,
485
+ });
486
+ if (which === "mcp") {
487
+ this.emit({ kind: "mcp_exited", serial, code, signal, expected });
488
+ }
489
+ else if (which === "daemon") {
490
+ this.emit({ kind: "daemon_exited", serial, code, signal, expected });
491
+ }
492
+ else {
493
+ this.emit({
494
+ kind: "scrcpy_exited",
495
+ serial,
496
+ code,
497
+ signal,
498
+ expected,
499
+ // If the child died inside the startup grace window we tag it
500
+ // for snapshot consumers so they can render a degraded label
501
+ // (e.g. "scrcpy crashed during boot") without parsing logs.
502
+ reason: childSlot.startedEmitted === false ? "startup_failed" : undefined,
503
+ });
504
+ }
505
+ });
506
+ childSlot.child.once("error", (err) => {
507
+ this.logger.error("child error", { serial, which, error: String(err) });
508
+ });
509
+ }
510
+ async killChild(serial, which, expected) {
511
+ const slot = this.slots.get(serial);
512
+ if (!slot)
513
+ return;
514
+ const childSlot = this.slotFor(slot, which);
515
+ if (!childSlot)
516
+ return;
517
+ childSlot.expectingKill = expected;
518
+ try {
519
+ childSlot.child.kill("SIGTERM");
520
+ }
521
+ catch (e) {
522
+ this.logger.warn("SIGTERM failed", { serial, which, error: String(e) });
523
+ }
524
+ // Wait up to shutdownGraceMs for `exit`. The exit listener is what
525
+ // clears the slot; we just observe.
526
+ const start = Date.now();
527
+ while (this.slotFor(slot, which) && Date.now() - start < this.shutdownGraceMs) {
528
+ await sleep(50);
529
+ }
530
+ if (this.slotFor(slot, which)) {
531
+ this.logger.warn("SIGTERM grace expired — sending SIGKILL", {
532
+ serial,
533
+ which,
534
+ });
535
+ try {
536
+ childSlot.child.kill("SIGKILL");
537
+ }
538
+ catch (e) {
539
+ this.logger.warn("SIGKILL failed", { serial, which, error: String(e) });
540
+ }
541
+ // wait briefly for SIGKILL exit
542
+ const killStart = Date.now();
543
+ while (this.slotFor(slot, which) && Date.now() - killStart < 2_000) {
544
+ await sleep(50);
545
+ }
546
+ }
547
+ }
548
+ emit(event) {
549
+ for (const l of this.listeners) {
550
+ try {
551
+ l(event);
552
+ }
553
+ catch (e) {
554
+ this.logger.warn("process event listener threw", { error: String(e) });
555
+ }
556
+ }
557
+ }
558
+ }
559
+ // ── Defaults ────────────────────────────────────────────────────────────────
560
+ const defaultSpawnFn = (bin, args, env) => {
561
+ const child = nodeSpawn(bin, [...args], {
562
+ env,
563
+ stdio: ["ignore", "pipe", "pipe"],
564
+ detached: false,
565
+ });
566
+ // Pipe child output through fleet's logger transparently — the supervisor
567
+ // doesn't need parsed lines, just visibility.
568
+ child.stdout?.on("data", (chunk) => {
569
+ process.stdout.write(`[${bin}] ${chunk.toString()}`);
570
+ });
571
+ child.stderr?.on("data", (chunk) => {
572
+ process.stderr.write(`[${bin} stderr] ${chunk.toString()}`);
573
+ });
574
+ return child;
575
+ };
576
+ const defaultHttpProbeFn = async (url, timeoutMs) => {
577
+ const deadline = Date.now() + timeoutMs;
578
+ while (Date.now() < deadline) {
579
+ const ok = await probeOnce(url, 1_000);
580
+ if (ok)
581
+ return true;
582
+ await sleep(250);
583
+ }
584
+ return false;
585
+ };
586
+ function probeOnce(url, timeoutMs) {
587
+ return new Promise((resolve) => {
588
+ const req = http.get(url, (res) => {
589
+ const ok = res.statusCode === 200;
590
+ res.resume();
591
+ resolve(ok);
592
+ });
593
+ req.setTimeout(timeoutMs, () => {
594
+ req.destroy();
595
+ resolve(false);
596
+ });
597
+ req.on("error", () => resolve(false));
598
+ });
599
+ }
600
+ /**
601
+ * Default scrcpy-bridge binary discovery — used when no `findScrcpyBinFn`
602
+ * is injected. Mirrors `scrcpyBridgeRuntime.findBinary()` semantics in
603
+ * `web/packages/core/src/runtime/scrcpy-bridge.ts` (constructor override
604
+ * → `BEEOS_SCRCPY_BRIDGE_BIN` env → `~/.beeos/bin/scrcpy-bridge[.exe]`).
605
+ *
606
+ * We deliberately do NOT consult `$PATH` (vs the `@beeos/core` adapter
607
+ * which uses `which`) — the fleet daemon usually runs from a non-login
608
+ * shell where `$PATH` is minimal, so PATH-based discovery is unreliable.
609
+ * The CLI's `scrcpyBridgeRuntime.ensureInstalled` always lays the binary
610
+ * at `~/.beeos/bin/scrcpy-bridge`, so the managed-install path is
611
+ * sufficient for the supported deploy modes.
612
+ */
613
+ async function defaultFindScrcpyBin(override) {
614
+ if (override && (await fileExists(override)))
615
+ return override;
616
+ const envBin = process.env.BEEOS_SCRCPY_BRIDGE_BIN;
617
+ if (envBin && (await fileExists(envBin)))
618
+ return envBin;
619
+ const home = beeoHome();
620
+ const exe = process.platform === "win32" ? "scrcpy-bridge.exe" : "scrcpy-bridge";
621
+ const managed = path.join(home, "bin", exe);
622
+ if (await fileExists(managed))
623
+ return managed;
624
+ return null;
625
+ }
626
+ /** Resolve the BeeOS home directory (override-aware, mirrors `port-allocator.ts`). */
627
+ function beeoHome() {
628
+ const override = process.env.BEEOS_HOME;
629
+ if (override && override.length > 0)
630
+ return override;
631
+ return path.join(os.homedir(), ".beeos");
632
+ }
633
+ async function fileExists(p) {
634
+ try {
635
+ await fs.promises.access(p, fs.constants.F_OK);
636
+ return true;
637
+ }
638
+ catch {
639
+ return false;
640
+ }
641
+ }
642
+ /**
643
+ * `device-mcp-server` `--adb-serial <serial>` is only meaningful when the
644
+ * backend talks to ADB. Currently that's just `adb` (canonical) and the
645
+ * `android` alias; desktop / mock backends ignore the flag entirely so we
646
+ * skip it to keep argv readable in `ps`.
647
+ */
648
+ function isAdbBackend(name) {
649
+ return name === "adb" || name === "android";
650
+ }
651
+ function sleep(ms) {
652
+ return new Promise((res) => {
653
+ const t = setTimeout(res, ms);
654
+ if (typeof t === "object" && t && "unref" in t) {
655
+ try {
656
+ t.unref();
657
+ }
658
+ catch {
659
+ /* ignore */
660
+ }
661
+ }
662
+ });
663
+ }
664
+ //# sourceMappingURL=node-process-manager.js.map