@xopcai/xopc 0.0.251 → 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 (329) 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-Bo_dmLv8.js → agent-avatar-dicebear-k039rbUz.js} +1 -1
  8. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-kILWelNb.js → agent-defaults-settings-panel-D4J4oq8p.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agents-yuUn8n-f.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-Cz56nrVF.js → app-management-settings-panel-ByJ4kiD0.js} +1 -1
  12. package/dist/gateway/static/root/assets/{appearance-settings-DxSws5U4.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-7k15-hqo.js → archive-plugin-DMDKtYpi.js} +1 -1
  15. package/dist/gateway/static/root/assets/{attachment-load-B-SFpjd9.js → attachment-load-B764Ql3Z.js} +1 -1
  16. package/dist/gateway/static/root/assets/{automations-page-Qy36j19q.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-CPOZQt8F.js → binary-plugins-fxtzYRpv.js} +1 -1
  19. package/dist/gateway/static/root/assets/{block-editor-DhvVlIp9.js → block-editor-Bcjtvckh.js} +3 -3
  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-1PJoxRuV.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-CBCc6zFA.js → cron-expression-DtsfalBM.js} +1 -1
  29. package/dist/gateway/static/root/assets/{date-picker-u8K5Kt_N.js → date-picker-tDEQV5TP.js} +1 -1
  30. package/dist/gateway/static/root/assets/{dependency-picker-y_i_cnpz.js → dependency-picker-HhNwg0Y2.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-DyL0JxLm.js → desktop-pet-acU4Li-C.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-settings-d2d_IsyP.js → desktop-pet-settings-R84AR0Pe.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-DqIBKJwl.js → extension-debug-page-CrLlRkSN.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-DUW1xxj2.js → extension-page-BH5lmZXE.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-BHY9qaNw.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-7CD9iPR7.js → heartbeat-settings-K5Zhl2rx.js} +1 -1
  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-BtlqMleF.js → keyboard-shortcuts-settings-B1QR49-7.js} +1 -1
  45. package/dist/gateway/static/root/assets/{local-app-workbench-page-BjxfkjxE.js → local-app-workbench-page-wicoV-ti.js} +2 -2
  46. package/dist/gateway/static/root/assets/{local-apps-page-B7xqQe2s.js → local-apps-page-C74It-T8.js} +1 -1
  47. package/dist/gateway/static/root/assets/{locale-store-CF4erhjB.js → locale-store-BfZGZKSs.js} +1 -1
  48. package/dist/gateway/static/root/assets/{logs-page-kACaPZKL.js → logs-page-xX-7S49A.js} +2 -2
  49. package/dist/gateway/static/root/assets/{management-settings-A432siER.js → management-settings-1kNnYL97.js} +1 -1
  50. package/dist/gateway/static/root/assets/{markdown-view-CQvzsE24.js → markdown-view-DjiwT28p.js} +2 -2
  51. package/dist/gateway/static/root/assets/{media-plugins-CpvYiauZ.js → media-plugins-B5c0AoS1.js} +1 -1
  52. package/dist/gateway/static/root/assets/messages-DaIwVWar.js +3 -0
  53. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DyjVGngO.js → mobile-pairing-wizard-CsIZqK51.js} +1 -1
  54. package/dist/gateway/static/root/assets/note-detail-panel-CfWxopl4.js +5 -0
  55. package/dist/gateway/static/root/assets/notes-page-CYN-LCHJ.js +8 -0
  56. package/dist/gateway/static/root/assets/{page-tabs-B3FKzjR6.js → page-tabs-CqJN6Ljz.js} +1 -1
  57. package/dist/gateway/static/root/assets/{preview-open-alternatives-DnjrwAHD.js → preview-open-alternatives-DqRIGxf4.js} +1 -1
  58. package/dist/gateway/static/root/assets/{product-open-page-COcr_NUJ.js → product-open-page-DE2nPE_K.js} +1 -1
  59. package/dist/gateway/static/root/assets/project-detail-page-B5G3LzDq.js +1 -0
  60. package/dist/gateway/static/root/assets/{projects-page-BzH8pjEz.js → projects-page-CuVK2mKu.js} +1 -1
  61. package/dist/gateway/static/root/assets/{registry-api-BsRBlji7.js → registry-api-Bpy8XX-5.js} +1 -1
  62. package/dist/gateway/static/root/assets/remote-access-hub-Dnd73xWt.js +1 -0
  63. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-LO4wZ_dO.js → runtime-tools-settings-panel-Bb4b74-P.js} +2 -2
  64. package/dist/gateway/static/root/assets/{schema-form-crcj4-Pm.js → schema-form-DoPU5j3J.js} +1 -1
  65. package/dist/gateway/static/root/assets/sessions-page-XL4LyKZe.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-0ForzDSS.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-form-section-Bl4MvTmq.js → settings-form-section-Ci-9WajJ.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-page-DplrjZ6x.js → settings-page-CL_2F95D.js} +1 -1
  69. package/dist/gateway/static/root/assets/setup-status-panel-DVws6XZc.js +1 -0
  70. package/dist/gateway/static/root/assets/{share-preview-page-CJP1kURj.js → share-preview-page-XUA3oKQX.js} +1 -1
  71. package/dist/gateway/static/root/assets/shares-settings-BwDvcacF.js +1 -0
  72. package/dist/gateway/static/root/assets/skill-reload-api-BJjrATqE.js +1 -0
  73. package/dist/gateway/static/root/assets/{skills-page-DsjcKg9Q.js → skills-page-sXXAZDc9.js} +1 -1
  74. package/dist/gateway/static/root/assets/{skills-page.utils-D6gWBbvy.js → skills-page.utils-DD79Bl1I.js} +1 -1
  75. package/dist/gateway/static/root/assets/{system-settings-panel-_eCXfqCo.js → system-settings-panel-BEH64qBV.js} +1 -1
  76. package/dist/gateway/static/root/assets/task-detail-page-0jxMi75O.js +1 -0
  77. package/dist/gateway/static/root/assets/{theme-store-BOgkc_9D.js → theme-store-CISSxU1c.js} +1 -1
  78. package/dist/gateway/static/root/assets/{tunnel-api-W5mktxl1.js → tunnel-api-DrKDhnJm.js} +1 -1
  79. package/dist/gateway/static/root/assets/{use-autosave-Na2DYzT3.js → use-autosave-CPYePL-Q.js} +1 -1
  80. package/dist/gateway/static/root/assets/user-model-page-B6zLDfDl.js +2 -0
  81. package/dist/gateway/static/root/assets/{voice-api-key-field-OXweUxS_.js → voice-api-key-field-DKqzrCXx.js} +1 -1
  82. package/dist/gateway/static/root/assets/{voice-config-api-C-ryeIxj.js → voice-config-api-e9xWjwBX.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-BqOsO47I.js → work-discovery-overlay-kTQug6bq.js} +1 -1
  84. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-B9S_lfT1.js → workflow-run-setup-panel-m9SKj_GT.js} +2 -2
  85. package/dist/gateway/static/root/assets/workflows-page-Bcd1XqP7.js +5 -0
  86. package/dist/gateway/static/root/index.html +10 -10
  87. package/dist/package.js +1 -1
  88. package/dist/packages/gateway-contract/src/new-session.js +9 -0
  89. package/dist/src/agent/agent-manager.d.ts +2 -1
  90. package/dist/src/agent/agent-manager.js +6 -5
  91. package/dist/src/agent/background-review/run-background-review.js +1 -1
  92. package/dist/src/agent/coding/repository-instructions.js +2 -2
  93. package/dist/src/agent/coding/workspace-revision.js +2 -2
  94. package/dist/src/agent/commands/command-isolation.js +2 -2
  95. package/dist/src/agent/embedded/model-runtime.js +1 -1
  96. package/dist/src/agent/embedded/run-for-session.js +1 -1
  97. package/dist/src/agent/external-tools/composio-provider.d.ts +1 -0
  98. package/dist/src/agent/external-tools/composio-provider.js +64 -34
  99. package/dist/src/agent/external-tools/search-error.js +5 -3
  100. package/dist/src/agent/image/tool-model-config.js +1 -1
  101. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  102. package/dist/src/agent/service.js +4 -3
  103. package/dist/src/agent/service.types.d.ts +2 -1
  104. package/dist/src/agent/session/session-inspector.js +1 -1
  105. package/dist/src/agent/skills/hub-lock.js +1 -1
  106. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +4 -0
  107. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  108. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  109. package/dist/src/agent/tool-manuals/browser.js +15 -226
  110. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -21
  111. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +48 -165
  112. package/dist/src/agent/tools/browser/tool/schemas.d.ts +203 -16
  113. package/dist/src/agent/tools/browser/tool/schemas.js +146 -16
  114. package/dist/src/agent/tools/browser-automation-tool.d.ts +121 -0
  115. package/dist/src/agent/tools/browser-automation-tool.js +197 -0
  116. package/dist/src/agent/tools/factory.d.ts +6 -9
  117. package/dist/src/agent/tools/factory.js +28 -55
  118. package/dist/src/agent/tools/index.d.ts +2 -2
  119. package/dist/src/agent/tools/index.js +3 -3
  120. package/dist/src/agent/tools/review-workspace.js +2 -2
  121. package/dist/src/ai-assist/text-assist.js +1 -1
  122. package/dist/src/auth/credentials.js +2 -2
  123. package/dist/src/auth/oauth/xopc-cloud.js +3 -1
  124. package/dist/src/auth/profiles/store.js +1 -1
  125. package/dist/src/auth/sync-provider-auth.js +2 -2
  126. package/dist/src/automations/domain/defaults.js +1 -1
  127. package/dist/src/automations/domain/types.d.ts +5 -5
  128. package/dist/src/automations/domain/validation.d.ts +12 -12
  129. package/dist/src/automations/domain/validation.js +3 -3
  130. package/dist/src/automations/draft/automation-draft-validator.d.ts +3 -3
  131. package/dist/src/automations/draft/automation-draft-validator.js +1 -1
  132. package/dist/src/automations/service/action-executor.d.ts +1 -1
  133. package/dist/src/automations/service/action-executor.js +7 -7
  134. package/dist/src/browser/{recipes → automations}/index.d.ts +1 -0
  135. package/dist/src/browser/automations/index.js +4 -0
  136. package/dist/src/browser/automations/repository.d.ts +13 -0
  137. package/dist/src/browser/automations/repository.js +60 -0
  138. package/dist/src/browser/automations/runner.d.ts +17 -0
  139. package/dist/src/browser/automations/runner.js +173 -0
  140. package/dist/src/browser/automations/runtime-service.d.ts +6 -0
  141. package/dist/src/browser/automations/runtime-service.js +37 -0
  142. package/dist/src/browser/automations/schema.d.ts +144 -0
  143. package/dist/src/browser/automations/schema.js +135 -0
  144. package/dist/src/browser/automations/service.d.ts +146 -0
  145. package/dist/src/browser/automations/service.js +168 -0
  146. package/dist/src/browser/automations/types.d.ts +90 -0
  147. package/dist/src/browser/cache-dir-policy.d.ts +1 -1
  148. package/dist/src/browser/cache-dir-policy.js +1 -4
  149. package/dist/src/browser/drivers/browser-driver.d.ts +17 -0
  150. package/dist/src/browser/drivers/create-driver.d.ts +3 -0
  151. package/dist/src/browser/drivers/create-driver.js +84 -0
  152. package/dist/src/browser/drivers/extension-driver.d.ts +20 -0
  153. package/dist/src/browser/drivers/extension-driver.js +47 -0
  154. package/dist/src/browser/drivers/playwright-driver.d.ts +38 -0
  155. package/dist/src/browser/drivers/playwright-driver.js +406 -0
  156. package/dist/src/browser/index.d.ts +10 -15
  157. package/dist/src/browser/index.js +10 -15
  158. package/dist/src/browser/install-lock.d.ts +1 -2
  159. package/dist/src/browser/install-lock.js +3 -9
  160. package/dist/src/browser/install-progress.d.ts +1 -1
  161. package/dist/src/browser/observation/format.d.ts +2 -0
  162. package/dist/src/browser/observation/format.js +26 -0
  163. package/dist/src/browser/policy/approval-store.d.ts +17 -0
  164. package/dist/src/browser/policy/approval-store.js +62 -0
  165. package/dist/src/browser/policy/browser-policy.d.ts +3 -0
  166. package/dist/src/browser/policy/browser-policy.js +27 -0
  167. package/dist/src/browser/providers/browser-ext-install.d.ts +1 -1
  168. package/dist/src/browser/providers/browser-ext-install.js +4 -6
  169. package/dist/src/browser/providers/browser-use.js +1 -1
  170. package/dist/src/browser/providers/browserbase.js +1 -1
  171. package/dist/src/browser/providers/extension-ws-acquire.d.ts +1 -4
  172. package/dist/src/browser/providers/extension-ws-acquire.js +1 -13
  173. package/dist/src/browser/providers/extension.d.ts +3 -22
  174. package/dist/src/browser/providers/extension.js +7 -15
  175. package/dist/src/browser/providers/index.d.ts +2 -2
  176. package/dist/src/browser/providers/index.js +3 -3
  177. package/dist/src/browser/providers/types.d.ts +0 -94
  178. package/dist/src/browser/readiness.d.ts +4 -22
  179. package/dist/src/browser/readiness.js +55 -118
  180. package/dist/src/browser/runtime/browser-runtime.d.ts +30 -0
  181. package/dist/src/browser/runtime/browser-runtime.js +362 -0
  182. package/dist/src/browser/url-policy.d.ts +3 -3
  183. package/dist/src/browser/url-policy.js +7 -6
  184. package/dist/src/browser/verification/expectation.d.ts +2 -0
  185. package/dist/src/browser/verification/expectation.js +17 -0
  186. package/dist/src/cli/command-loaders.js +1 -0
  187. package/dist/src/cli/command-manifest.js +5 -1
  188. package/dist/src/cli/commands/browser-cli-helpers.d.ts +0 -6
  189. package/dist/src/cli/commands/browser-cli-helpers.js +11 -144
  190. package/dist/src/cli/commands/browser.d.ts +0 -5
  191. package/dist/src/cli/commands/browser.js +11 -152
  192. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  193. package/dist/src/cli/commands/doctor/checks/node-version.js +25 -9
  194. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  195. package/dist/src/cli/commands/models.js +1 -1
  196. package/dist/src/cli/commands/platform.d.ts +1 -0
  197. package/dist/src/cli/commands/platform.js +111 -0
  198. package/dist/src/config/index.js +4 -4
  199. package/dist/src/config/loader.js +10 -4
  200. package/dist/src/config/models-json.js +1 -1
  201. package/dist/src/config/schema.d.ts +131 -84
  202. package/dist/src/config/schema.js +112 -59
  203. package/dist/src/connectors/composio-sessions.js +1 -3
  204. package/dist/src/extensions/lockfile.js +1 -1
  205. package/dist/src/extensions/marketplace.js +4 -0
  206. package/dist/src/gateway/agents-admin.js +1 -1
  207. package/dist/src/gateway/file-path-classifier.js +1 -1
  208. package/dist/src/gateway/heartbeat/service.js +1 -1
  209. package/dist/src/gateway/hono/lib/config-payload.d.ts +12 -26
  210. package/dist/src/gateway/hono/lib/config-payload.js +11 -40
  211. package/dist/src/gateway/hono/routes/browser-automations.d.ts +3 -0
  212. package/dist/src/gateway/hono/routes/browser-automations.js +77 -0
  213. package/dist/src/gateway/hono/routes/browser-install.js +0 -32
  214. package/dist/src/gateway/hono/routes/browser.d.ts +0 -17
  215. package/dist/src/gateway/hono/routes/browser.js +46 -568
  216. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -1
  217. package/dist/src/gateway/hono/routes/config.js +0 -11
  218. package/dist/src/gateway/hono/routes/lazy-bundles.js +5 -5
  219. package/dist/src/gateway/hono/routes/models.js +1 -1
  220. package/dist/src/gateway/service/config-coordinator.js +1 -1
  221. package/dist/src/gateway/service.d.ts +4 -6
  222. package/dist/src/gateway/service.js +24 -27
  223. package/dist/src/heartbeat/index.js +1 -1
  224. package/dist/src/platform/client.d.ts +121 -0
  225. package/dist/src/platform/client.js +108 -0
  226. package/dist/src/platform/contracts.d.ts +194 -0
  227. package/dist/src/platform/contracts.js +150 -0
  228. package/dist/src/platform/index.d.ts +4 -0
  229. package/dist/src/platform/index.js +9 -0
  230. package/dist/src/platform/resolution.d.ts +4 -0
  231. package/dist/src/platform/resolution.js +16 -0
  232. package/dist/src/platform/worker.d.ts +6 -0
  233. package/dist/src/platform/worker.js +75 -0
  234. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  235. package/dist/src/providers/index.js +2 -2
  236. package/dist/src/providers/model-registry.js +1 -1
  237. package/dist/src/providers/register-runtime-providers.js +1 -1
  238. package/dist/src/providers/xopc-cloud-config.js +3 -1
  239. package/dist/src/session/session-context-for-llm.js +41 -1
  240. package/dist/src/share/hosted-session-share.js +3 -1
  241. package/dist/src/share/share-thumbnail.js +1 -1
  242. package/dist/src/storage/sqlite/migrations/153_browser_control_v2.sql +45 -0
  243. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  244. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  245. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  246. package/dist/src/storage/sqlite/schema.js +1 -1
  247. package/dist/src/storage/sqlite/schema.sql +16 -20
  248. package/dist/src/tasks/home-query-service.js +1 -1
  249. package/dist/src/tui/tui-startup-resources.js +1 -1
  250. package/dist/src/tui/tui.js +1 -1
  251. package/dist/src/tunnel/env.js +3 -1
  252. package/dist/src/work-discovery/service.js +1 -1
  253. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  254. package/package.json +6 -6
  255. package/dist/gateway/static/root/assets/apps-page-BnizTdgs.js +0 -1
  256. package/dist/gateway/static/root/assets/automations-workspace-CZRKqSqY.js +0 -6
  257. package/dist/gateway/static/root/assets/browser-settings-page-pN5LbChY.js +0 -8
  258. package/dist/gateway/static/root/assets/browser-workflow-inputs-BX1-uM9L.js +0 -1
  259. package/dist/gateway/static/root/assets/browser-workflows-page-C65MI57t.js +0 -3
  260. package/dist/gateway/static/root/assets/capabilities-settings-panel-CJw2e16J.js +0 -7
  261. package/dist/gateway/static/root/assets/channels-settings-CRgjb4Ck.js +0 -1
  262. package/dist/gateway/static/root/assets/connectors-page-Dcpdy06y.js +0 -2
  263. package/dist/gateway/static/root/assets/gateway-config-api-e3BRcgDx.js +0 -1
  264. package/dist/gateway/static/root/assets/gateway-settings-Cheo0Rkc.js +0 -1
  265. package/dist/gateway/static/root/assets/home-page-DVrTRqNc.js +0 -1
  266. package/dist/gateway/static/root/assets/index-B7CX4Qob.css +0 -2
  267. package/dist/gateway/static/root/assets/index-BHrpyJ4t.js +0 -72
  268. package/dist/gateway/static/root/assets/messages-Cf5hpZE6.js +0 -3
  269. package/dist/gateway/static/root/assets/note-detail-panel-CUd8O4K7.js +0 -5
  270. package/dist/gateway/static/root/assets/notes-page-BLQwd39W.js +0 -8
  271. package/dist/gateway/static/root/assets/project-detail-page-NttW338u.js +0 -1
  272. package/dist/gateway/static/root/assets/remote-access-hub-BxpjSDnL.js +0 -1
  273. package/dist/gateway/static/root/assets/sessions-page-BLMaibOb.js +0 -1
  274. package/dist/gateway/static/root/assets/settings-advanced-gate-BRvvKhoH.js +0 -1
  275. package/dist/gateway/static/root/assets/setup-status-panel-DTOsxQC1.js +0 -1
  276. package/dist/gateway/static/root/assets/shares-settings-CemgzEi4.js +0 -1
  277. package/dist/gateway/static/root/assets/skill-reload-api-BWYanBlQ.js +0 -1
  278. package/dist/gateway/static/root/assets/task-detail-page-D0Z_K5JT.js +0 -1
  279. package/dist/gateway/static/root/assets/user-model-page-B_-SNat-.js +0 -2
  280. package/dist/gateway/static/root/assets/workflows-page-CNOT2Coo.js +0 -5
  281. package/dist/src/agent/tools/browser-recipe-tool.d.ts +0 -12
  282. package/dist/src/agent/tools/browser-recipe-tool.js +0 -113
  283. package/dist/src/browser/actions/extension-registry-bridge.d.ts +0 -5
  284. package/dist/src/browser/actions/extension-registry-bridge.js +0 -312
  285. package/dist/src/browser/actions/registry.d.ts +0 -5
  286. package/dist/src/browser/actions/registry.js +0 -741
  287. package/dist/src/browser/actions/types.d.ts +0 -65
  288. package/dist/src/browser/backend-from-config.d.ts +0 -22
  289. package/dist/src/browser/backend-from-config.js +0 -99
  290. package/dist/src/browser/browser-command-timeout.d.ts +0 -2
  291. package/dist/src/browser/browser-command-timeout.js +0 -11
  292. package/dist/src/browser/cdp-local-launcher.d.ts +0 -35
  293. package/dist/src/browser/cdp-local-launcher.js +0 -154
  294. package/dist/src/browser/cdp-supervisor.d.ts +0 -58
  295. package/dist/src/browser/cdp-supervisor.js +0 -133
  296. package/dist/src/browser/humanize.d.ts +0 -80
  297. package/dist/src/browser/humanize.js +0 -363
  298. package/dist/src/browser/manager.d.ts +0 -50
  299. package/dist/src/browser/manager.js +0 -251
  300. package/dist/src/browser/pipeline/output.d.ts +0 -35
  301. package/dist/src/browser/pipeline/output.js +0 -74
  302. package/dist/src/browser/pipeline/runner.d.ts +0 -27
  303. package/dist/src/browser/pipeline/runner.js +0 -453
  304. package/dist/src/browser/pipeline/schema.d.ts +0 -42
  305. package/dist/src/browser/pipeline/schema.js +0 -116
  306. package/dist/src/browser/pipeline/template.d.ts +0 -30
  307. package/dist/src/browser/pipeline/template.js +0 -112
  308. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -83
  309. package/dist/src/browser/providers/cloakbrowser.js +0 -612
  310. package/dist/src/browser/recipes/index.js +0 -3
  311. package/dist/src/browser/recipes/repository.d.ts +0 -13
  312. package/dist/src/browser/recipes/repository.js +0 -81
  313. package/dist/src/browser/recipes/runtime-service.d.ts +0 -6
  314. package/dist/src/browser/recipes/runtime-service.js +0 -30
  315. package/dist/src/browser/recipes/service.d.ts +0 -36
  316. package/dist/src/browser/recipes/service.js +0 -186
  317. package/dist/src/browser/recipes/types.d.ts +0 -36
  318. package/dist/src/browser/schemas.d.ts +0 -53
  319. package/dist/src/browser/schemas.js +0 -68
  320. package/dist/src/browser/session-lifecycle.d.ts +0 -40
  321. package/dist/src/browser/session-lifecycle.js +0 -136
  322. package/dist/src/browser/snapshot-helpers.d.ts +0 -24
  323. package/dist/src/browser/snapshot-helpers.js +0 -70
  324. package/dist/src/browser/stealth.d.ts +0 -46
  325. package/dist/src/browser/stealth.js +0 -163
  326. package/dist/src/gateway/hono/routes/browser-workflows.d.ts +0 -3
  327. package/dist/src/gateway/hono/routes/browser-workflows.js +0 -78
  328. /package/dist/src/browser/{actions → automations}/types.js +0 -0
  329. /package/dist/src/browser/{recipes/types.js → drivers/browser-driver.js} +0 -0
