@xopcai/xopc 0.0.367 → 0.0.369

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 (263) hide show
  1. package/dist/browser-ext/_locales/en/messages.json +30 -1
  2. package/dist/browser-ext/_locales/zh_CN/messages.json +30 -1
  3. package/dist/browser-ext/dist/assets/{auth-beGtbLPS.js → page-context-BeworyNB.js} +1331 -1355
  4. package/dist/browser-ext/dist/assets/{sidepanel-BT0ojEzG.css → sidepanel-Ccl0eSa1.css} +43 -0
  5. package/dist/browser-ext/dist/background.js +680 -182
  6. package/dist/browser-ext/dist/sidepanel.html +2 -2
  7. package/dist/browser-ext/dist/sidepanel.js +372 -193
  8. package/dist/browser-ext/manifest.json +2 -8
  9. package/dist/extensions/telegram/xopc.extension.json +1 -1
  10. package/dist/gateway/static/root/assets/{activity-store-Cuf3JFFJ.js → activity-store-BQ3PMp2q.js} +1 -1
  11. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DyATPNTe.js → agent-avatar-dicebear-Stj17S9u.js} +1 -1
  12. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CCRfvuov.js +1 -0
  13. package/dist/gateway/static/root/assets/agent-plugin-dialog-CRlzd8El.js +1 -0
  14. package/dist/gateway/static/root/assets/agents-_ug2LCQb.js +66 -0
  15. package/dist/gateway/static/root/assets/{agents-admin-api-D842OcNo.js → agents-admin-api-HBZvVyzF.js} +1 -1
  16. package/dist/gateway/static/root/assets/app-management-settings-panel-pJFe6M6c.js +1 -0
  17. package/dist/gateway/static/root/assets/{appearance-settings-DQr0o6Lm.js → appearance-settings-BrxSpBWa.js} +1 -1
  18. package/dist/gateway/static/root/assets/{apps-page-CltMV4Xp.js → apps-page-DegSl5Lh.js} +1 -1
  19. package/dist/gateway/static/root/assets/{archive-plugin-DT8Nio-r.js → archive-plugin-BO3I9zRP.js} +1 -1
  20. package/dist/gateway/static/root/assets/{automations-page-BIfWS_3Y.js → automations-page-BZQ_VHjp.js} +1 -1
  21. package/dist/gateway/static/root/assets/automations-workspace-BQywN6nG.js +6 -0
  22. package/dist/gateway/static/root/assets/{binary-plugins-7qs3qcW9.js → binary-plugins-gFD7vH9R.js} +1 -1
  23. package/dist/gateway/static/root/assets/{block-editor-BFPUlxJ6.js → block-editor-3XjFv3kK.js} +28 -28
  24. package/dist/gateway/static/root/assets/browser-automation-inputs-DxRoKFun.js +1 -0
  25. package/dist/gateway/static/root/assets/browser-automations-page-yiEuG1v7.js +3 -0
  26. package/dist/gateway/static/root/assets/browser-settings-page-ch2_bQF0.js +3 -0
  27. package/dist/gateway/static/root/assets/{capabilities-K0Zb_lH0.js → capabilities-B48r0DDa.js} +1 -1
  28. package/dist/gateway/static/root/assets/{capabilities-BzWFO_x_.js → capabilities-DO-vfNKI.js} +1 -1
  29. package/dist/gateway/static/root/assets/capabilities-page-BEnFt_dj.js +2 -0
  30. package/dist/gateway/static/root/assets/capabilities-settings-panel-NckMsJ5N.js +8 -0
  31. package/dist/gateway/static/root/assets/{capability-header-actions-AMn_vTNv.js → capability-header-actions-CY8KCO9j.js} +1 -1
  32. package/dist/gateway/static/root/assets/channels-CHOS2CGa.js +1 -0
  33. package/dist/gateway/static/root/assets/{chat-terminal-dock-C7nAROhF.js → chat-terminal-dock-Bwknnb4c.js} +2 -2
  34. package/dist/gateway/static/root/assets/computer-settings-page-B2xeFCSt.js +1 -0
  35. package/dist/gateway/static/root/assets/{connector-service-page-CTx1B8wx.js → connector-service-page-C83DnAqK.js} +1 -1
  36. package/dist/gateway/static/root/assets/connectors-page-D6wTmWA6.js +2 -0
  37. package/dist/gateway/static/root/assets/{date-picker-Cx_xIKvN.js → date-picker-Bq9GR-DU.js} +1 -1
  38. package/dist/gateway/static/root/assets/{dependency-picker-DYm96PDu.js → dependency-picker-BTERkA9X.js} +1 -1
  39. package/dist/gateway/static/root/assets/{desktop-pet-D90OzgeR.js → desktop-pet-BwsbQw8V.js} +1 -1
  40. package/dist/gateway/static/root/assets/{desktop-pet-settings-CmdCecjm.js → desktop-pet-settings-sL9i44pP.js} +1 -1
  41. package/dist/gateway/static/root/assets/device-pairing-wizard-DI2bqaKO.js +1 -0
  42. package/dist/gateway/static/root/assets/{directory-picker-path-field-DZpaoeNa.js → directory-picker-path-field-BFlDmsS5.js} +1 -1
  43. package/dist/gateway/static/root/assets/{extension-debug-page-Bv6QE8kC.js → extension-debug-page-7Z1Tp7-w.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-page-CEsq71Cm.js → extension-page-uGqvb8QX.js} +1 -1
  45. package/dist/gateway/static/root/assets/{extension-provider-CX-sK0Tw.js → extension-provider-xlSyz4Z6.js} +1 -1
  46. package/dist/gateway/static/root/assets/{extension-settings-page-UyOHF39P.js → extension-settings-page-CKHgrjOs.js} +1 -1
  47. package/dist/gateway/static/root/assets/{fallback-models-CKv_Wqg8.js → fallback-models-BwQg0G1D.js} +1 -1
  48. package/dist/gateway/static/root/assets/{gateway-config-swr-Cjnkle5J.js → gateway-config-swr-7RKqgU_U.js} +1 -1
  49. package/dist/gateway/static/root/assets/{gateway-realtime-DCCLdyQD.js → gateway-realtime-DDWymi-o.js} +1 -1
  50. package/dist/gateway/static/root/assets/gateway-realtime-store-BheKaO6d.js +1 -0
  51. package/dist/gateway/static/root/assets/gateway-settings-BAQnSEMJ.js +1 -0
  52. package/dist/gateway/static/root/assets/{gateway-startup-retry-CXKmdVzN.js → gateway-startup-retry-jiV5sbEX.js} +1 -1
  53. package/dist/gateway/static/root/assets/home-page-BZDjvwet.js +2 -0
  54. package/dist/gateway/static/root/assets/{image-generation-api-NLHzm4Nc.js → image-generation-api-DO4mXb6I.js} +1 -1
  55. package/dist/gateway/static/root/assets/{imports-page-C7qvlBTQ.js → imports-page-re1_Nh64.js} +1 -1
  56. package/dist/gateway/static/root/assets/index-BB1z8QxA.js +106 -0
  57. package/dist/gateway/static/root/assets/index-D9R6tU7r.css +1 -0
  58. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-pkgFWJb-.js → keyboard-shortcuts-settings-B_xja9LN.js} +1 -1
  59. package/dist/gateway/static/root/assets/{local-app-workbench-page-dMDhZXAi.js → local-app-workbench-page-CErdCrPX.js} +1 -1
  60. package/dist/gateway/static/root/assets/{local-apps-page-TpUAfOn2.js → local-apps-page-BPL2RXdK.js} +1 -1
  61. package/dist/gateway/static/root/assets/{local-session-drafts-Cvv7I0fw.js → local-session-drafts-DRPsDCj1.js} +1 -1
  62. package/dist/gateway/static/root/assets/{locale-store-C8TMD2gn.js → locale-store-COVscAqC.js} +1 -1
  63. package/dist/gateway/static/root/assets/logs-page-DL-BM0xq.js +2 -0
  64. package/dist/gateway/static/root/assets/management-settings-BOVRHhXk.js +1 -0
  65. package/dist/gateway/static/root/assets/{markdown-view-Dse7rkio.js → markdown-view-B_qnAcW2.js} +1 -1
  66. package/dist/gateway/static/root/assets/{media-plugins-BZrnzaBM.js → media-plugins-C0Pc-wSY.js} +1 -1
  67. package/dist/gateway/static/root/assets/messages-Bb2GK-Nj.js +3 -0
  68. package/dist/gateway/static/root/assets/models-hub-cache-DyPPksMP.js +1 -0
  69. package/dist/gateway/static/root/assets/note-detail-panel-DJJK2yL4.js +5 -0
  70. package/dist/gateway/static/root/assets/{notes-api-DKiVeQKG.js → notes-api-sBgBcyLW.js} +1 -1
  71. package/dist/gateway/static/root/assets/notes-page-oCxO7ZTv.js +8 -0
  72. package/dist/gateway/static/root/assets/{page-context-capture-button-Cxzd4QPB.js → page-context-capture-button-tf77xIz3.js} +1 -1
  73. package/dist/gateway/static/root/assets/personal-page-DOk9gUK5.js +1 -0
  74. package/dist/gateway/static/root/assets/{product-open-page-D4hoEWiu.js → product-open-page-Dc3Y-Y7J.js} +1 -1
  75. package/dist/gateway/static/root/assets/{product-preview-content-aR38El2E.js → product-preview-content-MG_hmVA3.js} +1 -1
  76. package/dist/gateway/static/root/assets/{project-detail-page-D20QH4YB.js → project-detail-page-3uAzbW4T.js} +1 -1
  77. package/dist/gateway/static/root/assets/{projects-page-Bf3BIcT6.js → projects-page-MllfNLGA.js} +1 -1
  78. package/dist/gateway/static/root/assets/{registry-api-AdnxowbH.js → registry-api-Bh9UBb-f.js} +1 -1
  79. package/dist/gateway/static/root/assets/remote-access-hub-Bs-C70el.js +1 -0
  80. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CBN3raz1.js → runtime-tools-settings-panel-DpJ5jNzR.js} +1 -1
  81. package/dist/gateway/static/root/assets/scenes-page-Dpxamkw6.js +2 -0
  82. package/dist/gateway/static/root/assets/{schema-form-CxrMGsT9.js → schema-form-DUeyQ1zh.js} +1 -1
  83. package/dist/gateway/static/root/assets/{send-session-input-CgOzhDZ0.js → send-session-input-Dgn4BRk_.js} +1 -1
  84. package/dist/gateway/static/root/assets/{session-api-_HIN8or3.js → session-api-yjpEz4pP.js} +1 -1
  85. package/dist/gateway/static/root/assets/{session-manager-CzCto5zT.js → session-manager-LInoZ_Yi.js} +1 -1
  86. package/dist/gateway/static/root/assets/sessions-page-BCVlNHtq.js +1 -0
  87. package/dist/gateway/static/root/assets/settings-advanced-gate-Bz-ue9fZ.js +1 -0
  88. package/dist/gateway/static/root/assets/{settings-page-D8Q3H3-o.js → settings-page-DouHuBXt.js} +1 -1
  89. package/dist/gateway/static/root/assets/{setup-status-panel-DvLMMiuS.js → setup-status-panel-B5BoZ-1y.js} +1 -1
  90. package/dist/gateway/static/root/assets/{share-link-dialog-Dg5os066.js → share-link-dialog-DJTabLAM.js} +1 -1
  91. package/dist/gateway/static/root/assets/{share-preview-page-DMvohAyr.js → share-preview-page-jw7h4t_B.js} +1 -1
  92. package/dist/gateway/static/root/assets/{shares-api-C96IO4qJ.js → shares-api-c0dfWz6h.js} +1 -1
  93. package/dist/gateway/static/root/assets/shares-settings-BlnlzGjH.js +1 -0
  94. package/dist/gateway/static/root/assets/{skill-api-C10ML0CH.js → skill-api-CfyX_0zN.js} +1 -1
  95. package/dist/gateway/static/root/assets/{skill-reload-api-DNbJzSfB.js → skill-reload-api-Ge5XymHa.js} +1 -1
  96. package/dist/gateway/static/root/assets/{skills-page-DObMKvA6.js → skills-page-DjdTeYzm.js} +1 -1
  97. package/dist/gateway/static/root/assets/system-settings-panel-DWf256TE.js +1 -0
  98. package/dist/gateway/static/root/assets/{task-detail-page-BR2L1L8l.js → task-detail-page-DE6N1ZQe.js} +2 -2
  99. package/dist/gateway/static/root/assets/{task-expandable-content-DL2Q2gre.js → task-expandable-content-hYcgCEE3.js} +1 -1
  100. package/dist/gateway/static/root/assets/{theme-store-DQ6KJa4l.js → theme-store-BOfCKgl6.js} +1 -1
  101. package/dist/gateway/static/root/assets/{tracing-settings-page-Ed8_GYUT.js → tracing-settings-page-DDWFXcST.js} +1 -1
  102. package/dist/gateway/static/root/assets/{tunnel-api-D3X8jDwo.js → tunnel-api-BBm9esrY.js} +1 -1
  103. package/dist/gateway/static/root/assets/{usage-page-BqzRyyb9.js → usage-page-C93x89uW.js} +1 -1
  104. package/dist/gateway/static/root/assets/{use-autosave-CRFefpzO.js → use-autosave-CSckcjFx.js} +1 -1
  105. package/dist/gateway/static/root/assets/{use-composer-attachments-OLrvSjn5.js → use-composer-attachments-C7Gaaai1.js} +1 -1
  106. package/dist/gateway/static/root/assets/{use-file-preview-expanded-CJvzfQvw.js → use-file-preview-expanded-Db2VYg1b.js} +2 -2
  107. package/dist/gateway/static/root/assets/user-model-page-B74LkVbp.js +2 -0
  108. package/dist/gateway/static/root/assets/{voice-api-key-field-R9zNWYR_.js → voice-api-key-field-GEw5x2fU.js} +1 -1
  109. package/dist/gateway/static/root/assets/{voice-config-api-DLudE9Rc.js → voice-config-api-3yyVwXln.js} +1 -1
  110. package/dist/gateway/static/root/assets/{work-discovery-overlay-DVmQrolV.js → work-discovery-overlay-Bs2MKiTv.js} +1 -1
  111. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DEkmuD3T.js → workflow-run-setup-panel-BR_U_snV.js} +2 -2
  112. package/dist/gateway/static/root/assets/{workflows-page-pqCB3sh4.js → workflows-page-Crk4SxtC.js} +3 -3
  113. package/dist/gateway/static/root/assets/{workspace-api-CdVUhyPo.js → workspace-api-Si2o3inw.js} +2 -2
  114. package/dist/gateway/static/root/index.html +27 -28
  115. package/dist/package.js +1 -1
  116. package/dist/packages/browser-control-contract/src/automation.js +213 -0
  117. package/dist/packages/browser-control-contract/src/index.js +43 -12
  118. package/dist/packages/gateway-contract/src/gateway-scopes.js +3 -1
  119. package/dist/packages/gateway-contract/src/notifications.js +1 -0
  120. package/dist/packages/realtime-protocol/src/voice-catalog.js +7 -1
  121. package/dist/packages/realtime-protocol/src/voice.js +9 -3
  122. package/dist/src/agent/coding/repository-instructions.js +8 -1
  123. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  124. package/dist/src/agent/tool-manuals/browser.js +3 -3
  125. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -1
  126. package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -13
  127. package/dist/src/agent/tools/browser/tool/schemas.js +0 -4
  128. package/dist/src/agent/tools/browser-automation-tool.d.ts +74 -1
  129. package/dist/src/agent/tools/browser-automation-tool.js +52 -6
  130. package/dist/src/agent-config/schema.d.ts +1 -1
  131. package/dist/src/agent-config/schema.js +1 -1
  132. package/dist/src/automations/capabilities/write.d.ts +2 -0
  133. package/dist/src/automations/domain/types.d.ts +11 -0
  134. package/dist/src/automations/domain/validation.d.ts +4 -0
  135. package/dist/src/automations/domain/validation.js +1 -0
  136. package/dist/src/automations/draft/automation-draft-validator.d.ts +1 -0
  137. package/dist/src/automations/service/action-executor.js +11 -3
  138. package/dist/src/automations/service/automation-service.d.ts +1 -0
  139. package/dist/src/automations/service/automation-service.js +13 -1
  140. package/dist/src/bootstrap/application-state.js +3 -1
  141. package/dist/src/browser/automations/repository.d.ts +4 -0
  142. package/dist/src/browser/automations/repository.js +27 -6
  143. package/dist/src/browser/automations/runner.js +101 -9
  144. package/dist/src/browser/automations/runtime-service.js +4 -3
  145. package/dist/src/browser/automations/schema.d.ts +84 -1
  146. package/dist/src/browser/automations/schema.js +68 -2
  147. package/dist/src/browser/automations/service.d.ts +78 -1
  148. package/dist/src/browser/automations/service.js +36 -4
  149. package/dist/src/browser/automations/types.d.ts +19 -4
  150. package/dist/src/browser/drivers/extension-driver.d.ts +5 -5
  151. package/dist/src/browser/drivers/extension-driver.js +10 -10
  152. package/dist/src/browser/drivers/playwright-driver.js +46 -0
  153. package/dist/src/browser/index.d.ts +1 -2
  154. package/dist/src/browser/index.js +2 -3
  155. package/dist/src/browser/policy/browser-policy.d.ts +0 -1
  156. package/dist/src/browser/policy/browser-policy.js +1 -4
  157. package/dist/src/browser/providers/index.d.ts +1 -1
  158. package/dist/src/browser/providers/index.js +2 -2
  159. package/dist/src/browser/providers/realtime-extension.d.ts +1 -1
  160. package/dist/src/browser/providers/realtime-extension.js +5 -1
  161. package/dist/src/browser/recordings/service.d.ts +22 -0
  162. package/dist/src/browser/recordings/service.js +160 -0
  163. package/dist/src/browser/runtime/browser-runtime.d.ts +1 -1
  164. package/dist/src/browser/runtime/browser-runtime.js +19 -56
  165. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  166. package/dist/src/computer/runtime.js +2 -2
  167. package/dist/src/config/schema.d.ts +12 -12
  168. package/dist/src/config/schema.js +12 -12
  169. package/dist/src/endpoint-tools/policy.js +4 -3
  170. package/dist/src/gateway/hono/routes/browser-automations.js +23 -7
  171. package/dist/src/gateway/hono/routes/browser-recordings.d.ts +3 -0
  172. package/dist/src/gateway/hono/routes/browser-recordings.js +78 -0
  173. package/dist/src/gateway/hono/routes/browser.js +1 -34
  174. package/dist/src/gateway/hono/routes/device-push.js +1 -0
  175. package/dist/src/gateway/hono/routes/home.js +1 -1
  176. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  177. package/dist/src/gateway/hono/routes/personal-agent.js +35 -0
  178. package/dist/src/gateway/hono/routes/voice.js +5 -2
  179. package/dist/src/gateway/security/gateway-scopes.js +3 -1
  180. package/dist/src/gateway/service/agent-runner.js +1 -0
  181. package/dist/src/home-intelligence/generator.d.ts +2 -0
  182. package/dist/src/home-intelligence/generator.js +53 -4
  183. package/dist/src/home-intelligence/host.d.ts +2 -1
  184. package/dist/src/home-intelligence/host.js +23 -3
  185. package/dist/src/migrations/cloud-public-models.d.ts +7 -0
  186. package/dist/src/migrations/cloud-public-models.js +157 -0
  187. package/dist/src/notifications/clarification.d.ts +5 -0
  188. package/dist/src/notifications/clarification.js +66 -0
  189. package/dist/src/notifications/device-store.js +1 -0
  190. package/dist/src/notifications/harmony-push.d.ts +1 -0
  191. package/dist/src/notifications/harmony-push.js +3 -1
  192. package/dist/src/notifications/planner.d.ts +1 -0
  193. package/dist/src/notifications/service.d.ts +2 -2
  194. package/dist/src/notifications/service.js +20 -4
  195. package/dist/src/notifications/store.d.ts +2 -0
  196. package/dist/src/notifications/store.js +7 -1
  197. package/dist/src/notifications/types.d.ts +1 -0
  198. package/dist/src/notifications/types.js +1 -0
  199. package/dist/src/providers/model-catalog-persistence.js +2 -2
  200. package/dist/src/providers/presentation.js +1 -0
  201. package/dist/src/providers/xopc-cloud-model-source.js +1 -1
  202. package/dist/src/storage/sqlite/clarification-wait-repository.js +1 -0
  203. package/dist/src/storage/sqlite/migrations/238_browser_record_replay.sql +45 -0
  204. package/dist/src/storage/sqlite/migrations/239_clarification_notifications.sql +26 -0
  205. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  206. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  207. package/dist/src/storage/sqlite/schema.js +1 -1
  208. package/dist/src/tasks/home-query-service.d.ts +1 -1
  209. package/dist/src/tasks/home-query-service.js +6 -2
  210. package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +2 -1
  211. package/dist/src/voice/dashscope/streaming-tts-stream.js +135 -79
  212. package/dist/src/voice/metadata/types.d.ts +1 -0
  213. package/dist/src/voice/platform-catalog.d.ts +4 -0
  214. package/dist/src/voice/platform-settings.js +1 -0
  215. package/dist/src/voice/realtime/agentEngine.js +78 -1
  216. package/dist/src/voice/realtime/speakable-segmenter.d.ts +2 -0
  217. package/dist/src/voice/realtime/speakable-segmenter.js +30 -0
  218. package/dist/src/voice/tts/providers/alibaba-speech.js +17 -1
  219. package/dist/src/voice/tts/providers/xopc-cloud-speech.js +3 -2
  220. package/dist/src/voice/tts/speak-core.d.ts +3 -0
  221. package/dist/src/voice/tts/speak-core.js +21 -1
  222. package/dist/src/voice/tts/speech-provider-types.d.ts +8 -0
  223. package/package.json +3 -3
  224. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-gT9_j4tr.js +0 -1
  225. package/dist/gateway/static/root/assets/agent-plugin-dialog-CLXCJ6JN.js +0 -1
  226. package/dist/gateway/static/root/assets/agents-BAUfOMsq.js +0 -66
  227. package/dist/gateway/static/root/assets/app-management-settings-panel-CoIFxQKH.js +0 -1
  228. package/dist/gateway/static/root/assets/automations-workspace-BCGPjsdU.js +0 -6
  229. package/dist/gateway/static/root/assets/browser-automation-inputs-BUAIKIX0.js +0 -1
  230. package/dist/gateway/static/root/assets/browser-automations-page-CSwu1U1F.js +0 -3
  231. package/dist/gateway/static/root/assets/browser-settings-page-C1ReMNqX.js +0 -3
  232. package/dist/gateway/static/root/assets/capabilities-page-BdTSqloI.js +0 -2
  233. package/dist/gateway/static/root/assets/capabilities-settings-panel-BUblBMZC.js +0 -8
  234. package/dist/gateway/static/root/assets/channels-CXCf5qO6.js +0 -1
  235. package/dist/gateway/static/root/assets/computer-settings-page-B5SuSZ3G.js +0 -1
  236. package/dist/gateway/static/root/assets/connectors-page-DfnK1crf.js +0 -2
  237. package/dist/gateway/static/root/assets/device-pairing-wizard-s2ogSa4l.js +0 -1
  238. package/dist/gateway/static/root/assets/gateway-realtime-store-C_Th8kGg.js +0 -1
  239. package/dist/gateway/static/root/assets/gateway-settings-CZ73IpbP.js +0 -1
  240. package/dist/gateway/static/root/assets/home-page-BQWq4kYi.js +0 -2
  241. package/dist/gateway/static/root/assets/index-BQgqzhQj.js +0 -106
  242. package/dist/gateway/static/root/assets/index-COB4QIJp.css +0 -1
  243. package/dist/gateway/static/root/assets/logs-page-B-Y9oZLh.js +0 -2
  244. package/dist/gateway/static/root/assets/management-settings-B2lzsw6X.js +0 -1
  245. package/dist/gateway/static/root/assets/messages-Dy26npMy.js +0 -3
  246. package/dist/gateway/static/root/assets/models-hub-cache-B1C86nRp.js +0 -1
  247. package/dist/gateway/static/root/assets/note-detail-panel-DL__qP6U.js +0 -5
  248. package/dist/gateway/static/root/assets/notes-page-DTBbg9Hs.js +0 -8
  249. package/dist/gateway/static/root/assets/oauth-api-BwpzpRwC.js +0 -1
  250. package/dist/gateway/static/root/assets/personal-page-CzaTnHeD.js +0 -1
  251. package/dist/gateway/static/root/assets/remote-access-hub-CKxqncqW.js +0 -1
  252. package/dist/gateway/static/root/assets/scenes-page-Cv_5ozfX.js +0 -2
  253. package/dist/gateway/static/root/assets/sessions-page-DZcu6NLJ.js +0 -1
  254. package/dist/gateway/static/root/assets/settings-advanced-gate-DazqeDQ7.js +0 -1
  255. package/dist/gateway/static/root/assets/shares-settings-CsDATuCw.js +0 -1
  256. package/dist/gateway/static/root/assets/system-settings-panel-Bn3khdzb.js +0 -1
  257. package/dist/gateway/static/root/assets/user-model-page-CG6wqIKP.js +0 -2
  258. package/dist/src/browser/policy/approval-store.d.ts +0 -17
  259. package/dist/src/browser/policy/approval-store.js +0 -62
  260. package/dist/src/browser/providers/extension-ws-acquire.d.ts +0 -19
  261. package/dist/src/browser/providers/extension-ws-acquire.js +0 -78
  262. package/dist/src/browser/providers/extension.d.ts +0 -61
  263. package/dist/src/browser/providers/extension.js +0 -378
