@xopcai/xopc 0.0.250 → 0.0.252

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 (312) hide show
  1. package/README.md +8 -5
  2. package/README.zh-CN.md +8 -5
  3. package/dist/browser-ext/dist/background.js +358 -768
  4. package/dist/browser-ext/manifest.json +1 -2
  5. package/dist/extensions/telegram/xopc.extension.json +1 -1
  6. package/dist/gateway/static/root/assets/{activity-store-DfBjTSo9.js → activity-store-w3eq3YpP.js} +1 -1
  7. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BN6FJXkJ.js → agent-avatar-dicebear-k039rbUz.js} +1 -1
  8. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-C7rZH1A2.js → agent-defaults-settings-panel-D4J4oq8p.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agents-CgGaoo4z.js → agents-Bmth_bSQ.js} +1 -1
  10. package/dist/gateway/static/root/assets/{api-zxpcJfgj.js → api-2joIfbrH.js} +1 -1
  11. package/dist/gateway/static/root/assets/{app-management-settings-panel-D2gMshuS.js → app-management-settings-panel-ByJ4kiD0.js} +1 -1
  12. package/dist/gateway/static/root/assets/{appearance-settings-wMu0jSKx.js → appearance-settings-BK2Jga-B.js} +1 -1
  13. package/dist/gateway/static/root/assets/apps-page-B3ky7cWU.js +1 -0
  14. package/dist/gateway/static/root/assets/{archive-plugin-u6EE3JV8.js → archive-plugin-DMDKtYpi.js} +1 -1
  15. package/dist/gateway/static/root/assets/{attachment-load-DbJurnv-.js → attachment-load-B764Ql3Z.js} +1 -1
  16. package/dist/gateway/static/root/assets/{automations-page-Ew_e5HDn.js → automations-page-D-sO8CZe.js} +1 -1
  17. package/dist/gateway/static/root/assets/automations-workspace-Ds5-_-9z.js +6 -0
  18. package/dist/gateway/static/root/assets/{binary-plugins-DtDFNfPM.js → binary-plugins-fxtzYRpv.js} +1 -1
  19. package/dist/gateway/static/root/assets/{block-editor-CnAwmabq.js → block-editor-Bcjtvckh.js} +50 -50
  20. package/dist/gateway/static/root/assets/browser-automation-inputs-BSmnusjD.js +1 -0
  21. package/dist/gateway/static/root/assets/browser-automations-page-DC_OQIBk.js +3 -0
  22. package/dist/gateway/static/root/assets/browser-settings-page-C1FojyG6.js +3 -0
  23. package/dist/gateway/static/root/assets/capabilities-settings-panel-Bs59UCut.js +7 -0
  24. package/dist/gateway/static/root/assets/channels-settings-CM9vNmoo.js +1 -0
  25. package/dist/gateway/static/root/assets/{channels-status-swr-CX-yWwLD.js → channels-status-swr-BuWjIG_a.js} +1 -1
  26. package/dist/gateway/static/root/assets/{chat-terminal-dock-CryTDNdD.js → chat-terminal-dock-5SevEo_I.js} +2 -2
  27. package/dist/gateway/static/root/assets/connectors-page-BPZ44D-V.js +2 -0
  28. package/dist/gateway/static/root/assets/{cron-expression-ji5aWrjG.js → cron-expression-DtsfalBM.js} +1 -1
  29. package/dist/gateway/static/root/assets/{date-picker-Dro_w3eX.js → date-picker-tDEQV5TP.js} +1 -1
  30. package/dist/gateway/static/root/assets/{dependency-picker-Ce19KKnX.js → dependency-picker-HhNwg0Y2.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-DsSi-3uZ.js → desktop-pet-acU4Li-C.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-settings-8WQ4woJy.js → desktop-pet-settings-R84AR0Pe.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-CgvEBfLZ.js → extension-debug-page-CrLlRkSN.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-DkznBbMj.js → extension-page-BH5lmZXE.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-BOjhchK2.js → extension-settings-page-BscjNAd1.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-swr-CMNbl0FZ.js → gateway-config-swr-9HidFZUd.js} +1 -1
  37. package/dist/gateway/static/root/assets/gateway-settings-BxLcW6ij.js +1 -0
  38. package/dist/gateway/static/root/assets/{gateway-startup-retry-CR7Xg8As.js → gateway-startup-retry-DRCPXONr.js} +1 -1
  39. package/dist/gateway/static/root/assets/heartbeat-settings-K5Zhl2rx.js +1 -0
  40. package/dist/gateway/static/root/assets/home-page-CZAg9RBv.js +1 -0
  41. package/dist/gateway/static/root/assets/{image-generation-api-C5mn73ca.js → image-generation-api-CR6Kle8H.js} +1 -1
  42. package/dist/gateway/static/root/assets/index-D4Ykja-U.js +72 -0
  43. package/dist/gateway/static/root/assets/index-zIJ3AXgR.css +2 -0
  44. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BYhfzsqe.js → keyboard-shortcuts-settings-B1QR49-7.js} +1 -1
  45. package/dist/gateway/static/root/assets/languages-5WaOu0Lf.js +2 -0
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-wicoV-ti.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page-vBlknU7C.js → local-apps-page-C74It-T8.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-CF4erhjB.js → locale-store-BfZGZKSs.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-xX-7S49A.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-Dnx6mSNe.js → management-settings-1kNnYL97.js} +1 -1
  51. package/dist/gateway/static/root/assets/markdown-editor-BjMTIM-m.js +1 -0
  52. package/dist/gateway/static/root/assets/{markdown-view-CQvzsE24.js → markdown-view-DjiwT28p.js} +2 -2
  53. package/dist/gateway/static/root/assets/{media-plugins-DrMYeHe7.js → media-plugins-B5c0AoS1.js} +1 -1
  54. package/dist/gateway/static/root/assets/messages-DaIwVWar.js +3 -0
  55. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-AKgGy3Kx.js → mobile-pairing-wizard-CsIZqK51.js} +1 -1
  56. package/dist/gateway/static/root/assets/note-detail-panel-CfWxopl4.js +5 -0
  57. package/dist/gateway/static/root/assets/notes-page-CYN-LCHJ.js +8 -0
  58. package/dist/gateway/static/root/assets/{page-tabs-CX9T71by.js → page-tabs-CqJN6Ljz.js} +1 -1
  59. package/dist/gateway/static/root/assets/{preview-open-alternatives-DvEHoimN.js → preview-open-alternatives-DqRIGxf4.js} +1 -1
  60. package/dist/gateway/static/root/assets/{product-open-page-COcr_NUJ.js → product-open-page-DE2nPE_K.js} +1 -1
  61. package/dist/gateway/static/root/assets/project-detail-page-B5G3LzDq.js +1 -0
  62. package/dist/gateway/static/root/assets/projects-page-CuVK2mKu.js +1 -0
  63. package/dist/gateway/static/root/assets/{registry-api-BsRBlji7.js → registry-api-Bpy8XX-5.js} +1 -1
  64. package/dist/gateway/static/root/assets/remote-access-hub-Dnd73xWt.js +1 -0
  65. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CQ13P-mS.js → runtime-tools-settings-panel-Bb4b74-P.js} +2 -2
  66. package/dist/gateway/static/root/assets/{schema-form-BUVyTpZj.js → schema-form-DoPU5j3J.js} +1 -1
  67. package/dist/gateway/static/root/assets/sessions-page-XL4LyKZe.js +1 -0
  68. package/dist/gateway/static/root/assets/settings-advanced-gate-0ForzDSS.js +1 -0
  69. package/dist/gateway/static/root/assets/{settings-form-section-DVY-8_B9.js → settings-form-section-Ci-9WajJ.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-CdiVYyTl.js → settings-page-CL_2F95D.js} +1 -1
  71. package/dist/gateway/static/root/assets/setup-status-panel-DVws6XZc.js +1 -0
  72. package/dist/gateway/static/root/assets/{share-preview-page-C88YLKm4.js → share-preview-page-XUA3oKQX.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-BwDvcacF.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-BJjrATqE.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-DLir1nM0.js → skills-page-sXXAZDc9.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-BMZAfS3G.js → skills-page.utils-DD79Bl1I.js} +1 -1
  77. package/dist/gateway/static/root/assets/source-workspace-editor-CVWzt0oT.js +1 -0
  78. package/dist/gateway/static/root/assets/{system-settings-panel-BM8ivYan.js → system-settings-panel-BEH64qBV.js} +1 -1
  79. package/dist/gateway/static/root/assets/task-detail-page-0jxMi75O.js +1 -0
  80. package/dist/gateway/static/root/assets/{theme-store-BOgkc_9D.js → theme-store-CISSxU1c.js} +1 -1
  81. package/dist/gateway/static/root/assets/{tunnel-api-DemxChjo.js → tunnel-api-DrKDhnJm.js} +1 -1
  82. package/dist/gateway/static/root/assets/{use-autosave-CV3Ui5hu.js → use-autosave-CPYePL-Q.js} +1 -1
  83. package/dist/gateway/static/root/assets/user-model-page-B6zLDfDl.js +2 -0
  84. package/dist/gateway/static/root/assets/{vendor-codemirror--gTq3YAI.js → vendor-codemirror-Qdcjid65.js} +1 -1
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-CUoCi4Sq.js → voice-api-key-field-DKqzrCXx.js} +1 -1
  86. package/dist/gateway/static/root/assets/{voice-config-api-C-ryeIxj.js → voice-config-api-e9xWjwBX.js} +1 -1
  87. package/dist/gateway/static/root/assets/{work-discovery-overlay-BhDlkCMB.js → work-discovery-overlay-kTQug6bq.js} +1 -1
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D8CcPc_C.js → workflow-run-setup-panel-m9SKj_GT.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-Bcd1XqP7.js +5 -0
  90. package/dist/gateway/static/root/index.html +10 -10
  91. package/dist/package.js +1 -1
  92. package/dist/packages/gateway-contract/src/new-session.js +9 -0
  93. package/dist/src/agent/agent-manager.d.ts +2 -1
  94. package/dist/src/agent/agent-manager.js +2 -1
  95. package/dist/src/agent/coding/repository-instructions.js +2 -2
  96. package/dist/src/agent/coding/workspace-revision.js +2 -2
  97. package/dist/src/agent/commands/command-isolation.js +2 -2
  98. package/dist/src/agent/external-tools/composio-provider.d.ts +1 -0
  99. package/dist/src/agent/external-tools/composio-provider.js +64 -34
  100. package/dist/src/agent/external-tools/search-error.js +5 -3
  101. package/dist/src/agent/service.js +2 -1
  102. package/dist/src/agent/service.types.d.ts +2 -1
  103. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +4 -0
  104. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  105. package/dist/src/agent/tool-manuals/browser.js +15 -226
  106. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -21
  107. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +48 -165
  108. package/dist/src/agent/tools/browser/tool/schemas.d.ts +203 -16
  109. package/dist/src/agent/tools/browser/tool/schemas.js +146 -16
  110. package/dist/src/agent/tools/browser-automation-tool.d.ts +121 -0
  111. package/dist/src/agent/tools/browser-automation-tool.js +197 -0
  112. package/dist/src/agent/tools/factory.d.ts +6 -9
  113. package/dist/src/agent/tools/factory.js +28 -55
  114. package/dist/src/agent/tools/index.d.ts +2 -2
  115. package/dist/src/agent/tools/index.js +3 -3
  116. package/dist/src/agent/tools/review-workspace.js +2 -2
  117. package/dist/src/auth/oauth/xopc-cloud.js +3 -1
  118. package/dist/src/automations/domain/defaults.js +1 -1
  119. package/dist/src/automations/domain/types.d.ts +5 -5
  120. package/dist/src/automations/domain/validation.d.ts +12 -12
  121. package/dist/src/automations/domain/validation.js +3 -3
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +3 -3
  123. package/dist/src/automations/draft/automation-draft-validator.js +1 -1
  124. package/dist/src/automations/service/action-executor.d.ts +1 -1
  125. package/dist/src/automations/service/action-executor.js +7 -7
  126. package/dist/src/browser/{recipes → automations}/index.d.ts +1 -0
  127. package/dist/src/browser/automations/index.js +4 -0
  128. package/dist/src/browser/automations/repository.d.ts +13 -0
  129. package/dist/src/browser/automations/repository.js +60 -0
  130. package/dist/src/browser/automations/runner.d.ts +17 -0
  131. package/dist/src/browser/automations/runner.js +173 -0
  132. package/dist/src/browser/automations/runtime-service.d.ts +6 -0
  133. package/dist/src/browser/automations/runtime-service.js +37 -0
  134. package/dist/src/browser/automations/schema.d.ts +144 -0
  135. package/dist/src/browser/automations/schema.js +135 -0
  136. package/dist/src/browser/automations/service.d.ts +146 -0
  137. package/dist/src/browser/automations/service.js +168 -0
  138. package/dist/src/browser/automations/types.d.ts +90 -0
  139. package/dist/src/browser/cache-dir-policy.d.ts +1 -1
  140. package/dist/src/browser/cache-dir-policy.js +1 -4
  141. package/dist/src/browser/drivers/browser-driver.d.ts +17 -0
  142. package/dist/src/browser/drivers/create-driver.d.ts +3 -0
  143. package/dist/src/browser/drivers/create-driver.js +84 -0
  144. package/dist/src/browser/drivers/extension-driver.d.ts +20 -0
  145. package/dist/src/browser/drivers/extension-driver.js +47 -0
  146. package/dist/src/browser/drivers/playwright-driver.d.ts +38 -0
  147. package/dist/src/browser/drivers/playwright-driver.js +406 -0
  148. package/dist/src/browser/index.d.ts +10 -15
  149. package/dist/src/browser/index.js +10 -15
  150. package/dist/src/browser/install-lock.d.ts +1 -2
  151. package/dist/src/browser/install-lock.js +3 -9
  152. package/dist/src/browser/install-progress.d.ts +1 -1
  153. package/dist/src/browser/observation/format.d.ts +2 -0
  154. package/dist/src/browser/observation/format.js +26 -0
  155. package/dist/src/browser/policy/approval-store.d.ts +17 -0
  156. package/dist/src/browser/policy/approval-store.js +62 -0
  157. package/dist/src/browser/policy/browser-policy.d.ts +3 -0
  158. package/dist/src/browser/policy/browser-policy.js +27 -0
  159. package/dist/src/browser/providers/browser-ext-install.d.ts +1 -1
  160. package/dist/src/browser/providers/browser-ext-install.js +3 -5
  161. package/dist/src/browser/providers/browser-use.js +1 -1
  162. package/dist/src/browser/providers/browserbase.js +1 -1
  163. package/dist/src/browser/providers/extension-ws-acquire.d.ts +1 -4
  164. package/dist/src/browser/providers/extension-ws-acquire.js +1 -13
  165. package/dist/src/browser/providers/extension.d.ts +3 -22
  166. package/dist/src/browser/providers/extension.js +7 -15
  167. package/dist/src/browser/providers/index.d.ts +2 -2
  168. package/dist/src/browser/providers/index.js +3 -3
  169. package/dist/src/browser/providers/types.d.ts +0 -94
  170. package/dist/src/browser/readiness.d.ts +4 -22
  171. package/dist/src/browser/readiness.js +55 -118
  172. package/dist/src/browser/runtime/browser-runtime.d.ts +30 -0
  173. package/dist/src/browser/runtime/browser-runtime.js +362 -0
  174. package/dist/src/browser/url-policy.d.ts +3 -3
  175. package/dist/src/browser/url-policy.js +7 -6
  176. package/dist/src/browser/verification/expectation.d.ts +2 -0
  177. package/dist/src/browser/verification/expectation.js +17 -0
  178. package/dist/src/cli/command-loaders.js +1 -0
  179. package/dist/src/cli/command-manifest.js +5 -1
  180. package/dist/src/cli/commands/browser-cli-helpers.d.ts +0 -6
  181. package/dist/src/cli/commands/browser-cli-helpers.js +11 -144
  182. package/dist/src/cli/commands/browser.d.ts +0 -5
  183. package/dist/src/cli/commands/browser.js +11 -152
  184. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  185. package/dist/src/cli/commands/doctor/checks/node-version.js +25 -9
  186. package/dist/src/cli/commands/platform.d.ts +1 -0
  187. package/dist/src/cli/commands/platform.js +111 -0
  188. package/dist/src/config/loader.js +9 -3
  189. package/dist/src/config/schema.d.ts +131 -84
  190. package/dist/src/config/schema.js +112 -59
  191. package/dist/src/connectors/composio-sessions.js +1 -3
  192. package/dist/src/extensions/marketplace.js +4 -0
  193. package/dist/src/files/file-service.js +139 -14
  194. package/dist/src/gateway/hono/lib/config-payload.d.ts +12 -26
  195. package/dist/src/gateway/hono/lib/config-payload.js +10 -39
  196. package/dist/src/gateway/hono/routes/browser-automations.d.ts +3 -0
  197. package/dist/src/gateway/hono/routes/browser-automations.js +77 -0
  198. package/dist/src/gateway/hono/routes/browser-install.js +0 -32
  199. package/dist/src/gateway/hono/routes/browser.d.ts +0 -17
  200. package/dist/src/gateway/hono/routes/browser.js +46 -568
  201. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -1
  202. package/dist/src/gateway/hono/routes/config.js +0 -11
  203. package/dist/src/gateway/hono/routes/lazy-bundles.js +5 -5
  204. package/dist/src/gateway/service.d.ts +4 -6
  205. package/dist/src/gateway/service.js +20 -23
  206. package/dist/src/platform/client.d.ts +121 -0
  207. package/dist/src/platform/client.js +108 -0
  208. package/dist/src/platform/contracts.d.ts +194 -0
  209. package/dist/src/platform/contracts.js +150 -0
  210. package/dist/src/platform/index.d.ts +4 -0
  211. package/dist/src/platform/index.js +9 -0
  212. package/dist/src/platform/resolution.d.ts +4 -0
  213. package/dist/src/platform/resolution.js +16 -0
  214. package/dist/src/platform/worker.d.ts +6 -0
  215. package/dist/src/platform/worker.js +75 -0
  216. package/dist/src/providers/xopc-cloud-config.js +3 -1
  217. package/dist/src/session/session-context-for-llm.js +41 -1
  218. package/dist/src/share/hosted-session-share.js +3 -1
  219. package/dist/src/share/share-thumbnail.js +1 -1
  220. package/dist/src/storage/sqlite/migrations/153_browser_control_v2.sql +45 -0
  221. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  222. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  223. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  224. package/dist/src/storage/sqlite/schema.js +1 -1
  225. package/dist/src/storage/sqlite/schema.sql +16 -20
  226. package/dist/src/tasks/home-query-service.js +1 -1
  227. package/dist/src/tunnel/env.js +3 -1
  228. package/dist/src/voice/realtime/agentEngine.js +0 -1
  229. package/package.json +7 -7
  230. package/dist/gateway/static/root/assets/apps-page-KF1Gnv36.js +0 -1
  231. package/dist/gateway/static/root/assets/automations-workspace-Ch-ldu35.js +0 -6
  232. package/dist/gateway/static/root/assets/browser-settings-page-DtVhsHJW.js +0 -8
  233. package/dist/gateway/static/root/assets/browser-workflow-inputs-BX1-uM9L.js +0 -1
  234. package/dist/gateway/static/root/assets/browser-workflows-page-CcbUOWDF.js +0 -3
  235. package/dist/gateway/static/root/assets/capabilities-settings-panel--sXeylhe.js +0 -7
  236. package/dist/gateway/static/root/assets/channels-settings-AXSBDujZ.js +0 -1
  237. package/dist/gateway/static/root/assets/code-editor-D4_k-6QN.js +0 -1
  238. package/dist/gateway/static/root/assets/connectors-page-HBHUWohz.js +0 -2
  239. package/dist/gateway/static/root/assets/gateway-config-api-OEruhhX3.js +0 -1
  240. package/dist/gateway/static/root/assets/gateway-settings-BgH3A0LO.js +0 -1
  241. package/dist/gateway/static/root/assets/heartbeat-settings-C97naDkO.js +0 -1
  242. package/dist/gateway/static/root/assets/home-page-BBKKme4G.js +0 -1
  243. package/dist/gateway/static/root/assets/html-workspace-editor-C3DKAkMc.js +0 -1
  244. package/dist/gateway/static/root/assets/index-BcaF-dgQ.js +0 -72
  245. package/dist/gateway/static/root/assets/index-DAryGvZ7.css +0 -2
  246. package/dist/gateway/static/root/assets/local-app-workbench-page-DNncc2tn.js +0 -2
  247. package/dist/gateway/static/root/assets/logs-page-CizZInrT.js +0 -2
  248. package/dist/gateway/static/root/assets/markdown-editor-nDLmA_LF.js +0 -2
  249. package/dist/gateway/static/root/assets/markdown-split-DtBtcHWi.js +0 -1
  250. package/dist/gateway/static/root/assets/messages-Cf5hpZE6.js +0 -3
  251. package/dist/gateway/static/root/assets/note-detail-panel-Bw3jD9Jf.js +0 -5
  252. package/dist/gateway/static/root/assets/notes-page-Dpqq7Z-J.js +0 -8
  253. package/dist/gateway/static/root/assets/project-detail-page-BuT6MCTs.js +0 -1
  254. package/dist/gateway/static/root/assets/projects-page-DXWMxOjf.js +0 -1
  255. package/dist/gateway/static/root/assets/remote-access-hub-7rBCUWzZ.js +0 -1
  256. package/dist/gateway/static/root/assets/sessions-page-gmEOYNb4.js +0 -1
  257. package/dist/gateway/static/root/assets/settings-advanced-gate-DYYoJcl7.js +0 -1
  258. package/dist/gateway/static/root/assets/setup-status-panel-BhenBnUj.js +0 -1
  259. package/dist/gateway/static/root/assets/shares-settings-Dq7xIj0_.js +0 -1
  260. package/dist/gateway/static/root/assets/skill-reload-api-MDI9Lz6z.js +0 -1
  261. package/dist/gateway/static/root/assets/task-detail-page-P0_RldWv.js +0 -1
  262. package/dist/gateway/static/root/assets/user-model-page-CxfnoRVn.js +0 -2
  263. package/dist/gateway/static/root/assets/workflows-page-Bxn2Dc16.js +0 -5
  264. package/dist/src/agent/tools/browser-recipe-tool.d.ts +0 -12
  265. package/dist/src/agent/tools/browser-recipe-tool.js +0 -113
  266. package/dist/src/browser/actions/extension-registry-bridge.d.ts +0 -5
  267. package/dist/src/browser/actions/extension-registry-bridge.js +0 -312
  268. package/dist/src/browser/actions/registry.d.ts +0 -5
  269. package/dist/src/browser/actions/registry.js +0 -741
  270. package/dist/src/browser/actions/types.d.ts +0 -65
  271. package/dist/src/browser/backend-from-config.d.ts +0 -22
  272. package/dist/src/browser/backend-from-config.js +0 -99
  273. package/dist/src/browser/browser-command-timeout.d.ts +0 -2
  274. package/dist/src/browser/browser-command-timeout.js +0 -11
  275. package/dist/src/browser/cdp-local-launcher.d.ts +0 -35
  276. package/dist/src/browser/cdp-local-launcher.js +0 -154
  277. package/dist/src/browser/cdp-supervisor.d.ts +0 -58
  278. package/dist/src/browser/cdp-supervisor.js +0 -133
  279. package/dist/src/browser/humanize.d.ts +0 -80
  280. package/dist/src/browser/humanize.js +0 -363
  281. package/dist/src/browser/manager.d.ts +0 -50
  282. package/dist/src/browser/manager.js +0 -251
  283. package/dist/src/browser/pipeline/output.d.ts +0 -35
  284. package/dist/src/browser/pipeline/output.js +0 -74
  285. package/dist/src/browser/pipeline/runner.d.ts +0 -27
  286. package/dist/src/browser/pipeline/runner.js +0 -453
  287. package/dist/src/browser/pipeline/schema.d.ts +0 -42
  288. package/dist/src/browser/pipeline/schema.js +0 -116
  289. package/dist/src/browser/pipeline/template.d.ts +0 -30
  290. package/dist/src/browser/pipeline/template.js +0 -112
  291. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -83
  292. package/dist/src/browser/providers/cloakbrowser.js +0 -612
  293. package/dist/src/browser/recipes/index.js +0 -3
  294. package/dist/src/browser/recipes/repository.d.ts +0 -13
  295. package/dist/src/browser/recipes/repository.js +0 -81
  296. package/dist/src/browser/recipes/runtime-service.d.ts +0 -6
  297. package/dist/src/browser/recipes/runtime-service.js +0 -30
  298. package/dist/src/browser/recipes/service.d.ts +0 -36
  299. package/dist/src/browser/recipes/service.js +0 -186
  300. package/dist/src/browser/recipes/types.d.ts +0 -36
  301. package/dist/src/browser/schemas.d.ts +0 -53
  302. package/dist/src/browser/schemas.js +0 -68
  303. package/dist/src/browser/session-lifecycle.d.ts +0 -40
  304. package/dist/src/browser/session-lifecycle.js +0 -136
  305. package/dist/src/browser/snapshot-helpers.d.ts +0 -24
  306. package/dist/src/browser/snapshot-helpers.js +0 -70
  307. package/dist/src/browser/stealth.d.ts +0 -46
  308. package/dist/src/browser/stealth.js +0 -163
  309. package/dist/src/gateway/hono/routes/browser-workflows.d.ts +0 -3
  310. package/dist/src/gateway/hono/routes/browser-workflows.js +0 -78
  311. /package/dist/src/browser/{actions → automations}/types.js +0 -0
  312. /package/dist/src/browser/{recipes/types.js → drivers/browser-driver.js} +0 -0
