@xopcai/xopc 0.0.368 → 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-D9ZMh5ZR.js → activity-store-BQ3PMp2q.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Bj3rvcTm.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-BjdgKCnk.js → agent-plugin-dialog-CRlzd8El.js} +1 -1
- package/dist/gateway/static/root/assets/agents-_ug2LCQb.js +66 -0
- package/dist/gateway/static/root/assets/{agents-admin-api-B5QDepbW.js → agents-admin-api-HBZvVyzF.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-2rTEtB_X.js → app-management-settings-panel-pJFe6M6c.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BPVBS80k.js → appearance-settings-BrxSpBWa.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-1FuKlZYP.js → apps-page-DegSl5Lh.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-BbT1O7oK.js → archive-plugin-BO3I9zRP.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-DjwP_h8h.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-gS7Wg68v.js → binary-plugins-gFD7vH9R.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DbwMaivP.js → block-editor-3XjFv3kK.js} +3 -3
- 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-Dd1PZRQw.js → capabilities-B48r0DDa.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-Lswa0hv8.js → capabilities-DO-vfNKI.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-page-djBsC_tG.js → capabilities-page-BEnFt_dj.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-DTHR1DrJ.js → capabilities-settings-panel-NckMsJ5N.js} +4 -4
- package/dist/gateway/static/root/assets/{capability-header-actions-494dnJsj.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-Bl7-Zk-x.js → chat-terminal-dock-Bwknnb4c.js} +2 -2
- package/dist/gateway/static/root/assets/{computer-settings-page-ByExKr_6.js → computer-settings-page-B2xeFCSt.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-BK_5aFxO.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-BXJv6472.js → date-picker-Bq9GR-DU.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CWbbhKZa.js → dependency-picker-BTERkA9X.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DWNEC3mk.js → desktop-pet-BwsbQw8V.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BYwlxGiN.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-D26tSY8Z.js → directory-picker-path-field-BFlDmsS5.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-xYIGNegB.js → extension-debug-page-7Z1Tp7-w.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BoQ1-3AW.js → extension-page-uGqvb8QX.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-Cw_JU6RR.js → extension-provider-xlSyz4Z6.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BH5TFGPe.js → extension-settings-page-CKHgrjOs.js} +1 -1
- package/dist/gateway/static/root/assets/{fallback-models-04Wqmw14.js → fallback-models-BwQg0G1D.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-CNf0ZeRw.js → gateway-config-swr-7RKqgU_U.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-realtime-C4KtwMY3.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-BqvCJVUC.js → gateway-settings-BAQnSEMJ.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DIxHacUw.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-CS0q0Kto.js → image-generation-api-DO4mXb6I.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-n_rSLo6b.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-tVkrHbYF.js → keyboard-shortcuts-settings-B_xja9LN.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-L8tYuas0.js → local-app-workbench-page-CErdCrPX.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-SSJ9B1bH.js → local-apps-page-BPL2RXdK.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-B_McurIj.js → local-session-drafts-DRPsDCj1.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-D6_rF-qT.js → locale-store-COVscAqC.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-BWD63eg1.js → logs-page-DL-BM0xq.js} +2 -2
- package/dist/gateway/static/root/assets/management-settings-BOVRHhXk.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-_xwUuKce.js → markdown-view-B_qnAcW2.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C631CDu4.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-vIZWQ9Yt.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-BlPDM7GM.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-BJjWvoER.js → product-open-page-Dc3Y-Y7J.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-CEd4E7Gf.js → product-preview-content-MG_hmVA3.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-DM4_VLNX.js → project-detail-page-3uAzbW4T.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-lszV8HuS.js → projects-page-MllfNLGA.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-uJnjqTcn.js → registry-api-Bh9UBb-f.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-O6j9CWX0.js → remote-access-hub-Bs-C70el.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CjnNQYW8.js → runtime-tools-settings-panel-DpJ5jNzR.js} +1 -1
- package/dist/gateway/static/root/assets/{scenes-page-B3T3dDOR.js → scenes-page-Dpxamkw6.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-DT3c4Vd_.js → schema-form-DUeyQ1zh.js} +1 -1
- package/dist/gateway/static/root/assets/{send-session-input-CICkGwn-.js → send-session-input-Dgn4BRk_.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-BcQodoAu.js → session-api-yjpEz4pP.js} +1 -1
- package/dist/gateway/static/root/assets/{session-manager-B0tOE4qz.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-D-PZjcss.js → settings-page-DouHuBXt.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Ce3gTbT3.js → setup-status-panel-B5BoZ-1y.js} +1 -1
- package/dist/gateway/static/root/assets/{share-link-dialog-CWS8EkJS.js → share-link-dialog-DJTabLAM.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-23NJAKiq.js → share-preview-page-jw7h4t_B.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-api-iKhHbvBD.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-C-MWdQwl.js → skill-api-CfyX_0zN.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-iy02aB13.js → skill-reload-api-Ge5XymHa.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-DjdTeYzm.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-DWf256TE.js +1 -0
- package/dist/gateway/static/root/assets/{task-detail-page-B2SIEyhZ.js → task-detail-page-DE6N1ZQe.js} +2 -2
- package/dist/gateway/static/root/assets/{task-expandable-content-D2LRR4BC.js → task-expandable-content-hYcgCEE3.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-BJfhz-Zq.js → theme-store-BOfCKgl6.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-aHD56iaS.js → tracing-settings-page-DDWFXcST.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-BCf8CfTC.js → tunnel-api-BBm9esrY.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-B4XUkuJd.js → usage-page-C93x89uW.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-BnnTw9RE.js → use-autosave-CSckcjFx.js} +1 -1
- package/dist/gateway/static/root/assets/{use-composer-attachments-Itczg0y1.js → use-composer-attachments-C7Gaaai1.js} +1 -1
- package/dist/gateway/static/root/assets/{use-file-preview-expanded-DJ5vyrvM.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-BphJku8x.js → voice-api-key-field-GEw5x2fU.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-B4u4coFj.js → voice-config-api-3yyVwXln.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-jgOEP1xw.js → work-discovery-overlay-Bs2MKiTv.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-N69crzRu.js → workflow-run-setup-panel-BR_U_snV.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-Crk4SxtC.js +6 -0
- package/dist/gateway/static/root/assets/{workspace-api-Lzv6GDO8.js → workspace-api-Si2o3inw.js} +2 -2
- package/dist/gateway/static/root/index.html +27 -27
- 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.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/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 +1 -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.js +1 -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/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/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/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-D0tD3kCe.js +0 -1
- package/dist/gateway/static/root/assets/agents-CWXKzX5L.js +0 -66
- package/dist/gateway/static/root/assets/automations-workspace-C9ZT6TAU.js +0 -6
- package/dist/gateway/static/root/assets/browser-automation-inputs-CXG_JveC.js +0 -1
- package/dist/gateway/static/root/assets/browser-automations-page-CJc7OKR3.js +0 -3
- package/dist/gateway/static/root/assets/browser-settings-page-BjaTEUR8.js +0 -3
- package/dist/gateway/static/root/assets/channels-BaYRJtz3.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DyqRwSH2.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-BAc4F35b.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-ChZUzVbe.js +0 -1
- package/dist/gateway/static/root/assets/home-page-DhPPLbdD.js +0 -2
- package/dist/gateway/static/root/assets/index-CK4O2xMa.css +0 -1
- package/dist/gateway/static/root/assets/index-DpLD-7Hc.js +0 -106
- package/dist/gateway/static/root/assets/management-settings-aKSibklM.js +0 -1
- package/dist/gateway/static/root/assets/messages-Bnx3GMDB.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-Di83uIPw.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-B_fve3_2.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-DnChyp8S.js +0 -8
- package/dist/gateway/static/root/assets/personal-page-BM2qAgg_.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BIixHXlQ.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-49SUEWPh.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CNEZjF66.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BndNdYsJ.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-EpZeMlvp.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-Bz5lkFG9.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-CPCgOfHh.js +0 -6
- 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,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extension browser provider — connects to the xopc Chrome Extension via WebSocket.
|
|
3
|
-
*
|
|
4
|
-
* The xopc process starts a WebSocket server; the Chrome Extension connects as a client.
|
|
5
|
-
* Commands are sent over the WS connection and results are returned asynchronously.
|
|
6
|
-
*/
|
|
7
|
-
import { type BrowserActionInput, type BrowserWireResult } from '@xopcai/browser-control-contract';
|
|
8
|
-
export interface ExtensionProviderConfig {
|
|
9
|
-
/** WebSocket server port. Default: 19820. */
|
|
10
|
-
port?: number;
|
|
11
|
-
/** Host to bind. Default: 127.0.0.1. */
|
|
12
|
-
host?: string;
|
|
13
|
-
/** Timeout waiting for extension connection (ms). Default: 30000. */
|
|
14
|
-
connectionTimeout?: number;
|
|
15
|
-
/** Default command timeout (ms). Default: 30000. */
|
|
16
|
-
commandTimeout?: number;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Manages a WebSocket server that the Chrome Extension connects to.
|
|
20
|
-
* Sends commands and receives results over the connection.
|
|
21
|
-
*/
|
|
22
|
-
export declare class ExtensionBrowserProvider {
|
|
23
|
-
readonly name = "extension";
|
|
24
|
-
private server;
|
|
25
|
-
private wss;
|
|
26
|
-
private clientWs;
|
|
27
|
-
private pending;
|
|
28
|
-
private commandCounter;
|
|
29
|
-
private socketConnected;
|
|
30
|
-
private handshakeReceived;
|
|
31
|
-
private connected;
|
|
32
|
-
private extensionProtocolVersion;
|
|
33
|
-
private extensionVersion;
|
|
34
|
-
private connectionId;
|
|
35
|
-
private principalId;
|
|
36
|
-
private readonly config;
|
|
37
|
-
private connectionWaiters;
|
|
38
|
-
constructor(config?: ExtensionProviderConfig);
|
|
39
|
-
/** Start the WebSocket server and wait for the extension to connect. */
|
|
40
|
-
start(): Promise<void>;
|
|
41
|
-
/** Wait for the Chrome Extension to connect. */
|
|
42
|
-
waitForConnection(timeoutMs?: number): Promise<void>;
|
|
43
|
-
/** Send one Browser Control v2 action to the extension. */
|
|
44
|
-
send(input: BrowserActionInput, timeoutMs?: number, visualFallback?: boolean): Promise<BrowserWireResult>;
|
|
45
|
-
/** Whether the extension is currently connected. */
|
|
46
|
-
isConnected(): boolean;
|
|
47
|
-
getConnectionStatus(): {
|
|
48
|
-
socketConnected: boolean;
|
|
49
|
-
connected: boolean;
|
|
50
|
-
protocolVersion: number | null;
|
|
51
|
-
expectedProtocolVersion: number;
|
|
52
|
-
extensionVersion: string | null;
|
|
53
|
-
principalId: string | null;
|
|
54
|
-
};
|
|
55
|
-
private protocolMismatchMessage;
|
|
56
|
-
/** Shutdown the WebSocket server. */
|
|
57
|
-
shutdown(): Promise<void>;
|
|
58
|
-
private _handleMessage;
|
|
59
|
-
private _authenticateCandidate;
|
|
60
|
-
}
|
|
61
|
-
export declare function isBrowserWireResult(value: unknown): value is BrowserWireResult;
|
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { deleteBrowserTabBindingsByPrincipal, getBrowserTabBindingById, init_browser_tab_binding_repository } from "../../storage/sqlite/browser-tab-binding-repository.js";
|
|
4
|
-
import { getDevice, init_device_access_repository } from "../../storage/sqlite/device-access-repository.js";
|
|
5
|
-
import { browserWireAuthenticationPayload } from "../../../packages/browser-control-contract/src/index.js";
|
|
6
|
-
import { isChromeExtensionOrigin } from "../../gateway/security/origin-check.js";
|
|
7
|
-
import crypto from "node:crypto";
|
|
8
|
-
//#region src/browser/providers/extension.ts
|
|
9
|
-
/**
|
|
10
|
-
* Extension browser provider — connects to the xopc Chrome Extension via WebSocket.
|
|
11
|
-
*
|
|
12
|
-
* The xopc process starts a WebSocket server; the Chrome Extension connects as a client.
|
|
13
|
-
* Commands are sent over the WS connection and results are returned asynchronously.
|
|
14
|
-
*/
|
|
15
|
-
init_logger();
|
|
16
|
-
init_device_access_repository();
|
|
17
|
-
init_browser_tab_binding_repository();
|
|
18
|
-
const log = createLogger("ExtensionProvider");
|
|
19
|
-
const DEFAULT_PORT = 19820;
|
|
20
|
-
const DEFAULT_HOST = "127.0.0.1";
|
|
21
|
-
const DEFAULT_CONNECTION_TIMEOUT = 3e4;
|
|
22
|
-
const DEFAULT_COMMAND_TIMEOUT = 3e4;
|
|
23
|
-
/**
|
|
24
|
-
* Manages a WebSocket server that the Chrome Extension connects to.
|
|
25
|
-
* Sends commands and receives results over the connection.
|
|
26
|
-
*/
|
|
27
|
-
var ExtensionBrowserProvider = class {
|
|
28
|
-
name = "extension";
|
|
29
|
-
server = null;
|
|
30
|
-
wss = null;
|
|
31
|
-
clientWs = null;
|
|
32
|
-
pending = /* @__PURE__ */ new Map();
|
|
33
|
-
commandCounter = 0;
|
|
34
|
-
socketConnected = false;
|
|
35
|
-
handshakeReceived = false;
|
|
36
|
-
connected = false;
|
|
37
|
-
extensionProtocolVersion = null;
|
|
38
|
-
extensionVersion = null;
|
|
39
|
-
connectionId = null;
|
|
40
|
-
principalId = null;
|
|
41
|
-
config;
|
|
42
|
-
connectionWaiters = [];
|
|
43
|
-
constructor(config) {
|
|
44
|
-
this.config = {
|
|
45
|
-
port: config?.port ?? DEFAULT_PORT,
|
|
46
|
-
host: config?.host ?? DEFAULT_HOST,
|
|
47
|
-
connectionTimeout: config?.connectionTimeout ?? DEFAULT_CONNECTION_TIMEOUT,
|
|
48
|
-
commandTimeout: config?.commandTimeout ?? DEFAULT_COMMAND_TIMEOUT
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/** Start the WebSocket server and wait for the extension to connect. */
|
|
52
|
-
async start() {
|
|
53
|
-
if (this.server) return;
|
|
54
|
-
const wsModule = await import("ws");
|
|
55
|
-
let WssClass = wsModule.WebSocketServer;
|
|
56
|
-
if (typeof WssClass !== "function") {
|
|
57
|
-
const def = wsModule.default;
|
|
58
|
-
WssClass = def?.WebSocketServer ?? def;
|
|
59
|
-
}
|
|
60
|
-
if (typeof WssClass !== "function") throw new Error("Failed to resolve WebSocketServer from \"ws\" package");
|
|
61
|
-
const WebSocketServer = WssClass;
|
|
62
|
-
const http = await import("node:http");
|
|
63
|
-
this.server = http.createServer((_req, res) => {
|
|
64
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
65
|
-
res.end(JSON.stringify({
|
|
66
|
-
ok: true,
|
|
67
|
-
...this.getConnectionStatus()
|
|
68
|
-
}));
|
|
69
|
-
});
|
|
70
|
-
this.wss = new WebSocketServer({
|
|
71
|
-
server: this.server,
|
|
72
|
-
path: "/browser-ext"
|
|
73
|
-
});
|
|
74
|
-
this.wss.on("connection", (ws, request) => {
|
|
75
|
-
const origin = request.headers.origin?.toLowerCase();
|
|
76
|
-
if (!isChromeExtensionOrigin(origin)) {
|
|
77
|
-
ws.close(4403, "Chrome extension origin required");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const challenge = {
|
|
81
|
-
type: "auth_challenge",
|
|
82
|
-
protocolVersion: 5,
|
|
83
|
-
connectionId: crypto.randomUUID(),
|
|
84
|
-
challenge: crypto.randomBytes(32).toString("base64url"),
|
|
85
|
-
issuedAt: Date.now()
|
|
86
|
-
};
|
|
87
|
-
let authenticated = false;
|
|
88
|
-
const authenticationTimer = setTimeout(() => {
|
|
89
|
-
if (!authenticated) ws.close(4401, "Browser authentication timed out");
|
|
90
|
-
}, 5e3);
|
|
91
|
-
ws.send(JSON.stringify(challenge));
|
|
92
|
-
ws.on("message", (data) => {
|
|
93
|
-
if (authenticated) {
|
|
94
|
-
this._handleMessage(data.toString(), ws);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (!this._authenticateCandidate(data.toString(), origin, challenge)) {
|
|
98
|
-
clearTimeout(authenticationTimer);
|
|
99
|
-
ws.close(4401, "Browser authentication failed");
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
authenticated = true;
|
|
103
|
-
clearTimeout(authenticationTimer);
|
|
104
|
-
const message = JSON.parse(data.toString());
|
|
105
|
-
const previousClient = this.clientWs;
|
|
106
|
-
this.clientWs = ws;
|
|
107
|
-
this.socketConnected = true;
|
|
108
|
-
this.handshakeReceived = true;
|
|
109
|
-
this.connected = true;
|
|
110
|
-
this.extensionProtocolVersion = message.protocolVersion;
|
|
111
|
-
this.extensionVersion = message.extensionVersion;
|
|
112
|
-
this.connectionId = message.connectionId;
|
|
113
|
-
this.principalId = message.principalId;
|
|
114
|
-
if (previousClient && previousClient !== ws) try {
|
|
115
|
-
previousClient.close(4001, "Connection replaced");
|
|
116
|
-
} catch {}
|
|
117
|
-
for (const waiter of this.connectionWaiters) waiter.resolve();
|
|
118
|
-
this.connectionWaiters = [];
|
|
119
|
-
log.info({
|
|
120
|
-
principalId: message.principalId,
|
|
121
|
-
extensionId: message.extensionId,
|
|
122
|
-
connectionId: message.connectionId
|
|
123
|
-
}, "Chrome extension authenticated");
|
|
124
|
-
});
|
|
125
|
-
ws.on("close", (code, reason) => {
|
|
126
|
-
if (this.clientWs !== ws) return;
|
|
127
|
-
log.warn({
|
|
128
|
-
code,
|
|
129
|
-
reason: reason.toString(),
|
|
130
|
-
pendingCount: this.pending.size
|
|
131
|
-
}, "Chrome Extension disconnected");
|
|
132
|
-
const disconnectedPrincipalId = this.principalId;
|
|
133
|
-
this.clientWs = null;
|
|
134
|
-
this.socketConnected = false;
|
|
135
|
-
this.handshakeReceived = false;
|
|
136
|
-
this.connected = false;
|
|
137
|
-
this.extensionProtocolVersion = null;
|
|
138
|
-
this.extensionVersion = null;
|
|
139
|
-
this.connectionId = null;
|
|
140
|
-
this.principalId = null;
|
|
141
|
-
if (disconnectedPrincipalId) deleteBrowserTabBindingsByPrincipal(disconnectedPrincipalId);
|
|
142
|
-
for (const [id, req] of this.pending) {
|
|
143
|
-
clearTimeout(req.timer);
|
|
144
|
-
req.reject(/* @__PURE__ */ new Error("Extension disconnected"));
|
|
145
|
-
this.pending.delete(id);
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
const wssEmitter = this.wss;
|
|
150
|
-
await new Promise((resolve, reject) => {
|
|
151
|
-
let settled = false;
|
|
152
|
-
const disposeFailedStart = async () => {
|
|
153
|
-
if (this.wss) {
|
|
154
|
-
try {
|
|
155
|
-
this.wss.close();
|
|
156
|
-
} catch {}
|
|
157
|
-
this.wss = null;
|
|
158
|
-
}
|
|
159
|
-
if (this.server) {
|
|
160
|
-
await new Promise((r) => {
|
|
161
|
-
this.server.close(() => r());
|
|
162
|
-
});
|
|
163
|
-
this.server = null;
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
const onStartError = (err) => {
|
|
167
|
-
if (settled) return;
|
|
168
|
-
settled = true;
|
|
169
|
-
this.server.removeListener("error", onStartError);
|
|
170
|
-
wssEmitter.removeListener("error", onStartError);
|
|
171
|
-
disposeFailedStart().then(() => reject(err));
|
|
172
|
-
};
|
|
173
|
-
const onListening = () => {
|
|
174
|
-
if (settled) return;
|
|
175
|
-
settled = true;
|
|
176
|
-
this.server.removeListener("error", onStartError);
|
|
177
|
-
wssEmitter.removeListener("error", onStartError);
|
|
178
|
-
log.info({
|
|
179
|
-
port: this.config.port,
|
|
180
|
-
host: this.config.host
|
|
181
|
-
}, "Extension WS server started");
|
|
182
|
-
const onRuntimeError = (err) => {
|
|
183
|
-
log.error({ err }, "Extension WS bridge runtime error");
|
|
184
|
-
};
|
|
185
|
-
this.server.on("error", onRuntimeError);
|
|
186
|
-
wssEmitter.on("error", onRuntimeError);
|
|
187
|
-
resolve();
|
|
188
|
-
};
|
|
189
|
-
this.server.on("error", onStartError);
|
|
190
|
-
wssEmitter.on("error", onStartError);
|
|
191
|
-
this.server.listen(this.config.port, this.config.host, onListening);
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
/** Wait for the Chrome Extension to connect. */
|
|
195
|
-
async waitForConnection(timeoutMs) {
|
|
196
|
-
if (this.connected) return;
|
|
197
|
-
if (this.socketConnected && this.handshakeReceived && this.extensionProtocolVersion !== 5) throw new Error(this.protocolMismatchMessage());
|
|
198
|
-
const timeout = timeoutMs ?? this.config.connectionTimeout;
|
|
199
|
-
return new Promise((resolve, reject) => {
|
|
200
|
-
const timer = setTimeout(() => {
|
|
201
|
-
const idx = this.connectionWaiters.findIndex((w) => w.resolve === resolve);
|
|
202
|
-
if (idx >= 0) this.connectionWaiters.splice(idx, 1);
|
|
203
|
-
reject(/* @__PURE__ */ new Error(`Extension connection timeout after ${timeout}ms. Is the Chrome Extension installed and enabled?`));
|
|
204
|
-
}, timeout);
|
|
205
|
-
this.connectionWaiters.push({
|
|
206
|
-
resolve: () => {
|
|
207
|
-
clearTimeout(timer);
|
|
208
|
-
resolve();
|
|
209
|
-
},
|
|
210
|
-
reject: (e) => {
|
|
211
|
-
clearTimeout(timer);
|
|
212
|
-
reject(e);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
/** Send one Browser Control v2 action to the extension. */
|
|
218
|
-
async send(input, timeoutMs, visualFallback = true) {
|
|
219
|
-
if (!this.connected || !this.clientWs) {
|
|
220
|
-
const detail = this.socketConnected ? this.protocolMismatchMessage() : "Extension not connected. Ensure the Chrome Extension is installed and connected.";
|
|
221
|
-
throw new Error(detail);
|
|
222
|
-
}
|
|
223
|
-
if (input.target?.kind === "attached_tab") {
|
|
224
|
-
const binding = getBrowserTabBindingById(input.target.bindingId);
|
|
225
|
-
if (!binding || binding.principalId !== this.principalId) throw new Error("Attached tab binding does not belong to the connected browser");
|
|
226
|
-
}
|
|
227
|
-
const id = `cmd_${++this.commandCounter}_${Date.now()}`;
|
|
228
|
-
const cmd = {
|
|
229
|
-
id,
|
|
230
|
-
protocolVersion: 5,
|
|
231
|
-
connectionId: this.connectionId,
|
|
232
|
-
input,
|
|
233
|
-
timeoutMs: timeoutMs ?? this.config.commandTimeout,
|
|
234
|
-
visualFallback
|
|
235
|
-
};
|
|
236
|
-
return new Promise((resolve, reject) => {
|
|
237
|
-
const timer = setTimeout(() => {
|
|
238
|
-
this.pending.delete(id);
|
|
239
|
-
reject(/* @__PURE__ */ new Error(`Browser action timed out: ${input.action} (${cmd.timeoutMs}ms)`));
|
|
240
|
-
}, cmd.timeoutMs);
|
|
241
|
-
this.pending.set(id, {
|
|
242
|
-
resolve,
|
|
243
|
-
reject,
|
|
244
|
-
timer
|
|
245
|
-
});
|
|
246
|
-
try {
|
|
247
|
-
this.clientWs.send(JSON.stringify(cmd));
|
|
248
|
-
} catch (e) {
|
|
249
|
-
clearTimeout(timer);
|
|
250
|
-
this.pending.delete(id);
|
|
251
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
/** Whether the extension is currently connected. */
|
|
256
|
-
isConnected() {
|
|
257
|
-
return this.connected;
|
|
258
|
-
}
|
|
259
|
-
getConnectionStatus() {
|
|
260
|
-
return {
|
|
261
|
-
socketConnected: this.socketConnected,
|
|
262
|
-
connected: this.connected,
|
|
263
|
-
protocolVersion: this.extensionProtocolVersion,
|
|
264
|
-
expectedProtocolVersion: 5,
|
|
265
|
-
extensionVersion: this.extensionVersion,
|
|
266
|
-
principalId: this.principalId
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
protocolMismatchMessage() {
|
|
270
|
-
return `Browser extension protocol mismatch (expected 5, received ${this.extensionProtocolVersion ?? "unknown"}). Reload the extension in Chrome.`;
|
|
271
|
-
}
|
|
272
|
-
/** Shutdown the WebSocket server. */
|
|
273
|
-
async shutdown() {
|
|
274
|
-
for (const waiter of this.connectionWaiters) waiter.reject(/* @__PURE__ */ new Error("Provider shutting down"));
|
|
275
|
-
this.connectionWaiters = [];
|
|
276
|
-
for (const [id, req] of this.pending) {
|
|
277
|
-
clearTimeout(req.timer);
|
|
278
|
-
req.reject(/* @__PURE__ */ new Error("Provider shutting down"));
|
|
279
|
-
this.pending.delete(id);
|
|
280
|
-
}
|
|
281
|
-
if (this.clientWs) {
|
|
282
|
-
try {
|
|
283
|
-
this.clientWs.close();
|
|
284
|
-
} catch {}
|
|
285
|
-
this.clientWs = null;
|
|
286
|
-
}
|
|
287
|
-
if (this.wss) {
|
|
288
|
-
try {
|
|
289
|
-
this.wss.close();
|
|
290
|
-
} catch {}
|
|
291
|
-
this.wss = null;
|
|
292
|
-
}
|
|
293
|
-
if (this.server) {
|
|
294
|
-
await new Promise((resolve) => {
|
|
295
|
-
this.server.close(() => resolve());
|
|
296
|
-
});
|
|
297
|
-
this.server = null;
|
|
298
|
-
}
|
|
299
|
-
this.connected = false;
|
|
300
|
-
this.socketConnected = false;
|
|
301
|
-
this.handshakeReceived = false;
|
|
302
|
-
this.extensionProtocolVersion = null;
|
|
303
|
-
this.extensionVersion = null;
|
|
304
|
-
this.connectionId = null;
|
|
305
|
-
this.principalId = null;
|
|
306
|
-
log.info("Extension provider shut down");
|
|
307
|
-
}
|
|
308
|
-
_handleMessage(raw, sourceWs) {
|
|
309
|
-
if (sourceWs !== this.clientWs) return;
|
|
310
|
-
try {
|
|
311
|
-
const msg = JSON.parse(raw);
|
|
312
|
-
if (!this.connectionId || msg.connectionId !== this.connectionId) return;
|
|
313
|
-
if (msg.type === "status") {
|
|
314
|
-
const status = msg;
|
|
315
|
-
if (status.principalId !== this.principalId) return;
|
|
316
|
-
log.debug({ sessionCount: status.sessionCount }, "Browser extension status updated");
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (isBrowserWireKeepAlive(msg)) return;
|
|
320
|
-
if (msg.type === "network_event") {
|
|
321
|
-
log.debug({
|
|
322
|
-
listenerId: msg.listenerId,
|
|
323
|
-
eventType: msg.eventType
|
|
324
|
-
}, "Network event");
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
const id = msg.id;
|
|
328
|
-
const pending = this.pending.get(id);
|
|
329
|
-
if (pending) {
|
|
330
|
-
clearTimeout(pending.timer);
|
|
331
|
-
this.pending.delete(id);
|
|
332
|
-
if (!isBrowserWireResult(msg)) {
|
|
333
|
-
pending.reject(/* @__PURE__ */ new Error("Browser extension returned an incompatible response. Reload the extension in Chrome."));
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
pending.resolve(msg);
|
|
337
|
-
}
|
|
338
|
-
} catch (e) {
|
|
339
|
-
log.error({ err: e }, "Failed to parse extension message");
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
_authenticateCandidate(raw, origin, challenge) {
|
|
343
|
-
try {
|
|
344
|
-
const message = JSON.parse(raw);
|
|
345
|
-
if (message.type !== "authenticate" || message.protocolVersion !== 5 || message.connectionId !== challenge.connectionId || `chrome-extension://${message.extensionId}` !== origin || Math.abs(Date.now() - challenge.issuedAt) > 5e3) return false;
|
|
346
|
-
const device = getDevice(message.principalId);
|
|
347
|
-
if (!device || device.revokedAt !== void 0 || device.platform !== "chrome" || device.extensionId !== message.extensionId) return false;
|
|
348
|
-
const payload = browserWireAuthenticationPayload({
|
|
349
|
-
protocolVersion: message.protocolVersion,
|
|
350
|
-
connectionId: message.connectionId,
|
|
351
|
-
challenge: challenge.challenge,
|
|
352
|
-
issuedAt: challenge.issuedAt,
|
|
353
|
-
principalId: message.principalId,
|
|
354
|
-
extensionId: message.extensionId,
|
|
355
|
-
extensionVersion: message.extensionVersion
|
|
356
|
-
});
|
|
357
|
-
return crypto.verify("sha256", Buffer.from(payload), {
|
|
358
|
-
key: crypto.createPublicKey({
|
|
359
|
-
key: device.publicKeyJwk,
|
|
360
|
-
format: "jwk"
|
|
361
|
-
}),
|
|
362
|
-
dsaEncoding: "ieee-p1363"
|
|
363
|
-
}, Buffer.from(message.signature, "base64url"));
|
|
364
|
-
} catch {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
function isBrowserWireResult(value) {
|
|
370
|
-
if (!value || typeof value !== "object") return false;
|
|
371
|
-
const result = value.result;
|
|
372
|
-
return typeof value.id === "string" && typeof value.connectionId === "string" && Boolean(result) && typeof result === "object" && typeof result.ok === "boolean";
|
|
373
|
-
}
|
|
374
|
-
function isBrowserWireKeepAlive(value) {
|
|
375
|
-
return Boolean(value) && typeof value === "object" && value.type === "keepalive" && typeof value.connectionId === "string" && typeof value.timestamp === "number";
|
|
376
|
-
}
|
|
377
|
-
//#endregion
|
|
378
|
-
export { ExtensionBrowserProvider, isBrowserWireResult };
|