@@ -0,0 +1,30 @@
1
+ import type { BrowserActionInput, BrowserControlResult } from '@xopcai/browser-control-contract';
2
+ import type { Config } from '../../config/schema.js';
3
+ import type { BrowserDriver } from '../drivers/browser-driver.js';
4
+ export interface BrowserRuntimeOptions {
5
+ getConfig: () => Config['browser'];
6
+ createDriver: () => Promise<BrowserDriver>;
7
+ allowedUploadRoots?: string[];
8
+ emit?: (type: string, payload: unknown) => void;
9
+ }
10
+ export declare class BrowserRuntime {
11
+ private readonly options;
12
+ private driver;
13
+ private sessionsByTask;
14
+ constructor(options: BrowserRuntimeOptions);
15
+ execute(taskKey: string, input: BrowserActionInput, signal?: AbortSignal): Promise<BrowserControlResult>;
16
+ shutdown(): Promise<void>;
17
+ closeTaskSession(taskKey: string): Promise<void>;
18
+ private dispatch;
19
+ private executeSequence;
20
+ private authorize;
21
+ private validateUrl;
22
+ private validateRedirect;
23
+ private blockedRedirect;
24
+ private crossDomainPolicy;
25
+ private invalidUploadPath;
26
+ private resolveSession;
27
+ private getDriver;
28
+ private constrainResult;
29
+ private evictExpiredSessions;
30
+ }
@@ -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>;