@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.
- package/dist/browser-ext/_locales/en/messages.json +30 -1
- package/dist/browser-ext/_locales/zh_CN/messages.json +30 -1
- package/dist/browser-ext/dist/assets/{auth-beGtbLPS.js → page-context-BeworyNB.js} +1331 -1355
- package/dist/browser-ext/dist/assets/{sidepanel-BT0ojEzG.css → sidepanel-Ccl0eSa1.css} +43 -0
- package/dist/browser-ext/dist/background.js +680 -182
- package/dist/browser-ext/dist/sidepanel.html +2 -2
- package/dist/browser-ext/dist/sidepanel.js +372 -193
- package/dist/browser-ext/manifest.json +2 -8
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-Cuf3JFFJ.js → activity-store-BQ3PMp2q.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DyATPNTe.js → agent-avatar-dicebear-Stj17S9u.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CCRfvuov.js +1 -0
- package/dist/gateway/static/root/assets/agent-plugin-dialog-CRlzd8El.js +1 -0
- package/dist/gateway/static/root/assets/agents-_ug2LCQb.js +66 -0
- package/dist/gateway/static/root/assets/{agents-admin-api-D842OcNo.js → agents-admin-api-HBZvVyzF.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-pJFe6M6c.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-DQr0o6Lm.js → appearance-settings-BrxSpBWa.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-CltMV4Xp.js → apps-page-DegSl5Lh.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DT8Nio-r.js → archive-plugin-BO3I9zRP.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BIfWS_3Y.js → automations-page-BZQ_VHjp.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-BQywN6nG.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-7qs3qcW9.js → binary-plugins-gFD7vH9R.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BFPUlxJ6.js → block-editor-3XjFv3kK.js} +28 -28
- package/dist/gateway/static/root/assets/browser-automation-inputs-DxRoKFun.js +1 -0
- package/dist/gateway/static/root/assets/browser-automations-page-yiEuG1v7.js +3 -0
- package/dist/gateway/static/root/assets/browser-settings-page-ch2_bQF0.js +3 -0
- package/dist/gateway/static/root/assets/{capabilities-K0Zb_lH0.js → capabilities-B48r0DDa.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-BzWFO_x_.js → capabilities-DO-vfNKI.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-page-BEnFt_dj.js +2 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-NckMsJ5N.js +8 -0
- package/dist/gateway/static/root/assets/{capability-header-actions-AMn_vTNv.js → capability-header-actions-CY8KCO9j.js} +1 -1
- package/dist/gateway/static/root/assets/channels-CHOS2CGa.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-C7nAROhF.js → chat-terminal-dock-Bwknnb4c.js} +2 -2
- package/dist/gateway/static/root/assets/computer-settings-page-B2xeFCSt.js +1 -0
- package/dist/gateway/static/root/assets/{connector-service-page-CTx1B8wx.js → connector-service-page-C83DnAqK.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-D6wTmWA6.js +2 -0
- package/dist/gateway/static/root/assets/{date-picker-Cx_xIKvN.js → date-picker-Bq9GR-DU.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-DYm96PDu.js → dependency-picker-BTERkA9X.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-D90OzgeR.js → desktop-pet-BwsbQw8V.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CmdCecjm.js → desktop-pet-settings-sL9i44pP.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-DI2bqaKO.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DZpaoeNa.js → directory-picker-path-field-BFlDmsS5.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-Bv6QE8kC.js → extension-debug-page-7Z1Tp7-w.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CEsq71Cm.js → extension-page-uGqvb8QX.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-CX-sK0Tw.js → extension-provider-xlSyz4Z6.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-UyOHF39P.js → extension-settings-page-CKHgrjOs.js} +1 -1
- package/dist/gateway/static/root/assets/{fallback-models-CKv_Wqg8.js → fallback-models-BwQg0G1D.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Cjnkle5J.js → gateway-config-swr-7RKqgU_U.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-realtime-DCCLdyQD.js → gateway-realtime-DDWymi-o.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-BheKaO6d.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-BAQnSEMJ.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CXKmdVzN.js → gateway-startup-retry-jiV5sbEX.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-BZDjvwet.js +2 -0
- package/dist/gateway/static/root/assets/{image-generation-api-NLHzm4Nc.js → image-generation-api-DO4mXb6I.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-C7qvlBTQ.js → imports-page-re1_Nh64.js} +1 -1
- package/dist/gateway/static/root/assets/index-BB1z8QxA.js +106 -0
- package/dist/gateway/static/root/assets/index-D9R6tU7r.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-pkgFWJb-.js → keyboard-shortcuts-settings-B_xja9LN.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-dMDhZXAi.js → local-app-workbench-page-CErdCrPX.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-TpUAfOn2.js → local-apps-page-BPL2RXdK.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-Cvv7I0fw.js → local-session-drafts-DRPsDCj1.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-C8TMD2gn.js → locale-store-COVscAqC.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DL-BM0xq.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-BOVRHhXk.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-Dse7rkio.js → markdown-view-B_qnAcW2.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BZrnzaBM.js → media-plugins-C0Pc-wSY.js} +1 -1
- package/dist/gateway/static/root/assets/messages-Bb2GK-Nj.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-cache-DyPPksMP.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-panel-DJJK2yL4.js +5 -0
- package/dist/gateway/static/root/assets/{notes-api-DKiVeQKG.js → notes-api-sBgBcyLW.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-oCxO7ZTv.js +8 -0
- package/dist/gateway/static/root/assets/{page-context-capture-button-Cxzd4QPB.js → page-context-capture-button-tf77xIz3.js} +1 -1
- package/dist/gateway/static/root/assets/personal-page-DOk9gUK5.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-D4hoEWiu.js → product-open-page-Dc3Y-Y7J.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-aR38El2E.js → product-preview-content-MG_hmVA3.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-D20QH4YB.js → project-detail-page-3uAzbW4T.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-Bf3BIcT6.js → projects-page-MllfNLGA.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-AdnxowbH.js → registry-api-Bh9UBb-f.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-Bs-C70el.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CBN3raz1.js → runtime-tools-settings-panel-DpJ5jNzR.js} +1 -1
- package/dist/gateway/static/root/assets/scenes-page-Dpxamkw6.js +2 -0
- package/dist/gateway/static/root/assets/{schema-form-CxrMGsT9.js → schema-form-DUeyQ1zh.js} +1 -1
- package/dist/gateway/static/root/assets/{send-session-input-CgOzhDZ0.js → send-session-input-Dgn4BRk_.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-_HIN8or3.js → session-api-yjpEz4pP.js} +1 -1
- package/dist/gateway/static/root/assets/{session-manager-CzCto5zT.js → session-manager-LInoZ_Yi.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BCVlNHtq.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Bz-ue9fZ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-D8Q3H3-o.js → settings-page-DouHuBXt.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-DvLMMiuS.js → setup-status-panel-B5BoZ-1y.js} +1 -1
- package/dist/gateway/static/root/assets/{share-link-dialog-Dg5os066.js → share-link-dialog-DJTabLAM.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-DMvohAyr.js → share-preview-page-jw7h4t_B.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-api-C96IO4qJ.js → shares-api-c0dfWz6h.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BlnlzGjH.js +1 -0
- package/dist/gateway/static/root/assets/{skill-api-C10ML0CH.js → skill-api-CfyX_0zN.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-DNbJzSfB.js → skill-reload-api-Ge5XymHa.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-DObMKvA6.js → skills-page-DjdTeYzm.js} +1 -1
- package/dist/gateway/static/root/assets/system-settings-panel-DWf256TE.js +1 -0
- package/dist/gateway/static/root/assets/{task-detail-page-BR2L1L8l.js → task-detail-page-DE6N1ZQe.js} +2 -2
- package/dist/gateway/static/root/assets/{task-expandable-content-DL2Q2gre.js → task-expandable-content-hYcgCEE3.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-DQ6KJa4l.js → theme-store-BOfCKgl6.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-Ed8_GYUT.js → tracing-settings-page-DDWFXcST.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-D3X8jDwo.js → tunnel-api-BBm9esrY.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-BqzRyyb9.js → usage-page-C93x89uW.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-CRFefpzO.js → use-autosave-CSckcjFx.js} +1 -1
- package/dist/gateway/static/root/assets/{use-composer-attachments-OLrvSjn5.js → use-composer-attachments-C7Gaaai1.js} +1 -1
- package/dist/gateway/static/root/assets/{use-file-preview-expanded-CJvzfQvw.js → use-file-preview-expanded-Db2VYg1b.js} +2 -2
- package/dist/gateway/static/root/assets/user-model-page-B74LkVbp.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-R9zNWYR_.js → voice-api-key-field-GEw5x2fU.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-DLudE9Rc.js → voice-config-api-3yyVwXln.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DVmQrolV.js → work-discovery-overlay-Bs2MKiTv.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DEkmuD3T.js → workflow-run-setup-panel-BR_U_snV.js} +2 -2
- package/dist/gateway/static/root/assets/{workflows-page-pqCB3sh4.js → workflows-page-Crk4SxtC.js} +3 -3
- package/dist/gateway/static/root/assets/{workspace-api-CdVUhyPo.js → workspace-api-Si2o3inw.js} +2 -2
- package/dist/gateway/static/root/index.html +27 -28
- package/dist/package.js +1 -1
- package/dist/packages/browser-control-contract/src/automation.js +213 -0
- package/dist/packages/browser-control-contract/src/index.js +43 -12
- package/dist/packages/gateway-contract/src/gateway-scopes.js +3 -1
- package/dist/packages/gateway-contract/src/notifications.js +1 -0
- package/dist/packages/realtime-protocol/src/voice-catalog.js +7 -1
- package/dist/packages/realtime-protocol/src/voice.js +9 -3
- package/dist/src/agent/coding/repository-instructions.js +8 -1
- package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
- package/dist/src/agent/tool-manuals/browser.js +3 -3
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -1
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -13
- package/dist/src/agent/tools/browser/tool/schemas.js +0 -4
- package/dist/src/agent/tools/browser-automation-tool.d.ts +74 -1
- package/dist/src/agent/tools/browser-automation-tool.js +52 -6
- package/dist/src/agent-config/schema.d.ts +1 -1
- package/dist/src/agent-config/schema.js +1 -1
- package/dist/src/automations/capabilities/write.d.ts +2 -0
- package/dist/src/automations/domain/types.d.ts +11 -0
- package/dist/src/automations/domain/validation.d.ts +4 -0
- package/dist/src/automations/domain/validation.js +1 -0
- package/dist/src/automations/draft/automation-draft-validator.d.ts +1 -0
- package/dist/src/automations/service/action-executor.js +11 -3
- package/dist/src/automations/service/automation-service.d.ts +1 -0
- package/dist/src/automations/service/automation-service.js +13 -1
- package/dist/src/bootstrap/application-state.js +3 -1
- package/dist/src/browser/automations/repository.d.ts +4 -0
- package/dist/src/browser/automations/repository.js +27 -6
- package/dist/src/browser/automations/runner.js +101 -9
- package/dist/src/browser/automations/runtime-service.js +4 -3
- package/dist/src/browser/automations/schema.d.ts +84 -1
- package/dist/src/browser/automations/schema.js +68 -2
- package/dist/src/browser/automations/service.d.ts +78 -1
- package/dist/src/browser/automations/service.js +36 -4
- package/dist/src/browser/automations/types.d.ts +19 -4
- package/dist/src/browser/drivers/extension-driver.d.ts +5 -5
- package/dist/src/browser/drivers/extension-driver.js +10 -10
- package/dist/src/browser/drivers/playwright-driver.js +46 -0
- package/dist/src/browser/index.d.ts +1 -2
- package/dist/src/browser/index.js +2 -3
- package/dist/src/browser/policy/browser-policy.d.ts +0 -1
- package/dist/src/browser/policy/browser-policy.js +1 -4
- package/dist/src/browser/providers/index.d.ts +1 -1
- package/dist/src/browser/providers/index.js +2 -2
- package/dist/src/browser/providers/realtime-extension.d.ts +1 -1
- package/dist/src/browser/providers/realtime-extension.js +5 -1
- package/dist/src/browser/recordings/service.d.ts +22 -0
- package/dist/src/browser/recordings/service.js +160 -0
- package/dist/src/browser/runtime/browser-runtime.d.ts +1 -1
- package/dist/src/browser/runtime/browser-runtime.js +19 -56
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/computer/runtime.js +2 -2
- package/dist/src/config/schema.d.ts +12 -12
- package/dist/src/config/schema.js +12 -12
- package/dist/src/endpoint-tools/policy.js +4 -3
- package/dist/src/gateway/hono/routes/browser-automations.js +23 -7
- package/dist/src/gateway/hono/routes/browser-recordings.d.ts +3 -0
- package/dist/src/gateway/hono/routes/browser-recordings.js +78 -0
- package/dist/src/gateway/hono/routes/browser.js +1 -34
- package/dist/src/gateway/hono/routes/device-push.js +1 -0
- package/dist/src/gateway/hono/routes/home.js +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/personal-agent.js +35 -0
- package/dist/src/gateway/hono/routes/voice.js +5 -2
- package/dist/src/gateway/security/gateway-scopes.js +3 -1
- package/dist/src/gateway/service/agent-runner.js +1 -0
- package/dist/src/home-intelligence/generator.d.ts +2 -0
- package/dist/src/home-intelligence/generator.js +53 -4
- package/dist/src/home-intelligence/host.d.ts +2 -1
- package/dist/src/home-intelligence/host.js +23 -3
- package/dist/src/migrations/cloud-public-models.d.ts +7 -0
- package/dist/src/migrations/cloud-public-models.js +157 -0
- package/dist/src/notifications/clarification.d.ts +5 -0
- package/dist/src/notifications/clarification.js +66 -0
- package/dist/src/notifications/device-store.js +1 -0
- package/dist/src/notifications/harmony-push.d.ts +1 -0
- package/dist/src/notifications/harmony-push.js +3 -1
- package/dist/src/notifications/planner.d.ts +1 -0
- package/dist/src/notifications/service.d.ts +2 -2
- package/dist/src/notifications/service.js +20 -4
- package/dist/src/notifications/store.d.ts +2 -0
- package/dist/src/notifications/store.js +7 -1
- package/dist/src/notifications/types.d.ts +1 -0
- package/dist/src/notifications/types.js +1 -0
- package/dist/src/providers/model-catalog-persistence.js +2 -2
- package/dist/src/providers/presentation.js +1 -0
- package/dist/src/providers/xopc-cloud-model-source.js +1 -1
- package/dist/src/storage/sqlite/clarification-wait-repository.js +1 -0
- package/dist/src/storage/sqlite/migrations/238_browser_record_replay.sql +45 -0
- package/dist/src/storage/sqlite/migrations/239_clarification_notifications.sql +26 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tasks/home-query-service.d.ts +1 -1
- package/dist/src/tasks/home-query-service.js +6 -2
- package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +2 -1
- package/dist/src/voice/dashscope/streaming-tts-stream.js +135 -79
- package/dist/src/voice/metadata/types.d.ts +1 -0
- package/dist/src/voice/platform-catalog.d.ts +4 -0
- package/dist/src/voice/platform-settings.js +1 -0
- package/dist/src/voice/realtime/agentEngine.js +78 -1
- package/dist/src/voice/realtime/speakable-segmenter.d.ts +2 -0
- package/dist/src/voice/realtime/speakable-segmenter.js +30 -0
- package/dist/src/voice/tts/providers/alibaba-speech.js +17 -1
- package/dist/src/voice/tts/providers/xopc-cloud-speech.js +3 -2
- package/dist/src/voice/tts/speak-core.d.ts +3 -0
- package/dist/src/voice/tts/speak-core.js +21 -1
- package/dist/src/voice/tts/speech-provider-types.d.ts +8 -0
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-gT9_j4tr.js +0 -1
- package/dist/gateway/static/root/assets/agent-plugin-dialog-CLXCJ6JN.js +0 -1
- package/dist/gateway/static/root/assets/agents-BAUfOMsq.js +0 -66
- package/dist/gateway/static/root/assets/app-management-settings-panel-CoIFxQKH.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-BCGPjsdU.js +0 -6
- package/dist/gateway/static/root/assets/browser-automation-inputs-BUAIKIX0.js +0 -1
- package/dist/gateway/static/root/assets/browser-automations-page-CSwu1U1F.js +0 -3
- package/dist/gateway/static/root/assets/browser-settings-page-C1ReMNqX.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-page-BdTSqloI.js +0 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BUblBMZC.js +0 -8
- package/dist/gateway/static/root/assets/channels-CXCf5qO6.js +0 -1
- package/dist/gateway/static/root/assets/computer-settings-page-B5SuSZ3G.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DfnK1crf.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-s2ogSa4l.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-C_Th8kGg.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CZ73IpbP.js +0 -1
- package/dist/gateway/static/root/assets/home-page-BQWq4kYi.js +0 -2
- package/dist/gateway/static/root/assets/index-BQgqzhQj.js +0 -106
- package/dist/gateway/static/root/assets/index-COB4QIJp.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-B-Y9oZLh.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-B2lzsw6X.js +0 -1
- package/dist/gateway/static/root/assets/messages-Dy26npMy.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-B1C86nRp.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-DL__qP6U.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-DTBbg9Hs.js +0 -8
- package/dist/gateway/static/root/assets/oauth-api-BwpzpRwC.js +0 -1
- package/dist/gateway/static/root/assets/personal-page-CzaTnHeD.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CKxqncqW.js +0 -1
- package/dist/gateway/static/root/assets/scenes-page-Cv_5ozfX.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-DZcu6NLJ.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DazqeDQ7.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CsDATuCw.js +0 -1
- package/dist/gateway/static/root/assets/system-settings-panel-Bn3khdzb.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-CG6wqIKP.js +0 -2
- package/dist/src/browser/policy/approval-store.d.ts +0 -17
- package/dist/src/browser/policy/approval-store.js +0 -62
- package/dist/src/browser/providers/extension-ws-acquire.d.ts +0 -19
- package/dist/src/browser/providers/extension-ws-acquire.js +0 -78
- package/dist/src/browser/providers/extension.d.ts +0 -61
- 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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
+
actionDenied(input, risk) {
|
|
169
167
|
const security = this.options.getConfig().security;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
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: "
|
|
129
|
-
uploads: "
|
|
130
|
-
consequentialActions: "
|
|
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: "
|
|
149
|
-
uploads: "
|
|
150
|
-
consequentialActions: "
|
|
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: "
|
|
1096
|
-
uploads: "
|
|
1097
|
-
consequentialActions: "
|
|
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 !==
|
|
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
|
|
72
|
+
authenticated.post("/api/browser/automations/:id/:operation{run|test}", deps.strictRateLimitMiddleware, async (c) => {
|
|
61
73
|
try {
|
|
62
|
-
const
|
|
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
|
|
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,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
|
|
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,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({
|
|
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/
|
|
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";
|