@@ -0,0 +1,362 @@
1
+ import { assertBrowserUrlAllowed, checkPostRedirectUrl, containsApiKeyPattern } from "../url-policy.js";
2
+ import { consumeBrowserApproval, createBrowserApproval } from "../policy/approval-store.js";
3
+ import { browserRiskNeedsApproval, classifyBrowserRisk } from "../policy/browser-policy.js";
4
+ import { isAbsolute, relative, resolve } from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ //#region src/browser/runtime/browser-runtime.ts
7
+ var BrowserRuntime = class {
8
+ driver = null;
9
+ sessionsByTask = /* @__PURE__ */ new Map();
10
+ constructor(options) {
11
+ this.options = options;
12
+ }
13
+ async execute(taskKey, input, signal) {
14
+ this.evictExpiredSessions();
15
+ if (!this.options.getConfig().enabled) return failure("DRIVER_UNAVAILABLE", "Browser Control is disabled.");
16
+ if (signal?.aborted) return failure("ABORTED", "Operation was aborted.");
17
+ let session;
18
+ let driver;
19
+ try {
20
+ session = await this.resolveSession(taskKey, input.sessionId);
21
+ if (!session) return failure("SESSION_NOT_FOUND", "The browser session does not belong to this task.");
22
+ driver = await this.getDriver();
23
+ } catch (error) {
24
+ return failure("DRIVER_UNAVAILABLE", error instanceof Error ? error.message : String(error));
25
+ }
26
+ session.lastUsedAt = Date.now();
27
+ this.options.emit?.("browser.action.started", {
28
+ sessionId: session.id,
29
+ action: input.action
30
+ });
31
+ let result;
32
+ try {
33
+ result = await this.dispatch(driver, session, input, signal);
34
+ result = this.constrainResult(result);
35
+ } catch (error) {
36
+ result = failure("DRIVER_UNAVAILABLE", error instanceof Error ? error.message : String(error));
37
+ }
38
+ if (result.ok) {
39
+ if (result.receipt.observation) session.observation = result.receipt.observation;
40
+ this.options.emit?.("browser.action.completed", {
41
+ sessionId: session.id,
42
+ receipt: withoutVisual(result.receipt)
43
+ });
44
+ if (result.receipt.observation) this.options.emit?.("browser.observation.created", withoutVisual(result.receipt.observation));
45
+ } else if ("error" in result) {
46
+ if (result.error.observation) session.observation = result.error.observation;
47
+ this.options.emit?.("browser.session.failed", {
48
+ sessionId: session.id,
49
+ error: result.error
50
+ });
51
+ }
52
+ return result;
53
+ }
54
+ async shutdown() {
55
+ await this.driver?.disconnect();
56
+ this.driver = null;
57
+ this.sessionsByTask.clear();
58
+ }
59
+ async closeTaskSession(taskKey) {
60
+ const session = this.sessionsByTask.get(taskKey);
61
+ if (!session) return;
62
+ await this.driver?.closeSession(session.id);
63
+ this.sessionsByTask.delete(taskKey);
64
+ this.options.emit?.("browser.session.closed", { sessionId: session.id });
65
+ }
66
+ async dispatch(driver, session, input, signal) {
67
+ if (input.action === "close") {
68
+ await this.closeTaskSession(session.taskKey);
69
+ return {
70
+ ok: true,
71
+ receipt: {
72
+ action: "close",
73
+ risk: "read",
74
+ durationMs: 0,
75
+ verified: true
76
+ }
77
+ };
78
+ }
79
+ if (input.action === "observe") return {
80
+ ok: true,
81
+ receipt: {
82
+ action: "observe",
83
+ risk: "read",
84
+ durationMs: 0,
85
+ verified: true,
86
+ observation: await driver.observe(session.id, input, signal)
87
+ }
88
+ };
89
+ if (input.action === "navigate") {
90
+ const blocked = this.validateUrl(input.url);
91
+ if (blocked) return failure("BLOCKED_URL", blocked);
92
+ const crossDomainPolicy = this.crossDomainPolicy(session.observation?.url, input.url);
93
+ if (crossDomainPolicy === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
94
+ const authorization = this.authorize(session.taskKey, input, crossDomainPolicy === "ask" ? "external_effect" : "read", crossDomainPolicy);
95
+ if (authorization) return authorization;
96
+ const result = await driver.navigate(session.id, input, signal);
97
+ return this.validateRedirect(input.url, result);
98
+ }
99
+ if (input.action === "tabs") {
100
+ if (input.url) {
101
+ const blocked = this.validateUrl(input.url);
102
+ if (blocked) return failure("BLOCKED_URL", blocked);
103
+ const crossDomainPolicy = this.crossDomainPolicy(session.observation?.url, input.url);
104
+ if (crossDomainPolicy === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
105
+ const authorization = this.authorize(session.taskKey, input, crossDomainPolicy === "ask" ? "external_effect" : "read", crossDomainPolicy);
106
+ if (authorization) return authorization;
107
+ }
108
+ const result = await driver.tabs(session.id, input, signal);
109
+ if (!input.url || !result.ok) return result;
110
+ const finalUrl = result.receipt.tabs?.find((tab) => tab.active)?.url;
111
+ const blocked = finalUrl ? this.blockedRedirect(finalUrl) : "The created tab did not report its final URL.";
112
+ return blocked ? failure("BLOCKED_URL", blocked) : result;
113
+ }
114
+ if (input.action === "sequence") return this.executeSequence(driver, session, input, signal);
115
+ const target = findActionTarget(input, session.observation);
116
+ const risk = classifyBrowserRisk(input, target);
117
+ if (input.action === "upload") {
118
+ const invalidPath = this.invalidUploadPath(input.paths);
119
+ if (invalidPath) return failure("INVALID_INPUT", invalidPath);
120
+ }
121
+ const authorization = this.authorize(session.taskKey, input, risk, void 0, target);
122
+ if (authorization) return authorization;
123
+ return withRisk(await driver.perform(session.id, input, signal), risk);
124
+ }
125
+ async executeSequence(driver, session, input, signal) {
126
+ const config = this.options.getConfig();
127
+ if (input.steps.length === 0 || input.steps.length > config.limits.maxSequenceLength) return failure("INVALID_INPUT", `Sequence length must be between 1 and ${config.limits.maxSequenceLength}.`);
128
+ const initialDocument = session.observation?.documentId;
129
+ let revision = input.revision;
130
+ let last;
131
+ let highestRisk = "draft";
132
+ for (const step of input.steps) {
133
+ const risk = classifyBrowserRisk(step, findActionTarget(step, session.observation));
134
+ if (riskRank(risk) > riskRank(highestRisk)) highestRisk = risk;
135
+ }
136
+ const authorization = this.authorize(session.taskKey, input, highestRisk);
137
+ if (authorization) return authorization;
138
+ for (const step of input.steps) {
139
+ const primitive = {
140
+ ...step,
141
+ sessionId: session.id,
142
+ revision
143
+ };
144
+ last = await driver.perform(session.id, primitive, signal);
145
+ if (!last.ok) return last;
146
+ const observation = last.receipt.observation;
147
+ if (observation) {
148
+ session.observation = observation;
149
+ revision = observation.revision;
150
+ if (initialDocument && observation.documentId !== initialDocument) return failure("STALE_OBSERVATION", "Sequence stopped because navigation replaced the document.", observation);
151
+ }
152
+ }
153
+ if (!last?.ok) return failure("INVALID_INPUT", "Sequence did not execute.");
154
+ return {
155
+ ok: true,
156
+ receipt: {
157
+ ...last.receipt,
158
+ action: "sequence",
159
+ risk: highestRisk
160
+ }
161
+ };
162
+ }
163
+ authorize(sessionKey, input, risk, explicitPolicy, target) {
164
+ const security = this.options.getConfig().security;
165
+ const policy = explicitPolicy ?? (input.action === "upload" ? security.uploads : security.consequentialActions);
166
+ if (!browserRiskNeedsApproval(risk) || policy === "allow") return null;
167
+ if (policy === "deny") return failure("APPROVAL_REQUIRED", `Browser action is denied by policy (${risk}).`);
168
+ if (consumeBrowserApproval(input.approvalId, sessionKey, input)) return null;
169
+ const approval = createBrowserApproval(sessionKey, input, risk, browserApprovalSummary(input, target));
170
+ this.options.emit?.("browser.approval.required", approval);
171
+ return {
172
+ ok: false,
173
+ error: {
174
+ code: "APPROVAL_REQUIRED",
175
+ message: "This browser action needs local-owner approval before it can run.",
176
+ approval: {
177
+ id: approval.id,
178
+ risk,
179
+ summary: approval.summary,
180
+ expiresAt: approval.expiresAt
181
+ }
182
+ }
183
+ };
184
+ }
185
+ validateUrl(url) {
186
+ if (containsApiKeyPattern(url)) return "URL contains a credential-like value.";
187
+ try {
188
+ const host = new URL(url).hostname.toLowerCase();
189
+ assertBrowserUrlAllowed(url, { privateHostAllowed: this.options.getConfig().security.allowedPrivateHosts.some((candidate) => candidate.toLowerCase() === host) });
190
+ return null;
191
+ } catch (error) {
192
+ return error instanceof Error ? error.message : String(error);
193
+ }
194
+ }
195
+ validateRedirect(requestedUrl, result) {
196
+ if (!result.ok || !result.receipt.observation) return result;
197
+ const finalUrl = result.receipt.observation.url;
198
+ if (finalUrl === requestedUrl) return result;
199
+ const blocked = this.blockedRedirect(finalUrl);
200
+ return blocked ? failure("BLOCKED_URL", blocked, result.receipt.observation) : result;
201
+ }
202
+ blockedRedirect(finalUrl) {
203
+ try {
204
+ const host = new URL(finalUrl).hostname.toLowerCase();
205
+ return checkPostRedirectUrl(finalUrl, { privateHostAllowed: this.options.getConfig().security.allowedPrivateHosts.some((candidate) => candidate.toLowerCase() === host) });
206
+ } catch {
207
+ return "Browser returned an invalid final URL.";
208
+ }
209
+ }
210
+ crossDomainPolicy(currentUrl, nextUrl) {
211
+ if (!currentUrl || currentUrl === "about:blank") return "allow";
212
+ try {
213
+ if (new URL(currentUrl).hostname === new URL(nextUrl).hostname) return "allow";
214
+ } catch {
215
+ return "allow";
216
+ }
217
+ return this.options.getConfig().security.crossDomainNavigation;
218
+ }
219
+ invalidUploadPath(paths) {
220
+ const roots = this.options.allowedUploadRoots ?? [];
221
+ if (roots.length === 0) return "File uploads are unavailable because no upload root is configured.";
222
+ const normalizedRoots = roots.map((root) => resolve(root));
223
+ const invalid = paths.find((path) => {
224
+ if (!isAbsolute(path)) return true;
225
+ const absolute = resolve(path);
226
+ return !normalizedRoots.some((root) => {
227
+ const child = relative(root, absolute);
228
+ return child === "" || !child.startsWith("..") && !isAbsolute(child);
229
+ });
230
+ });
231
+ return invalid ? `Upload path is outside the allowed workspace: ${invalid}` : null;
232
+ }
233
+ async resolveSession(taskKey, requestedId) {
234
+ const existing = this.sessionsByTask.get(taskKey);
235
+ if (existing) return !requestedId || requestedId === existing.id ? existing : null;
236
+ if (requestedId) return null;
237
+ const session = {
238
+ id: randomUUID(),
239
+ taskKey,
240
+ lastUsedAt: Date.now()
241
+ };
242
+ const driver = await this.getDriver();
243
+ await driver.createSession(session.id);
244
+ this.sessionsByTask.set(taskKey, session);
245
+ this.options.emit?.("browser.session.started", {
246
+ sessionId: session.id,
247
+ taskKey,
248
+ driver: driver.kind
249
+ });
250
+ return session;
251
+ }
252
+ async getDriver() {
253
+ if (this.driver) return this.driver;
254
+ this.driver = await this.options.createDriver();
255
+ await this.driver.connect();
256
+ return this.driver;
257
+ }
258
+ constrainResult(result) {
259
+ const observation = "error" in result ? result.error.observation : result.receipt.observation;
260
+ if (!observation) return result;
261
+ const { maxNodes, maxCharacters } = this.options.getConfig().observation;
262
+ const nodes = [];
263
+ let characters = 0;
264
+ for (const node of observation.nodes.slice(0, maxNodes)) {
265
+ const size = node.name.length + (node.value?.length ?? 0) + (node.description?.length ?? 0);
266
+ if (characters + size > maxCharacters) break;
267
+ characters += size;
268
+ nodes.push(node);
269
+ }
270
+ if (nodes.length === observation.nodes.length) return result;
271
+ const refs = new Set(nodes.map((node) => node.ref));
272
+ const constrained = {
273
+ ...observation,
274
+ nodes,
275
+ changes: {
276
+ added: observation.changes.added.filter((node) => refs.has(node.ref)),
277
+ changed: observation.changes.changed.filter((node) => refs.has(node.ref)),
278
+ removed: observation.changes.removed
279
+ }
280
+ };
281
+ return "error" in result ? {
282
+ ok: false,
283
+ error: {
284
+ ...result.error,
285
+ observation: constrained
286
+ }
287
+ } : {
288
+ ok: true,
289
+ receipt: {
290
+ ...result.receipt,
291
+ observation: constrained
292
+ }
293
+ };
294
+ }
295
+ evictExpiredSessions() {
296
+ const expiresBefore = Date.now() - this.options.getConfig().limits.sessionTimeoutMs;
297
+ for (const [taskKey, session] of this.sessionsByTask) {
298
+ if (session.lastUsedAt >= expiresBefore) continue;
299
+ this.driver?.closeSession(session.id).catch(() => {});
300
+ this.sessionsByTask.delete(taskKey);
301
+ }
302
+ }
303
+ };
304
+ function failure(code, message, observation) {
305
+ return {
306
+ ok: false,
307
+ error: {
308
+ code,
309
+ message,
310
+ observation
311
+ }
312
+ };
313
+ }
314
+ function withRisk(result, risk) {
315
+ return result.ok ? {
316
+ ok: true,
317
+ receipt: {
318
+ ...result.receipt,
319
+ risk
320
+ }
321
+ } : result;
322
+ }
323
+ function riskRank(risk) {
324
+ return [
325
+ "read",
326
+ "draft",
327
+ "external_effect",
328
+ "destructive",
329
+ "sensitive"
330
+ ].indexOf(risk);
331
+ }
332
+ function findActionTarget(input, observation) {
333
+ const ref = "ref" in input && input.ref ? input.ref : input.action === "press" ? observation?.focused : void 0;
334
+ return ref ? observation?.nodes.find((node) => node.ref === ref) : void 0;
335
+ }
336
+ function browserApprovalSummary(input, target) {
337
+ const targetName = target?.name.trim() ? ` “${target.name.slice(0, 120)}”` : "";
338
+ switch (input.action) {
339
+ case "navigate": return `Navigate to ${safeUrlLabel(input.url)}.`;
340
+ case "tabs": return input.url ? `Open a tab at ${safeUrlLabel(input.url)}.` : `Change browser tabs (${input.operation}).`;
341
+ case "click": return `Click${targetName || ` element ${input.ref}`}.`;
342
+ case "fill": return `${target?.states.includes("sensitive") ? "Fill a sensitive field" : "Fill field"}${targetName || ` ${input.ref}`}${input.submit ? " and submit the form" : ""}.`;
343
+ case "upload": return `Upload ${input.paths.length} file${input.paths.length === 1 ? "" : "s"}${targetName ? ` using${targetName}` : ""}.`;
344
+ case "press": return `Press ${input.key}${targetName ? ` on${targetName}` : ""}.`;
345
+ case "sequence": return `Run ${input.steps.length} browser actions as one sequence.`;
346
+ default: return `Run browser action “${input.action}”${targetName ? ` on${targetName}` : ""}.`;
347
+ }
348
+ }
349
+ function safeUrlLabel(raw) {
350
+ try {
351
+ const url = new URL(raw);
352
+ return `${url.origin}${url.pathname}`.slice(0, 240);
353
+ } catch {
354
+ return "the requested URL";
355
+ }
356
+ }
357
+ function withoutVisual(value) {
358
+ if (!value || typeof value !== "object") return value;
359
+ return JSON.parse(JSON.stringify(value, (key, child) => key === "visual" ? void 0 : child));
360
+ }
361
+ //#endregion
362
+ export { BrowserRuntime };
@@ -5,10 +5,10 @@
5
5
  * no cloud metadata endpoints, no API key exfiltration attempts.
6
6
  *
7
7
  * @param raw URL string from the agent
8
- * @param options.allowPrivateUrls When true, skip private-IP blocking (cloud metadata still blocked)
8
+ * @param options.privateHostAllowed When true, skip private-IP blocking (cloud metadata still blocked)
9
9
  */
10
10
  export declare function assertBrowserUrlAllowed(raw: string, options?: {
11
- allowPrivateUrls?: boolean;
11
+ privateHostAllowed?: boolean;
12
12
  }): void;
13
13
  /**
14
14
  * Check whether a URL targets an always-blocked cloud metadata endpoint.
@@ -33,5 +33,5 @@ export declare function containsApiKeyPattern(raw: string): boolean;
33
33
  * @returns Error message string if blocked, `undefined` if safe.
34
34
  */
35
35
  export declare function checkPostRedirectUrl(finalUrl: string, options?: {
36
- allowPrivateUrls?: boolean;
36
+ privateHostAllowed?: boolean;
37
37
  }): string | undefined;
@@ -7,7 +7,7 @@ import { isIPv4, isIPv6 } from "node:net";
7
7
  */
8
8
  const ALWAYS_BLOCKED_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
9
9
  /**
10
- * Cloud metadata / IMDS IPv4 addresses — always blocked regardless of `allowPrivateUrls`.
10
+ * Cloud metadata / IMDS IPv4 addresses — always blocked regardless of `privateHostAllowed`.
11
11
  * Covers AWS, GCP, Azure, DigitalOcean, Oracle, Alibaba Cloud, and ECS task metadata.
12
12
  */
13
13
  const ALWAYS_BLOCKED_IPV4 = new Set([
@@ -30,13 +30,13 @@ const API_KEY_PATTERN = /(?:sk-ant-|sk-[a-zA-Z0-9]{20,}|OPENAI_API_KEY|ANTHROPIC
30
30
  * no cloud metadata endpoints, no API key exfiltration attempts.
31
31
  *
32
32
  * @param raw URL string from the agent
33
- * @param options.allowPrivateUrls When true, skip private-IP blocking (cloud metadata still blocked)
33
+ * @param options.privateHostAllowed When true, skip private-IP blocking (cloud metadata still blocked)
34
34
  */
35
35
  function assertBrowserUrlAllowed(raw, options) {
36
36
  const parsed = parseAndValidateUrl(raw);
37
37
  assertNotApiKeyExfiltration(raw);
38
38
  assertNotAlwaysBlocked(parsed.hostname);
39
- assertNotPrivate(parsed.hostname, options?.allowPrivateUrls ?? false);
39
+ assertNotPrivate(parsed.hostname, options?.privateHostAllowed ?? false);
40
40
  }
41
41
  /**
42
42
  * Check whether a URL targets an always-blocked cloud metadata endpoint.
@@ -79,7 +79,7 @@ function containsApiKeyPattern(raw) {
79
79
  */
80
80
  function checkPostRedirectUrl(finalUrl, options) {
81
81
  if (isAlwaysBlockedUrl(finalUrl)) return "Blocked: redirect landed on a cloud metadata endpoint";
82
- if (options?.allowPrivateUrls) return void 0;
82
+ if (options?.privateHostAllowed) return void 0;
83
83
  try {
84
84
  const host = new URL(finalUrl.trim()).hostname.toLowerCase();
85
85
  if (host === "localhost" || host.endsWith(".localhost")) return "Blocked: redirect landed on localhost";
@@ -111,13 +111,14 @@ function assertNotAlwaysBlocked(hostname) {
111
111
  }
112
112
  function assertNotPrivate(hostname, allowPrivate) {
113
113
  const host = hostname.toLowerCase();
114
+ if (allowPrivate) return;
114
115
  if (host === "localhost" || host.endsWith(".localhost")) throw new Error("Blocked: localhost");
115
116
  if (isIPv4(host)) {
116
- if (!allowPrivate && isBlockedIPv4(host)) throw new Error("Blocked: private or non-public IPv4 address");
117
+ if (isBlockedIPv4(host)) throw new Error("Blocked: private or non-public IPv4 address");
117
118
  return;
118
119
  }
119
120
  if (isIPv6(host)) {
120
- if (!allowPrivate && isBlockedIPv6(host)) throw new Error("Blocked: private or loopback IPv6 address");
121
+ if (isBlockedIPv6(host)) throw new Error("Blocked: private or loopback IPv6 address");
121
122
  return;
122
123
  }
123
124
  if (host.endsWith(".local") || host.endsWith(".internal")) throw new Error("Blocked: internal hostname");
@@ -0,0 +1,2 @@
1
+ import type { BrowserExpectation, BrowserObservation } from '@xopcai/browser-control-contract';
2
+ export declare function verifyBrowserExpectation(expectation: BrowserExpectation | undefined, observation: BrowserObservation): string | null;
@@ -0,0 +1,17 @@
1
+ //#region src/browser/verification/expectation.ts
2
+ function verifyBrowserExpectation(expectation, observation) {
3
+ if (!expectation) return null;
4
+ if (expectation.urlIncludes && !observation.url.includes(expectation.urlIncludes)) return `URL does not include ${JSON.stringify(expectation.urlIncludes)}`;
5
+ if (expectation.titleIncludes && !observation.title.includes(expectation.titleIncludes)) return `Title does not include ${JSON.stringify(expectation.titleIncludes)}`;
6
+ if (expectation.textIncludes) {
7
+ if (!observation.nodes.map((node) => `${node.name}\n${node.value ?? ""}\n${node.description ?? ""}`).join("\n").includes(expectation.textIncludes)) return `Page does not include ${JSON.stringify(expectation.textIncludes)}`;
8
+ }
9
+ if (expectation.ref && expectation.state) {
10
+ const present = observation.nodes.some((node) => node.ref === expectation.ref);
11
+ if (expectation.state === "visible" && !present) return `Target ${expectation.ref} is not visible`;
12
+ if (expectation.state === "hidden" && present) return `Target ${expectation.ref} is still visible`;
13
+ }
14
+ return null;
15
+ }
16
+ //#endregion
17
+ export { verifyBrowserExpectation };
@@ -18,6 +18,7 @@ const REGISTRY_COMMAND_MODULES = {
18
18
  doctor: () => import("./commands/doctor/index.js"),
19
19
  support: () => import("./commands/support.js"),
20
20
  runtime: () => import("./commands/runtime.js"),
21
+ platform: () => import("./commands/platform.js"),
21
22
  image: () => import("./commands/image.js"),
22
23
  channels: () => import("./commands/channels.js"),
23
24
  models: () => import("./commands/models.js"),
@@ -91,6 +91,10 @@ const ROOT_HELP_COMMANDS = [
91
91
  name: "runtime",
92
92
  description: "Manage Node.js and Python tool runtimes used by agents"
93
93
  },
94
+ {
95
+ name: "platform",
96
+ description: "Connect to XOPC Cloud or an enterprise platform"
97
+ },
94
98
  {
95
99
  name: "update [options]",
96
100
  description: "Check for and install xopc updates"
@@ -137,7 +141,7 @@ const ROOT_HELP_COMMANDS = [
137
141
  },
138
142
  {
139
143
  name: "browser",
140
- description: "Browser automation commands (uses Playwright)"
144
+ description: "Browser Control v2 diagnostics and extension setup"
141
145
  },
142
146
  {
143
147
  name: "agents",
@@ -1,7 +1 @@
1
- /**
2
- * CLI helpers for `xopc browser` — shared runtime setup for CLI browser commands.
3
- */
4
- export declare function executeBrowserCliAction(action: string, args: Record<string, unknown>): Promise<void>;
5
- export declare function validatePipelineCli(file: string): Promise<void>;
6
- export declare function runPipelineCli(file: string, args: Record<string, unknown>): Promise<void>;
7
1
  export declare function doctorCli(): Promise<void>;
@@ -1,152 +1,19 @@
1
1
  import { init_loader, loadConfig } from "../../config/loader.js";
2
- import { loadPlaywrightCoreModule } from "../../browser/providers/playwright-doctor.js";
3
- import { BrowserManager } from "../../browser/manager.js";
4
- import { resolveBrowserBackendFromConfig } from "../../browser/backend-from-config.js";
5
- import { createBrowserActionRegistry } from "../../browser/actions/registry.js";
6
- import { runBrowserPipeline, validateBrowserPipeline } from "../../browser/pipeline/runner.js";
7
- import "../../browser/index.js";
8
- import { readFile } from "node:fs/promises";
2
+ import { checkBrowserReadiness } from "../../browser/readiness.js";
9
3
  //#region src/cli/commands/browser-cli-helpers.ts
10
4
  init_loader();
11
- let _manager = null;
12
- /** When set, `xopc browser open --headless` overrides config for this CLI invocation. */
13
- let browserCliHeadlessOverride;
14
- async function getManager() {
15
- if (_manager) return _manager;
5
+ async function doctorCli() {
16
6
  const config = await loadConfig();
17
- _manager = new BrowserManager({
18
- getHeadless: () => {
19
- if (typeof browserCliHeadlessOverride === "boolean") return browserCliHeadlessOverride;
20
- return false;
21
- },
22
- getBackend: () => resolveBrowserBackendFromConfig(config)
23
- });
24
- return _manager;
25
- }
26
- async function getActionContext() {
27
- const manager = await getManager();
28
- await manager.ensureConnected();
29
- return {
30
- page: manager.getExtensionProvider() ? null : await manager.getPage("cli"),
31
- manager,
32
- config: await loadConfig(),
33
- taskId: "cli"
34
- };
35
- }
36
- async function executeBrowserCliAction(action, args) {
37
- const prevOverride = browserCliHeadlessOverride;
38
- if (typeof args.headless === "boolean") browserCliHeadlessOverride = args.headless;
39
- try {
40
- const registry = createBrowserActionRegistry();
41
- const ctx = await getActionContext();
42
- const result = await registry.execute(action, ctx, args);
43
- if (result.ok) {
44
- if (result.text) console.log(result.text);
45
- if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));
46
- } else {
47
- console.error(`[${result.error?.code}] ${result.error?.message}`);
48
- process.exitCode = 1;
49
- }
50
- if (action === "close") {
51
- await _manager?.shutdown();
52
- _manager = null;
53
- }
54
- } finally {
55
- browserCliHeadlessOverride = prevOverride;
56
- }
57
- }
58
- async function validatePipelineCli(file) {
59
- let yamlSource;
60
- try {
61
- yamlSource = await readFile(file, "utf8");
62
- } catch (e) {
63
- const msg = e instanceof Error ? e.message : String(e);
64
- console.error(`Failed to read pipeline source: ${msg}`);
65
- process.exitCode = 1;
66
- return;
67
- }
68
- const registry = createBrowserActionRegistry();
69
- const result = validateBrowserPipeline(yamlSource, registry);
70
- if (result.ok) console.log(`✓ Pipeline "${result.document.name}" is valid (${result.document.pipeline.length} steps).`);
71
- else {
72
- console.error("✗ Pipeline validation failed:");
73
- for (const err of result.errors) console.error(` ${err.path}: ${err.message}`);
74
- process.exitCode = 1;
75
- }
76
- }
77
- async function runPipelineCli(file, args) {
78
- let yamlSource;
79
- try {
80
- yamlSource = await readFile(file, "utf8");
81
- } catch (e) {
82
- const msg = e instanceof Error ? e.message : String(e);
83
- console.error(`Failed to read pipeline source: ${msg}`);
84
- process.exitCode = 1;
7
+ const readiness = await checkBrowserReadiness(config);
8
+ console.log("Browser Control v2");
9
+ console.log(`Driver: ${config.browser.driver.kind}`);
10
+ if (!readiness) {
11
+ console.log("Status: ready");
85
12
  return;
86
13
  }
87
- const registry = createBrowserActionRegistry();
88
- const ctx = await getActionContext();
89
- const result = await runBrowserPipeline(yamlSource, args, ctx, registry);
90
- if (result.ok) {
91
- if (result.text) console.log(result.text);
92
- if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));
93
- } else {
94
- console.error(`Pipeline failed: [${result.error?.code}] ${result.error?.message}`);
95
- if (result.diagnostics?.snapshot) console.error(`Snapshot:\n${result.diagnostics.snapshot.slice(0, 2e3)}`);
96
- process.exitCode = 1;
97
- }
98
- await _manager?.shutdown();
99
- _manager = null;
100
- }
101
- async function doctorCli() {
102
- console.log("Browser Doctor");
103
- console.log("──────────────");
104
- try {
105
- const pw = await loadPlaywrightCoreModule();
106
- const chromium = pw.chromium ?? pw.default?.chromium;
107
- if (chromium) {
108
- console.log("✓ playwright-core installed");
109
- const execPath = chromium.executablePath?.();
110
- if (execPath) console.log(` Chromium path: ${execPath}`);
111
- else console.log(" ⚠ No default Chromium path detected. Run: npx playwright install chromium");
112
- } else console.log("✗ playwright-core chromium not available");
113
- } catch {
114
- console.log("✗ playwright-core not installed");
115
- }
116
- try {
117
- await loadConfig();
118
- console.log(`\nConfig:`);
119
- console.log(` enabled: true`);
120
- console.log(` headless: false`);
121
- console.log(` backend: extension`);
122
- console.log(` provider: local`);
123
- {
124
- const port = 19820;
125
- const host = "127.0.0.1";
126
- console.log(`\nExtension Bridge:`);
127
- console.log(` endpoint: ws://${host}:${port}/browser-ext`);
128
- try {
129
- const { browserExtDoctor } = await import("../../browser/providers/browser-ext-install.js");
130
- const artifacts = await browserExtDoctor();
131
- console.log(` artifacts: ${artifacts.installed ? "✓ installed" : "✗ not installed"}`);
132
- if (artifacts.extensionDir) console.log(` path: ${artifacts.extensionDir}`);
133
- if (artifacts.needsRefresh) console.log(` refresh: ⚠ bundled update available`);
134
- } catch {
135
- console.log(` artifacts: ⚠ could not check`);
136
- }
137
- try {
138
- const data = await (await fetch(`http://${host}:${port}/`)).json();
139
- if (data.ok) {
140
- console.log(` server: ✓ running`);
141
- console.log(` extension: ${data.connected ? "✓ connected" : "⚠ waiting for connection"}`);
142
- }
143
- } catch {
144
- console.log(` server: ✗ not running (start xopc with backend: 'extension' to enable)`);
145
- }
146
- }
147
- } catch {
148
- console.log("\n⚠ Could not load config");
149
- }
14
+ console.error(`Status: ${readiness.hint.reason}`);
15
+ if (readiness.hint.detail) console.error(`Detail: ${readiness.hint.detail}`);
16
+ process.exitCode = 1;
150
17
  }
151
18
  //#endregion
152
- export { doctorCli, executeBrowserCliAction, runPipelineCli, validatePipelineCli };
19
+ export { doctorCli };
@@ -1,6 +1 @@
1
- /**
2
- * CLI: `xopc browser` — browser automation commands.
3
- *
4
- * Shares the same action registry and pipeline runner as the `browser_use` AgentTool.
5
- */
6
1
  export {};