@@ -1,6 +1,5 @@
1
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";
2
+ import { classifyBrowserRisk } from "../policy/browser-policy.js";
4
3
  import { isAbsolute, relative, resolve } from "node:path";
5
4
  import { randomUUID } from "node:crypto";
6
5
  //#region src/browser/runtime/browser-runtime.ts
@@ -94,10 +93,7 @@ var BrowserRuntime = class {
94
93
  if (input.action === "navigate") {
95
94
  const blocked = this.validateUrl(input.url);
96
95
  if (blocked) return failure("BLOCKED_URL", blocked);
97
- const crossDomainPolicy = this.crossDomainPolicy(session.observation?.url, input.url);
98
- if (crossDomainPolicy === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
99
- const authorization = this.authorize(session.taskKey, input, crossDomainPolicy === "ask" ? "external_effect" : "read", crossDomainPolicy);
100
- if (authorization) return authorization;
96
+ if (this.crossDomainPolicy(session.observation?.url, input.url) === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
101
97
  const result = await driver.navigate(session.id, input, signal);
102
98
  return this.validateRedirect(input.url, result);
103
99
  }
@@ -105,10 +101,7 @@ var BrowserRuntime = class {
105
101
  if (input.url) {
106
102
  const blocked = this.validateUrl(input.url);
107
103
  if (blocked) return failure("BLOCKED_URL", blocked);
108
- const crossDomainPolicy = this.crossDomainPolicy(session.observation?.url, input.url);
109
- if (crossDomainPolicy === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
110
- const authorization = this.authorize(session.taskKey, input, crossDomainPolicy === "ask" ? "external_effect" : "read", crossDomainPolicy);
111
- if (authorization) return authorization;
104
+ if (this.crossDomainPolicy(session.observation?.url, input.url) === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
112
105
  }
113
106
  const result = await driver.tabs(session.id, input, signal);
114
107
  if (!input.url || !result.ok) return result;
@@ -117,15 +110,21 @@ var BrowserRuntime = class {
117
110
  return blocked ? failure("BLOCKED_URL", blocked) : result;
118
111
  }
119
112
  if (input.action === "sequence") return this.executeSequence(driver, session, input, signal);
113
+ if (input.action === "resolve") return driver.perform(session.id, input, signal);
120
114
  const target = findActionTarget(input, session.observation);
121
115
  const risk = classifyBrowserRisk(input, target);
122
116
  if (input.action === "upload") {
123
117
  const invalidPath = this.invalidUploadPath(input.paths);
124
118
  if (invalidPath) return failure("INVALID_INPUT", invalidPath);
125
119
  }
126
- const authorization = this.authorize(session.taskKey, input, risk, void 0, target);
127
- if (authorization) return authorization;
128
- return withRisk(await driver.perform(session.id, input, signal), risk);
120
+ if (this.actionDenied(input, risk)) return failure("INVALID_INPUT", `Browser action is denied by policy (${risk}).`);
121
+ if (input.action === "click" && target?.href) {
122
+ const blocked = this.validateUrl(target.href);
123
+ if (blocked) return failure("BLOCKED_URL", blocked);
124
+ if (this.crossDomainPolicy(session.observation?.url, target.href) === "deny") return failure("BLOCKED_URL", "Cross-domain navigation is denied by policy.");
125
+ }
126
+ const result = await driver.perform(session.id, input, signal);
127
+ return withRisk(this.validateRedirect(session.observation?.url ?? "", result), risk);
129
128
  }
130
129
  async executeSequence(driver, session, input, signal) {
131
130
  const config = this.options.getConfig();
@@ -138,8 +137,7 @@ var BrowserRuntime = class {
138
137
  const risk = classifyBrowserRisk(step, findActionTarget(step, session.observation));
139
138
  if (riskRank(risk) > riskRank(highestRisk)) highestRisk = risk;
140
139
  }
141
- const authorization = this.authorize(session.taskKey, input, highestRisk);
142
- if (authorization) return authorization;
140
+ if (this.actionDenied(input, highestRisk)) return failure("INVALID_INPUT", `Browser action is denied by policy (${highestRisk}).`);
143
141
  for (const step of input.steps) {
144
142
  const primitive = {
145
143
  ...step,
@@ -165,27 +163,13 @@ var BrowserRuntime = class {
165
163
  }
166
164
  };
167
165
  }
168
- authorize(conversationId, input, risk, explicitPolicy, target) {
166
+ actionDenied(input, risk) {
169
167
  const security = this.options.getConfig().security;
170
- const policy = explicitPolicy ?? (input.action === "upload" ? security.uploads : security.consequentialActions);
171
- if (!browserRiskNeedsApproval(risk) || policy === "allow") return null;
172
- if (policy === "deny") return failure("APPROVAL_REQUIRED", `Browser action is denied by policy (${risk}).`);
173
- if (consumeBrowserApproval(input.approvalId, conversationId, input)) return null;
174
- const approval = createBrowserApproval(conversationId, input, risk, browserApprovalSummary(input, target));
175
- this.options.emit?.("browser.approval.required", approval);
176
- return {
177
- ok: false,
178
- error: {
179
- code: "APPROVAL_REQUIRED",
180
- message: "This browser action needs local-owner approval before it can run.",
181
- approval: {
182
- id: approval.id,
183
- risk,
184
- summary: approval.summary,
185
- expiresAt: approval.expiresAt
186
- }
187
- }
188
- };
168
+ return (input.action === "upload" ? security.uploads : security.consequentialActions) === "deny" && [
169
+ "external_effect",
170
+ "destructive",
171
+ "sensitive"
172
+ ].includes(risk);
189
173
  }
190
174
  validateUrl(url) {
191
175
  if (containsApiKeyPattern(url)) return "URL contains a credential-like value.";
@@ -338,27 +322,6 @@ function findActionTarget(input, observation) {
338
322
  const ref = "ref" in input && input.ref ? input.ref : input.action === "press" ? observation?.focused : void 0;
339
323
  return ref ? observation?.nodes.find((node) => node.ref === ref) : void 0;
340
324
  }
341
- function browserApprovalSummary(input, target) {
342
- const targetName = target?.name.trim() ? ` “${target.name.slice(0, 120)}”` : "";
343
- switch (input.action) {
344
- case "navigate": return `Navigate to ${safeUrlLabel(input.url)}.`;
345
- case "tabs": return input.url ? `Open a tab at ${safeUrlLabel(input.url)}.` : `Change browser tabs (${input.operation}).`;
346
- case "click": return `Click${targetName || ` element ${input.ref}`}.`;
347
- case "fill": return `${target?.states.includes("sensitive") ? "Fill a sensitive field" : "Fill field"}${targetName || ` ${input.ref}`}${input.submit ? " and submit the form" : ""}.`;
348
- case "upload": return `Upload ${input.paths.length} file${input.paths.length === 1 ? "" : "s"}${targetName ? ` using${targetName}` : ""}.`;
349
- case "press": return `Press ${input.key}${targetName ? ` on${targetName}` : ""}.`;
350
- case "sequence": return `Run ${input.steps.length} browser actions as one sequence.`;
351
- default: return `Run browser action “${input.action}”${targetName ? ` on${targetName}` : ""}.`;
352
- }
353
- }
354
- function safeUrlLabel(raw) {
355
- try {
356
- const url = new URL(raw);
357
- return `${url.origin}${url.pathname}`.slice(0, 240);
358
- } catch {
359
- return "the requested URL";
360
- }
361
- }
362
325
  function withoutVisual(value) {
363
326
  if (!value || typeof value !== "object") return value;
364
327
  return JSON.parse(JSON.stringify(value, (key, child) => key === "visual" ? void 0 : child));
@@ -53,7 +53,7 @@ async function checkDatabaseSchema(ctx) {
53
53
  id: "database-schema",
54
54
  label: "Database schema",
55
55
  status: "pass",
56
- message: `SQLite schema v${status.dbVersion} (current release v237).`,
56
+ message: `SQLite schema v${status.dbVersion} (current release v239).`,
57
57
  hints: []
58
58
  };
59
59
  }
@@ -173,7 +173,7 @@ var ComputerRuntime = class {
173
173
  const metadata = (await readComputerJson(response, 2 * 1024 * 1024)).data?.find((item) => item.id === model.id)?.xopc;
174
174
  const parsedDeployment = z.object({
175
175
  revision: z.string().regex(/^[a-f0-9]{64}$/),
176
- origin: z.string().url()
176
+ origin: z.string().url().optional()
177
177
  }).safeParse(metadata?.computerDeployment);
178
178
  const parsedLimits = ComputerServiceLimitsSchema.optional().safeParse(metadata?.computerLimits);
179
179
  if (!parsedDeployment.success || !parsedLimits.success) throw new Error("COMPUTER_DEPLOYMENT_UNAVAILABLE");
@@ -204,7 +204,7 @@ var ComputerRuntime = class {
204
204
  profile,
205
205
  origin: new URL(model.baseUrl).origin,
206
206
  runtimeLocation: "unknown",
207
- ...deployment ? { upstreamOrigin: deployment.origin } : {}
207
+ ...deployment?.origin ? { upstreamOrigin: deployment.origin } : {}
208
208
  },
209
209
  createdAt: Date.now(),
210
210
  actions: 0,
@@ -87,21 +87,21 @@ export declare const BrowserConfigSchema: z.ZodDefault<z.ZodObject<{
87
87
  security: z.ZodDefault<z.ZodObject<{
88
88
  privateNetworks: z.ZodDefault<z.ZodLiteral<"deny">>;
89
89
  allowedPrivateHosts: z.ZodDefault<z.ZodArray<z.ZodString>>;
90
- crossDomainNavigation: z.ZodDefault<z.ZodEnum<{
90
+ crossDomainNavigation: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
91
91
  allow: "allow";
92
92
  deny: "deny";
93
93
  ask: "ask";
94
- }>>;
95
- uploads: z.ZodDefault<z.ZodEnum<{
94
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
95
+ uploads: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
96
96
  allow: "allow";
97
97
  deny: "deny";
98
98
  ask: "ask";
99
- }>>;
100
- consequentialActions: z.ZodDefault<z.ZodEnum<{
99
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
100
+ consequentialActions: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
101
101
  allow: "allow";
102
102
  deny: "deny";
103
103
  ask: "ask";
104
- }>>;
104
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
105
105
  }, z.core.$strict>>;
106
106
  }, z.core.$strict>>;
107
107
  export { TelegramTopicConfigSchema, TelegramGroupConfigSchema, TelegramAccountConfigSchema, TelegramConfigSchema, } from '../../extensions/telegram/src/config-schema.js';
@@ -1611,21 +1611,21 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
1611
1611
  security: z.ZodDefault<z.ZodObject<{
1612
1612
  privateNetworks: z.ZodDefault<z.ZodLiteral<"deny">>;
1613
1613
  allowedPrivateHosts: z.ZodDefault<z.ZodArray<z.ZodString>>;
1614
- crossDomainNavigation: z.ZodDefault<z.ZodEnum<{
1614
+ crossDomainNavigation: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
1615
1615
  allow: "allow";
1616
1616
  deny: "deny";
1617
1617
  ask: "ask";
1618
- }>>;
1619
- uploads: z.ZodDefault<z.ZodEnum<{
1618
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
1619
+ uploads: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
1620
1620
  allow: "allow";
1621
1621
  deny: "deny";
1622
1622
  ask: "ask";
1623
- }>>;
1624
- consequentialActions: z.ZodDefault<z.ZodEnum<{
1623
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
1624
+ consequentialActions: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
1625
1625
  allow: "allow";
1626
1626
  deny: "deny";
1627
1627
  ask: "ask";
1628
- }>>;
1628
+ }>>, z.ZodTransform<"allow" | "deny", "allow" | "deny" | "ask">>;
1629
1629
  }, z.core.$strict>>;
1630
1630
  }, z.core.$strict>>;
1631
1631
  computer: z.ZodPrefault<z.ZodObject<{
@@ -111,23 +111,23 @@ var init_schema = __esmMin((() => {
111
111
  "allow",
112
112
  "ask",
113
113
  "deny"
114
- ]).default("ask"),
114
+ ]).default("allow").transform((policy) => policy === "ask" ? "allow" : policy),
115
115
  uploads: z.enum([
116
116
  "allow",
117
117
  "ask",
118
118
  "deny"
119
- ]).default("ask"),
119
+ ]).default("allow").transform((policy) => policy === "ask" ? "allow" : policy),
120
120
  consequentialActions: z.enum([
121
121
  "allow",
122
122
  "ask",
123
123
  "deny"
124
- ]).default("ask")
124
+ ]).default("allow").transform((policy) => policy === "ask" ? "allow" : policy)
125
125
  }).strict().default({
126
126
  privateNetworks: "deny",
127
127
  allowedPrivateHosts: [],
128
- crossDomainNavigation: "ask",
129
- uploads: "ask",
130
- consequentialActions: "ask"
128
+ crossDomainNavigation: "allow",
129
+ uploads: "allow",
130
+ consequentialActions: "allow"
131
131
  })
132
132
  }).strict().default({
133
133
  enabled: true,
@@ -145,9 +145,9 @@ var init_schema = __esmMin((() => {
145
145
  security: {
146
146
  privateNetworks: "deny",
147
147
  allowedPrivateHosts: [],
148
- crossDomainNavigation: "ask",
149
- uploads: "ask",
150
- consequentialActions: "ask"
148
+ crossDomainNavigation: "allow",
149
+ uploads: "allow",
150
+ consequentialActions: "allow"
151
151
  }
152
152
  });
153
153
  SessionDmScopeSchema = z.enum([
@@ -1092,9 +1092,9 @@ workDiscoveryOnboarding: z.boolean().default(true) }).strict().default({ workDis
1092
1092
  security: {
1093
1093
  privateNetworks: "deny",
1094
1094
  allowedPrivateHosts: [],
1095
- crossDomainNavigation: "ask",
1096
- uploads: "ask",
1097
- consequentialActions: "ask"
1095
+ crossDomainNavigation: "allow",
1096
+ uploads: "allow",
1097
+ consequentialActions: "allow"
1098
1098
  }
1099
1099
  },
1100
1100
  tools: { web: { search: {
@@ -1,6 +1,6 @@
1
1
  import { ENDPOINT_CONTACT_LIST_OUTPUT_SCHEMA, ENDPOINT_CONTACT_OUTPUT_SCHEMA, ENDPOINT_FILE_OUTPUT_SCHEMA, ENDPOINT_TEXT_OUTPUT_SCHEMA, canonicalJson, init_src } from "../../packages/endpoint-tools-protocol/src/index.js";
2
2
  import { COMPUTER_INPUT_SCHEMA, COMPUTER_OUTPUT_SCHEMA, init_src as init_src$1 } from "../../packages/computer-control-contract/src/index.js";
3
- import { BROWSER_CONTROL_ENDPOINT_INPUT_SCHEMA, BROWSER_CONTROL_ENDPOINT_OUTPUT_SCHEMA } from "../../packages/browser-control-contract/src/index.js";
3
+ import { BROWSER_CONTROL_ENDPOINT_DESCRIPTOR, BROWSER_CONTROL_ENDPOINT_INPUT_SCHEMA, BROWSER_CONTROL_ENDPOINT_OUTPUT_SCHEMA, BROWSER_RECORDING_ENDPOINT_DESCRIPTOR, BROWSER_RECORDING_ENDPOINT_INPUT_SCHEMA } from "../../packages/browser-control-contract/src/index.js";
4
4
  import Ajv2020 from "ajv/dist/2020.js";
5
5
  //#region src/endpoint-tools/policy.ts
6
6
  init_src$1();
@@ -38,7 +38,8 @@ const POLICY_BY_TOOL = {
38
38
  "mobile.device.get_info": contract("public.background-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], []),
39
39
  "mobile.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
40
40
  "mobile.app.open_url": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["open-external-url"]),
41
- "browser.control": contract("browser.control", BROWSER_CONTROL_ENDPOINT_OUTPUT_SCHEMA, ["json"], ["browser-control"], [], BROWSER_CONTROL_ENDPOINT_INPUT_SCHEMA)
41
+ "browser.control": contract("browser.control", BROWSER_CONTROL_ENDPOINT_OUTPUT_SCHEMA, ["json"], ["browser-control"], [], BROWSER_CONTROL_ENDPOINT_INPUT_SCHEMA),
42
+ "browser.recording": contract("browser.control", BROWSER_CONTROL_ENDPOINT_OUTPUT_SCHEMA, ["json"], ["browser-control"], [], BROWSER_RECORDING_ENDPOINT_INPUT_SCHEMA)
42
43
  };
43
44
  var EndpointToolPolicy = class {
44
45
  ajv = new Ajv2020({
@@ -88,7 +89,7 @@ var EndpointToolPolicy = class {
88
89
  return;
89
90
  case "browser.control":
90
91
  this.assertFields(descriptor, "write", "never", false, "personal");
91
- if (descriptor.requiredPermissions.length !== 1 || descriptor.requiredPermissions[0] !== "browser-control" || descriptor.timeoutMs !== 12e4 || descriptor.maxConcurrency !== 4 || descriptor.supportsCancellation !== true || descriptor.idempotent !== false) throw new EndpointToolPolicyError(`Browser tool ${descriptor.name} violates its trusted policy`);
92
+ if (descriptor.requiredPermissions.length !== 1 || descriptor.requiredPermissions[0] !== "browser-control" || descriptor.timeoutMs !== 12e4 || descriptor.maxConcurrency !== (descriptor.name === BROWSER_RECORDING_ENDPOINT_DESCRIPTOR.name ? BROWSER_RECORDING_ENDPOINT_DESCRIPTOR.maxConcurrency : BROWSER_CONTROL_ENDPOINT_DESCRIPTOR.maxConcurrency) || descriptor.supportsCancellation !== true || descriptor.idempotent !== false) throw new EndpointToolPolicyError(`Browser tool ${descriptor.name} violates its trusted policy`);
92
93
  return;
93
94
  case "computer.session-scoped":
94
95
  this.assertFields(descriptor, "write", "never", false, "personal");
@@ -1,8 +1,11 @@
1
+ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
1
2
  //#region src/gateway/hono/routes/browser-automations.ts
2
3
  function presentRun(run) {
3
4
  return {
4
5
  id: run.id,
5
6
  automationId: run.automationId,
7
+ automationRevision: run.automationRevision,
8
+ businessOutcome: run.businessOutcome,
6
9
  status: run.status,
7
10
  inputs: run.inputs,
8
11
  result: run.result,
@@ -21,6 +24,14 @@ function parseStatus(value) {
21
24
  function registerBrowserAutomationRoutes(authenticated, deps) {
22
25
  const service = deps.service.browserAutomations;
23
26
  authenticated.get("/api/browser/automations", (c) => c.json({ automations: service.list() }));
27
+ authenticated.post("/api/browser/automations/validate", async (c) => {
28
+ const parsed = service.validate((await c.req.json()).definition);
29
+ return c.json({
30
+ valid: parsed.success,
31
+ issues: parsed.success ? [] : parsed.error.issues
32
+ });
33
+ });
34
+ authenticated.get("/api/browser/automations/:id/versions", (c) => c.json({ versions: service.versions(c.req.param("id")) }));
24
35
  authenticated.post("/api/browser/automations", deps.strictRateLimitMiddleware, async (c) => {
25
36
  try {
26
37
  const body = await c.req.json();
@@ -29,7 +40,7 @@ function registerBrowserAutomationRoutes(authenticated, deps) {
29
40
  status: parseStatus(body.status)
30
41
  }) }, 201);
31
42
  } catch (error) {
32
- return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
43
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, /revision changed|reused/.test(String(error)) ? 409 : 400);
33
44
  }
34
45
  });
35
46
  authenticated.get("/api/browser/automations/:id", (c) => {
@@ -44,10 +55,11 @@ function registerBrowserAutomationRoutes(authenticated, deps) {
44
55
  return c.json({ automation: service.save({
45
56
  definition: body.definition ?? current.definition,
46
57
  status: parseStatus(body.status) ?? current.status,
47
- expectedId: current.id
58
+ expectedId: current.id,
59
+ expectedRevision: body.expectedRevision
48
60
  }) });
49
61
  } catch (error) {
50
- return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
62
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, /revision changed|reused/.test(String(error)) ? 409 : 400);
51
63
  }
52
64
  });
53
65
  authenticated.delete("/api/browser/automations/:id", deps.strictRateLimitMiddleware, (c) => {
@@ -57,13 +69,17 @@ function registerBrowserAutomationRoutes(authenticated, deps) {
57
69
  return c.json({ error: error instanceof Error ? error.message : String(error) }, 409);
58
70
  }
59
71
  });
60
- authenticated.post("/api/browser/automations/:id/run", deps.strictRateLimitMiddleware, async (c) => {
72
+ authenticated.post("/api/browser/automations/:id/:operation{run|test}", deps.strictRateLimitMiddleware, async (c) => {
61
73
  try {
62
- const inputs = (await c.req.json().catch(() => ({}))).inputs ?? {};
74
+ const body = await c.req.json().catch(() => ({}));
75
+ const inputs = body.inputs ?? {};
63
76
  if (!inputs || typeof inputs !== "object" || Array.isArray(inputs)) return c.json({ error: "inputs must be an object." }, 400);
64
- return c.json({ run: presentRun(service.startRun(c.req.param("id"), inputs)) }, 202);
77
+ return c.json({ run: presentRun(service.startRun(c.req.param("id"), inputs, {
78
+ revision: body.revision,
79
+ clientRequestId: typeof body.clientRequestId === "string" ? `${getGatewayPrincipal(c).kind === "device" ? getGatewayPrincipal(c).deviceId : "owner"}:${body.clientRequestId}` : void 0
80
+ })) }, 202);
65
81
  } catch (error) {
66
- return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
82
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, /revision changed|reused/.test(String(error)) ? 409 : 400);
67
83
  }
68
84
  });
69
85
  authenticated.get("/api/browser/automation-runs", (c) => c.json({ runs: service.listRuns(c.req.query("automationId")).map(presentRun) }));
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerBrowserRecordingRoutes(app: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,78 @@
1
+ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
2
+ import { BrowserRecordingService } from "../../../browser/recordings/service.js";
3
+ import { randomUUID } from "node:crypto";
4
+ //#region src/gateway/hono/routes/browser-recordings.ts
5
+ function recordingAvailability(deps, deviceId) {
6
+ const browsers = deps.service.endpointTools.registry.list().filter((endpoint) => endpoint.kind === "browser" && (!deviceId || endpoint.principalId === deviceId));
7
+ const endpoints = browsers.filter((endpoint) => endpoint.tools.some((tool) => tool.descriptor.name === "browser.recording")).map(({ endpointId, displayName }) => ({
8
+ endpointId,
9
+ displayName
10
+ }));
11
+ return {
12
+ state: endpoints.length > 1 ? "choose_browser" : endpoints.length === 1 ? "ready" : browsers.length ? "update_required" : "connect_required",
13
+ endpoints
14
+ };
15
+ }
16
+ function registerBrowserRecordingRoutes(app, deps) {
17
+ const service = new BrowserRecordingService(deps.service.browserAutomations);
18
+ app.get("/api/browser/recordings/availability", (c) => {
19
+ const principal = getGatewayPrincipal(c);
20
+ return c.json(recordingAvailability(deps, principal.kind === "device" ? principal.deviceId : void 0));
21
+ });
22
+ app.post("/api/browser/recordings/control", async (c) => {
23
+ try {
24
+ const body = await c.req.json();
25
+ if (![
26
+ "start",
27
+ "pause",
28
+ "resume",
29
+ "finish",
30
+ "status"
31
+ ].includes(body.operation)) return c.json({ error: "Invalid recording operation." }, 400);
32
+ const principal = getGatewayPrincipal(c);
33
+ const endpoints = deps.service.endpointTools.registry.list().filter((endpoint) => endpoint.kind === "browser" && (principal.kind !== "device" || endpoint.principalId === principal.deviceId) && (!body.endpointId || endpoint.endpointId === body.endpointId) && endpoint.tools.some((tool) => tool.descriptor.name === "browser.recording"));
34
+ if (endpoints.length !== 1) {
35
+ const availability = recordingAvailability(deps, principal.kind === "device" ? principal.deviceId : void 0);
36
+ return c.json({
37
+ code: availability.state === "ready" ? "connect_required" : availability.state,
38
+ error: "Recording requires a connected browser with recording support.",
39
+ endpoints: availability.endpoints
40
+ }, 409);
41
+ }
42
+ const endpoint = endpoints[0];
43
+ const tool = deps.service.endpointTools.registry.getTool(endpoint.endpointId, "browser.recording");
44
+ const result = await deps.service.endpointTools.invocations.invoke({
45
+ endpointId: endpoint.endpointId,
46
+ toolCallId: `recording:${randomUUID()}`,
47
+ toolName: "browser.recording",
48
+ arguments: { operation: body.operation },
49
+ descriptorRevision: tool.revision,
50
+ signal: AbortSignal.timeout(3e4)
51
+ });
52
+ return c.json({
53
+ value: result.content.find((item) => item.type === "json")?.value,
54
+ endpointId: endpoint.endpointId
55
+ });
56
+ } catch (error) {
57
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
58
+ }
59
+ });
60
+ app.post("/api/browser/recordings/:id/:operation{events|finish}", async (c) => {
61
+ const principal = getGatewayPrincipal(c);
62
+ const endpointId = c.req.header("x-endpoint-id") ?? "";
63
+ const claim = c.req.header("x-endpoint-claim") ?? "";
64
+ const endpoint = deps.service.endpointTools.registry.get(endpointId);
65
+ if (principal.kind !== "device" || !principal.deviceId || endpoint?.principalId !== principal.deviceId || !deps.service.endpointTools.registry.verifyTurnClaim(endpointId, claim)) return c.json({ error: "Recording device is not authenticated." }, 403);
66
+ try {
67
+ if (Number(c.req.header("content-length") ?? 0) > 262144) return c.json({ error: "Recording batch is too large." }, 413);
68
+ const raw = await c.req.text();
69
+ if (Buffer.byteLength(raw) > 262144) return c.json({ error: "Recording batch is too large." }, 413);
70
+ const body = JSON.parse(raw);
71
+ return c.req.param("operation") === "events" ? c.json(service.append(c.req.param("id"), principal.deviceId, body.events)) : c.json({ automation: service.finish(c.req.param("id"), principal.deviceId, body.finalSeq) });
72
+ } catch (error) {
73
+ return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
74
+ }
75
+ });
76
+ }
77
+ //#endregion
78
+ export { registerBrowserRecordingRoutes };
@@ -3,14 +3,13 @@ import { browserTabBindingRequestSchema } from "../../../../packages/gateway-con
3
3
  import { init_src } from "../../../../packages/gateway-contract/src/index.js";
4
4
  import { getDevice, init_device_access_repository } from "../../../storage/sqlite/device-access-repository.js";
5
5
  import "../../../../packages/browser-control-contract/src/index.js";
6
- import { decideBrowserApproval, listBrowserApprovals } from "../../../browser/policy/approval-store.js";
7
6
  import { createBrowserDriver } from "../../../browser/drivers/create-driver.js";
8
7
  import { checkBrowserReadiness } from "../../../browser/readiness.js";
9
8
  import { isLoopbackClientIp } from "../../security/loopback.js";
10
9
  import { getGatewayPrincipal } from "../../security/gateway-principal.js";
11
10
  import { getConnInfo } from "@hono/node-server/conninfo";
12
11
  //#region src/gateway/hono/routes/browser.ts
13
- /** Browser Control status, approvals, and driver diagnostics. */
12
+ /** Browser Control status and driver diagnostics. */
14
13
  init_src();
15
14
  init_device_access_repository();
16
15
  init_browser_tab_binding_repository();
@@ -332,38 +331,6 @@ function registerBrowserRoutes(authenticated, deps) {
332
331
  }, 400);
333
332
  }
334
333
  });
335
- authenticated.get("/api/browser/approvals", (c) => {
336
- const conversationId = c.req.query("conversationId");
337
- if (!isLocalOwnerRequest(c, service) && (!conversationId || !canManageBrowserSession(c, service, conversationId))) return c.json({
338
- ok: false,
339
- error: "Local owner access required."
340
- }, 403);
341
- return c.json({
342
- ok: true,
343
- approvals: listBrowserApprovals(conversationId)
344
- });
345
- });
346
- authenticated.post("/api/browser/approvals/respond", strictRateLimitMiddleware, async (c) => {
347
- const body = await c.req.json().catch(() => null);
348
- const approval = typeof body?.id === "string" ? listBrowserApprovals().find((candidate) => candidate.id === body.id) : void 0;
349
- if (!isLocalOwnerRequest(c, service) && (!approval || !canManageBrowserSession(c, service, approval.conversationId))) return c.json({
350
- ok: false,
351
- error: "Local owner access required."
352
- }, 403);
353
- if (typeof body?.id !== "string" || body.decision !== "approved" && body.decision !== "denied") return c.json({
354
- ok: false,
355
- error: "id and decision are required."
356
- }, 400);
357
- const decided = decideBrowserApproval(body.id, body.decision);
358
- if (!decided) return c.json({
359
- ok: false,
360
- error: "Approval not found."
361
- }, 404);
362
- return c.json({
363
- ok: true,
364
- approval: decided
365
- });
366
- });
367
334
  authenticated.get("/api/browser/playwright/doctor", async (c) => {
368
335
  try {
369
336
  const { playwrightChromiumDoctor } = await import("../../../browser/providers/playwright-doctor.js");
@@ -13,6 +13,7 @@ function parsePreferences(value) {
13
13
  const source = value;
14
14
  const result = {};
15
15
  for (const key of [
16
+ "chatNeedsInput",
16
17
  "chatCompleted",
17
18
  "chatFailed",
18
19
  "taskNeedsInput",
@@ -13,7 +13,7 @@ init_sqlite();
13
13
  /** Register the unified work-home read model and its decision actions. */
14
14
  function registerHomeRoutes(authenticated, deps) {
15
15
  const { service } = deps;
16
- const home = new HomeQueryService(service, () => service.homeIntelligence.getAdvisor());
16
+ const home = new HomeQueryService(service, (locale) => service.homeIntelligence.getAdvisor(locale));
17
17
  authenticated.get("/api/home", async (c) => {
18
18
  const locale = c.req.query("locale");
19
19
  return c.json(await home.getSnapshot(locale));
@@ -123,6 +123,14 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
123
123
  return { register: registerBrowserInstallRoutes };
124
124
  }
125
125
  },
126
+ {
127
+ id: "browser-recordings",
128
+ match: (path) => path.startsWith("/api/browser/recordings/"),
129
+ load: async () => {
130
+ const { registerBrowserRecordingRoutes } = await import("./browser-recordings.js");
131
+ return { register: registerBrowserRecordingRoutes };
132
+ }
133
+ },
126
134
  {
127
135
  id: "browser-automations",
128
136
  match: (path) => startsWithAny(path, ["/api/browser/automations", "/api/browser/automation-runs"]),
@@ -1,6 +1,7 @@
1
1
  import { getDevice, init_device_access_repository } from "../../../storage/sqlite/device-access-repository.js";
2
2
  import { getPersonalRequest, init_request_repository, listPersonalRequests } from "../../../personal-agent/request-repository.js";
3
3
  import { getPersonalAgent } from "../../../personal-agent/repository.js";
4
+ import { writeAgentAvatarFromBase64 } from "../../agents-admin.js";
4
5
  import { TaskOriginRepository } from "../../../tasks/task-origin-repository.js";
5
6
  import { cancelPersonalRequest, personalRequestSnapshot, publishPersonalRequest } from "../../../personal-agent/request-service.js";
6
7
  import { PersonalOnboardingDraftSchema, PersonalOnboardingStepSchema, finishPersonalWelcome, getPersonalOnboarding, savePersonalOnboarding } from "../../../personal-agent/onboarding.js";
@@ -12,6 +13,14 @@ import { z } from "zod";
12
13
  //#region src/gateway/hono/routes/personal-agent.ts
13
14
  init_device_access_repository();
14
15
  init_request_repository();
16
+ const AvatarSchema = z.object({
17
+ base64: z.string().min(1).max(7e5),
18
+ mimeType: z.enum([
19
+ "image/png",
20
+ "image/jpeg",
21
+ "image/webp"
22
+ ])
23
+ }).strict();
15
24
  const CreateSchema = z.object({
16
25
  model: z.string().trim().min(3).optional(),
17
26
  displayName: z.string().trim().min(1).max(60).optional(),
@@ -54,6 +63,32 @@ function registerPersonalAgentRoutes(authenticated, deps) {
54
63
  return platform === "harmonyos" || platform === "ios" || platform === "android" ? "local-owner" : null;
55
64
  };
56
65
  registerProactivityRoutes(authenticated, deps, owner);
66
+ authenticated.put("/api/personal-agent/avatar", deps.strictRateLimitMiddleware, async (c) => {
67
+ const ownerId = owner(c);
68
+ if (!ownerId) return c.json({
69
+ ok: false,
70
+ error: "Owner access is required"
71
+ }, 403);
72
+ const record = getPersonalAgent(ownerId);
73
+ if (!record || record.state !== "ready") return c.json({
74
+ ok: false,
75
+ error: "Personal AI is not ready"
76
+ }, 409);
77
+ const input = AvatarSchema.safeParse(await c.req.json().catch(() => null));
78
+ if (!input.success) return c.json({
79
+ ok: false,
80
+ error: "Invalid avatar"
81
+ }, 400);
82
+ const result = await writeAgentAvatarFromBase64(record.agentId, input.data.base64, input.data.mimeType);
83
+ if (result.ok === false) return c.json({
84
+ ok: false,
85
+ error: result.error
86
+ }, result.status ?? 400);
87
+ return c.json({
88
+ ok: true,
89
+ payload: { agentId: record.agentId }
90
+ });
91
+ });
57
92
  authenticated.get("/api/personal-agent", async (c) => {
58
93
  const ownerId = owner(c);
59
94
  if (!ownerId) return c.json({
@@ -1,5 +1,5 @@
1
1
  import { voiceSelectionSchema } from "../../../../packages/realtime-protocol/src/voice-catalog.js";
2
- import { createVoiceSessionRequestSchema, init_voice } from "../../../../packages/realtime-protocol/src/voice.js";
2
+ import { VOICE_TIMING_METRICS, createVoiceSessionRequestSchema, init_voice } from "../../../../packages/realtime-protocol/src/voice.js";
3
3
  import { getDefaultModelSync, init_providers, resolveModel } from "../../../providers/index.js";
4
4
  import { isPersonalConversation } from "../../../personal-agent/repository.js";
5
5
  import { completeWithResolvedCredentials } from "../../../providers/model-call.js";
@@ -312,7 +312,10 @@ function registerVoiceRoutes(authenticated, deps) {
312
312
  }, 409);
313
313
  if (action === "preflight") {
314
314
  await service.voiceRealtime.preflight(parsed.data);
315
- return c.json({ ok: true });
315
+ return c.json({
316
+ ok: true,
317
+ timingMetrics: VOICE_TIMING_METRICS
318
+ });
316
319
  }
317
320
  const principal = getGatewayPrincipal(c);
318
321
  const create = () => service.voiceRealtime.createSession(parsed.data, principal.principalId);
@@ -20,7 +20,9 @@ function requiredGatewayScope(method, path) {
20
20
  if (path.startsWith("/api/endpoint-tools")) return "device.self";
21
21
  if (path === "/api/personal-agent/activity") return "tasks.read";
22
22
  if (path === "/api/personal-agent" || path.startsWith("/api/personal-agent/")) return methodScope(method, "sessions.read", "sessions.write");
23
- if (path.startsWith("/api/browser/tab-bindings") || path.startsWith("/api/browser/approvals")) return methodScope(method, "sessions.read", "sessions.write");
23
+ if (path.startsWith("/api/browser/recordings/")) return "device.self";
24
+ if (path.startsWith("/api/browser/automations") || path.startsWith("/api/browser/automation-runs")) return methodScope(method, "automations.read", "automations.write");
25
+ if (path.startsWith("/api/browser/tab-bindings")) return methodScope(method, "sessions.read", "sessions.write");
24
26
  if (method === "GET" && path === "/api/connectors/approvals") return "sessions.read";
25
27
  if (method === "POST" && path === "/api/connectors/approvals/respond") return "sessions.write";
26
28
  if (path === "/api/agent" || path.startsWith("/api/agent/")) return "agents.run";
@@ -397,6 +397,7 @@ var GatewayAgentRunner = class {
397
397
  suggestedAnswer: request.suggestedAnswer,
398
398
  approvalKey: request.approvalKey
399
399
  });
400
+ this.opts.emit("clarification.created", wait);
400
401
  const event = {
401
402
  type: "clarify_request",
402
403
  requestId: wait.id,