@xopcai/xopc 0.0.414 → 0.0.416
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 +4 -1
- package/dist/browser-ext/_locales/zh_CN/messages.json +4 -1
- package/dist/browser-ext/dist/assets/{page-context-MuzjMBlJ.js → page-context-CVvmTWZb.js} +33 -9
- package/dist/browser-ext/dist/background.js +39 -10
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +22 -3
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-ClobpdW3.js → agent-avatar-dicebear-CufU7cqe.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DHDAcss8.js +1 -0
- package/dist/gateway/static/root/assets/agents-BV3dAoa0.js +77 -0
- package/dist/gateway/static/root/assets/{agents-admin-api-CeBkHnl8.js → agents-admin-api-B1p-ghg9.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CLunLNGp.js → app-management-settings-panel-D4-n1uBg.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DBEgoE9g.js → appearance-settings-Cgn4eNsX.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BOYzD7Zz.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-JElK4Goq.js → archive-plugin-B4btCsiV.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CZ0UqwyU.js → automations-page-yb1EL_3N.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-J7LJ4RuV.js +8 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CXFawow6.js → binary-plugins-DQT9e258.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BoduwSYI.js → block-editor-B50rU9tL.js} +30 -30
- package/dist/gateway/static/root/assets/{browser-automation-inputs-D1pDgMJu.js → browser-automation-inputs-D6AccXaA.js} +1 -1
- package/dist/gateway/static/root/assets/browser-automations-page-BiQz6lJA.js +3 -0
- package/dist/gateway/static/root/assets/browser-settings-page-W9kuxBbE.js +3 -0
- package/dist/gateway/static/root/assets/{capabilities-Bpeh6E22.js → capabilities-BlxF36t-.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-page-iXe87MdG.js +2 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CRLSXe7Z.js +8 -0
- package/dist/gateway/static/root/assets/{capability-header-actions-BasrAWA0.js → capability-header-actions-BMnbzHms.js} +1 -1
- package/dist/gateway/static/root/assets/channels-CrRJkOKX.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CwQbzcZ_.js → chat-terminal-dock-Bd3af4gL.js} +2 -2
- package/dist/gateway/static/root/assets/{computer-settings-page-DNWeJKfF.js → computer-settings-page-DXfqy7xh.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-CxHgC5RM.js → connector-service-page-B-cw0CPU.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DbFxc0Fd.js +1 -0
- package/dist/gateway/static/root/assets/{date-picker-CXxLbLJb.js → date-picker-CqzXevH6.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-DVuWMrSj.js → dependency-picker-pgT4Gyaf.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BDlg9g4s.js → desktop-pet-settings-Dy_-i2L8.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-KbVLtAlO.js → desktop-pet-zICeqw9c.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-ByGbxqkg.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-a7xEodzo.js → directory-picker-path-field-C-aQ7qoM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CHelH5u_.js → extension-debug-page-2NwpYkS5.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CrVHmS9-.js → extension-page-y9J0z7_Q.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CiMybi0r.js → extension-settings-page-BtowusUh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-DF_HV6NP.js → gateway-config-swr-fQKBHBi1.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-C52ghnBK.js +1 -0
- package/dist/gateway/static/root/assets/gateway-realtime-store-Bx9KCID-.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-BYSKzUMR.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B91CBTzO.js → gateway-startup-retry-Cfwxof4k.js} +1 -1
- package/dist/gateway/static/root/assets/highlight-code-Cz6eeDH5.js +1 -0
- package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-8ACAVktj.js → highlighted-body-KQOG7T2V-BiAa8HKC.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-Cd1BjYHj.js +2 -0
- package/dist/gateway/static/root/assets/{image-generation-api-CVBaWmrV.js → image-generation-api-gBFro48x.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-C5IP3e6d.js → imports-page-BZQpXgjj.js} +1 -1
- package/dist/gateway/static/root/assets/index-Cy16gQST.css +1 -0
- package/dist/gateway/static/root/assets/index-DRyGCING.js +710 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BhU6VYvd.js → keyboard-shortcuts-settings-CYunR34k.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-B_Ac1lly.js +1 -0
- package/dist/gateway/static/root/assets/{local-apps-page-DcP1Bdlk.js → local-apps-page-w-J5bY02.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-DvmwiLUx.js → local-session-drafts-iGX_6O0O.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-JogcXC4J.js → locale-store-B7s2Hb35.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Dnjvvx2i.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-w1EDwgLW.js +1 -0
- package/dist/gateway/static/root/assets/{media-plugins-BnPpcJ2J.js → media-plugins-CIx1koXw.js} +1 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-DISkHmEC.js +1 -0
- package/dist/gateway/static/root/assets/{messages-RzwPiQNL.js → messages-BYq0cPbn.js} +2 -2
- package/dist/gateway/static/root/assets/note-detail-panel-CNkxMTFU.js +5 -0
- package/dist/gateway/static/root/assets/note-image-lightbox-D5GH2wuC.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-DZgKqFBG.js +8 -0
- package/dist/gateway/static/root/assets/page-context-capture-button-DusR2Itk.js +1 -0
- package/dist/gateway/static/root/assets/personal-page-CR5JFkQ9.js +1 -0
- package/dist/gateway/static/root/assets/personal-settings-panel-B7undvlr.js +1 -0
- package/dist/gateway/static/root/assets/phone-model-picker-fWDltRUJ.js +1 -0
- package/dist/gateway/static/root/assets/phone-settings-page-CsOirAiy.js +1 -0
- package/dist/gateway/static/root/assets/plugin-details-dialog-BOBVIB3j.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-FGqN-mQx.js → preview-open-alternatives-CMxjsKSw.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CwnHLfdL.js → product-open-page-CrlyJx5M.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-BD6k5hF9.js → product-preview-content-B-Jhzi7W.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DoYUbtcI.js +7 -0
- package/dist/gateway/static/root/assets/projects-page-xGQd9oAZ.js +1 -0
- package/dist/gateway/static/root/assets/refresh-cw-BRlGaq2w.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-BGqSwITi.js → registry-api-BcfoLEna.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-Gs0Xkws9.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-api-CSm5SpnR.js → runtime-tools-api-DesqGCnE.js} +1 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bwg7U7TR.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-DoVn5jJK.js → schema-form-ByzTNR_C.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-DTxZyMta.js → session-api-DdQnMwkl.js} +1 -1
- package/dist/gateway/static/root/assets/{session-manager-B2HDomj4.js → session-manager-B_h0jlLb.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-XzK1ftbR.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D_8Mvnog.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Ce8vVv-9.js → settings-form-section-Brgd8IOV.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DP2w3ejC.js → settings-page-B6Mv02eg.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-header-BWyxJKOG.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-B20AfmFG.js → settings-page-layout-DLHcS-0T.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DSCj5yis.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DV4dKrmG.js → share-preview-page-DF8Of0aZ.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DXNPe4Tl.js +1 -0
- package/dist/gateway/static/root/assets/{skill-api-DTdejInH.js → skill-api-CKCDCHLq.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BH0WF6Br.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DFWMVRW4.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-DB-ttubV.js +1 -0
- package/dist/gateway/static/root/assets/task-detail-page-BJY7c8wb.js +2 -0
- package/dist/gateway/static/root/assets/{task-result-evidence-DIGSC4qF.js → task-result-evidence-B-vt1BgK.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-BaU8frtc.js → tracing-settings-page-Dt51Z_ws.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-BCcOUsqu.js → tunnel-api-Dok3t7Qe.js} +1 -1
- package/dist/gateway/static/root/assets/usage-page-lJym5G7F.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-C1X47WVb.js → use-autosave-D4EMIB-V.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-BXdNkITp.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-Bk4DQMTw.js → voice-api-key-field-CO3KuanA.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-D7xsWrdh.js → voice-config-api-BkUlN7GH.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-B7_NmTB5.js → work-discovery-overlay-BJRtgQM3.js} +1 -1
- package/dist/gateway/static/root/assets/wrench-DFb4r8bH.js +1 -0
- package/dist/gateway/static/root/assets/xopc-cloud-account-card-CS-_GxHV.js +1 -0
- package/dist/gateway/static/root/browser-setup-test.html +5 -0
- package/dist/gateway/static/root/browser-setup-test.js +7 -0
- package/dist/gateway/static/root/index.html +17 -14
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/browser-setup.js +6 -0
- package/dist/packages/gateway-contract/src/index.js +4 -0
- package/dist/packages/gateway-contract/src/phone-setup.js +6 -0
- package/dist/packages/realtime-client/src/index.js +1 -0
- package/dist/packages/realtime-protocol/src/index.js +1 -0
- package/dist/src/agent/agent-manager.d.ts +4 -0
- package/dist/src/agent/agent-manager.js +12 -1
- package/dist/src/agent/coding/workspace-revision.js +1 -1
- package/dist/src/agent/commands/command-registry.js +1 -1
- package/dist/src/agent/embedded/tool-search-extension.js +14 -1
- package/dist/src/agent/memory/context-recovery.d.ts +1 -1
- package/dist/src/agent/service.d.ts +1 -0
- package/dist/src/agent/service.js +5 -0
- package/dist/src/agent/service.types.d.ts +2 -0
- package/dist/src/agent/skills/installer.js +3 -3
- package/dist/src/agent/tool-manuals/phone.d.ts +1 -1
- package/dist/src/agent/tool-manuals/phone.js +4 -2
- package/dist/src/agent/tool-manuals/xopc-configuration.d.ts +2 -0
- package/dist/src/agent/tool-manuals/xopc-configuration.js +25 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +2 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +6 -2
- package/dist/src/agent/tools/factory.d.ts +3 -0
- package/dist/src/agent/tools/factory.js +11 -1
- package/dist/src/agent/tools/personal-task-tool.d.ts +1 -1
- package/dist/src/agent/tools/personal-task-tool.js +23 -21
- package/dist/src/agent/tools/phone-use-tool.d.ts +1 -0
- package/dist/src/agent/tools/phone-use-tool.js +29 -1
- package/dist/src/agent/tools/tool-manual-tool.d.ts +1 -1
- package/dist/src/agent/tools/tool-manual-tool.js +3 -1
- package/dist/src/agent/tools/toolExposure.js +3 -0
- package/dist/src/agent/tools/xopc-use-tool.d.ts +4 -2
- package/dist/src/agent/tools/xopc-use-tool.js +40 -2
- package/dist/src/backup/archive.js +2 -1
- package/dist/src/browser/drivers/browser-driver.d.ts +2 -2
- package/dist/src/browser/drivers/extension-driver.d.ts +2 -2
- package/dist/src/browser/drivers/extension-driver.js +6 -3
- package/dist/src/browser/providers/browser-ext-install.js +3 -2
- package/dist/src/browser/runtime/browser-runtime.d.ts +4 -1
- package/dist/src/browser/runtime/browser-runtime.js +29 -17
- package/dist/src/browser/setup/repository.d.ts +5 -0
- package/dist/src/browser/setup/repository.js +42 -0
- package/dist/src/browser/setup/service.d.ts +152 -0
- package/dist/src/browser/setup/service.js +404 -0
- package/dist/src/browser/setup/types.d.ts +38 -0
- package/dist/src/browser/setup/types.js +1 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +3 -3
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/extension.js +2 -2
- package/dist/src/config/schema.d.ts +2 -0
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/browser-setup.d.ts +3 -0
- package/dist/src/gateway/hono/routes/browser-setup.js +114 -0
- package/dist/src/gateway/hono/routes/browser.d.ts +2 -1
- package/dist/src/gateway/hono/routes/browser.js +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/phone-dependencies.js +1 -1
- package/dist/src/gateway/hono/routes/phone-setup.d.ts +7 -0
- package/dist/src/gateway/hono/routes/phone-setup.js +162 -0
- package/dist/src/gateway/hono/routes/phone.js +11 -7
- package/dist/src/gateway/hono/routes/public-gateway.js +2 -0
- package/dist/src/gateway/provider-model-setup.js +1 -1
- package/dist/src/gateway/service/config-coordinator.d.ts +2 -0
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/session-input-coordinator.js +1 -1
- package/dist/src/gateway/service.d.ts +5 -0
- package/dist/src/gateway/service.js +52 -7
- package/dist/src/gateway/xopc-cloud-capability-setup.js +7 -1
- package/dist/src/home-intelligence/host.js +2 -2
- package/dist/src/infra/unhandled-rejections.js +2 -2
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/personal-agent/prompts.js +1 -1
- package/dist/src/phone/adb-driver.d.ts +8 -2
- package/dist/src/phone/adb-driver.js +124 -54
- package/dist/src/phone/cloud-adb.js +8 -0
- package/dist/src/phone/cloud-scrcpy.d.ts +3 -1
- package/dist/src/phone/cloud-scrcpy.js +17 -3
- package/dist/src/phone/contracts.d.ts +85 -0
- package/dist/src/phone/contracts.js +31 -5
- package/dist/src/phone/model-adapter.d.ts +141 -2
- package/dist/src/phone/model-adapter.js +176 -24
- package/dist/src/phone/numeric-entry.d.ts +31 -0
- package/dist/src/phone/numeric-entry.js +126 -0
- package/dist/src/phone/planning.d.ts +27 -0
- package/dist/src/phone/planning.js +79 -0
- package/dist/src/phone/recovery.d.ts +37 -0
- package/dist/src/phone/recovery.js +81 -0
- package/dist/src/phone/reliability.d.ts +7 -0
- package/dist/src/phone/reliability.js +66 -0
- package/dist/src/phone/repository.d.ts +1 -0
- package/dist/src/phone/repository.js +3 -0
- package/dist/src/phone/runtime.d.ts +8 -0
- package/dist/src/phone/runtime.js +387 -41
- package/dist/src/phone/scrcpy-text.d.ts +11 -0
- package/dist/src/phone/scrcpy-text.js +72 -0
- package/dist/src/phone/scrcpy.d.ts +5 -1
- package/dist/src/phone/scrcpy.js +48 -3
- package/dist/src/phone/semantic-controls.d.ts +13 -0
- package/dist/src/phone/semantic-controls.js +76 -0
- package/dist/src/phone/setup/service.d.ts +148 -0
- package/dist/src/phone/setup/service.js +251 -0
- package/dist/src/providers/presentation.js +2 -2
- package/dist/src/providers/xopc-cloud-model-source.js +6 -2
- package/dist/src/realtime/runtime.js +1 -1
- package/dist/src/storage/sqlite/connection.js +2 -2
- package/dist/src/storage/sqlite/offline-access.js +13 -7
- package/dist/src/storage/sqlite/schema-errors.d.ts +12 -0
- package/dist/src/storage/sqlite/schema-errors.js +21 -3
- package/dist/src/storage/sqlite/schema-upgrade.d.ts +4 -0
- package/dist/src/storage/sqlite/schema-upgrade.js +78 -0
- package/dist/src/storage/sqlite/schema.d.ts +4 -3
- package/dist/src/storage/sqlite/schema.js +14 -8
- package/dist/src/storage/sqlite/schema.sql +10 -0
- package/dist/src/storage/sqlite/upgrades/203_remove_retired_proactive_contracts.sql +70 -0
- package/dist/src/storage/sqlite/upgrades/204_home_intelligence.sql +78 -0
- package/dist/src/storage/sqlite/upgrades/205_agent_catalog.sql +66 -0
- package/dist/src/storage/sqlite/upgrades/206_home_advice_strategy_version.sql +2 -0
- package/dist/src/storage/sqlite/upgrades/207_user_model_policy_contract.sql +121 -0
- package/dist/src/storage/sqlite/upgrades/208_automation_management.sql +2 -0
- package/dist/src/storage/sqlite/upgrades/209_automation_event_hub.sql +48 -0
- package/dist/src/storage/sqlite/upgrades/210_remove_legacy_automation_timeout.sql +14 -0
- package/dist/src/storage/sqlite/upgrades/211_automation_result_deliveries.sql +16 -0
- package/dist/src/storage/sqlite/upgrades/212_automation_delivery_policy.sql +30 -0
- package/dist/src/storage/sqlite/upgrades/213_automation_reliability_contract.sql +188 -0
- package/dist/src/storage/sqlite/upgrades/214_ai_usage_ledger.sql +41 -0
- package/dist/src/storage/sqlite/upgrades/215_scene_execution_adapters.sql +6 -0
- package/dist/src/storage/sqlite/upgrades/216_remove_scene_model_usage.sql +1 -0
- package/dist/src/storage/sqlite/upgrades/217_remove_legacy_memory_tables.sql +4 -0
- package/dist/src/storage/sqlite/upgrades/218_core_relation_indexes.sql +26 -0
- package/dist/src/storage/sqlite/upgrades/219_json_contracts.sql +123 -0
- package/dist/src/storage/sqlite/upgrades/220_normalize_timestamps.sql +339 -0
- package/dist/src/storage/sqlite/upgrades/221_ai_usage_retention_index.sql +2 -0
- package/dist/src/storage/sqlite/upgrades/222_session_config_authority.sql +13 -0
- package/dist/src/storage/sqlite/upgrades/223_session_creation_receipts.sql +59 -0
- package/dist/src/storage/sqlite/upgrades/224_task_origin_links.sql +8 -0
- package/dist/src/storage/sqlite/upgrades/225_task_collaboration.sql +32 -0
- package/dist/src/storage/sqlite/upgrades/226_task_main_updates.sql +9 -0
- package/dist/src/storage/sqlite/upgrades/227_task_main_update_decisions.sql +8 -0
- package/dist/src/storage/sqlite/upgrades/228_task_main_agent_links.sql +14 -0
- package/dist/src/storage/sqlite/upgrades/229_task_criterion_reviews.sql +12 -0
- package/dist/src/storage/sqlite/upgrades/230_personal_agent_onboarding.sql +8 -0
- package/dist/src/storage/sqlite/upgrades/231_task_result_deliveries.sql +32 -0
- package/dist/src/storage/sqlite/upgrades/232_personal_requests.sql +28 -0
- package/dist/src/storage/sqlite/upgrades/233_observability_usage_links.sql +3 -0
- package/dist/src/storage/sqlite/upgrades/234_task_result_reply.sql +14 -0
- package/dist/src/storage/sqlite/upgrades/235_personal_conversation_priority.sql +3 -0
- package/dist/src/storage/sqlite/upgrades/236_personal_proactivity.sql +53 -0
- package/dist/src/storage/sqlite/upgrades/237_personal_strategy_versions.sql +18 -0
- package/dist/src/storage/sqlite/upgrades/238_browser_record_replay.sql +45 -0
- package/dist/src/storage/sqlite/upgrades/239_clarification_notifications.sql +26 -0
- package/dist/src/storage/sqlite/upgrades/240_device_settings.sql +5 -0
- package/dist/src/storage/sqlite/upgrades/241_device_grant_audit.sql +13 -0
- package/dist/src/storage/sqlite/upgrades/242_cloud_usage_receipts.sql +5 -0
- package/dist/src/storage/sqlite/upgrades/243_voice_opening_greetings.sql +12 -0
- package/dist/src/storage/sqlite/upgrades/244_device_request_proofs.sql +8 -0
- package/dist/src/storage/sqlite/upgrades/245_memory_learning.sql +125 -0
- package/dist/src/storage/sqlite/upgrades/246_personal_session_thinking.sql +22 -0
- package/dist/src/storage/sqlite/upgrades/247_agent_selection_records.sql +32 -0
- package/dist/src/storage/sqlite/upgrades/248_next_turn_suggestions.sql +20 -0
- package/dist/src/storage/sqlite/upgrades/249_task_allocations.sql +17 -0
- package/dist/src/storage/sqlite/upgrades/250_research_checkpoints.sql +15 -0
- package/dist/src/storage/sqlite/upgrades/251_personal_result_reads.sql +40 -0
- package/dist/src/storage/sqlite/upgrades/252_task_work_revisions.sql +15 -0
- package/dist/src/storage/sqlite/upgrades/253_discussion_processing_recovery.sql +20 -0
- package/dist/src/storage/sqlite/upgrades/254_discussion_annotations.sql +17 -0
- package/dist/src/storage/sqlite/upgrades/255_discussion_chapter_progress.sql +10 -0
- package/dist/src/storage/sqlite/upgrades/256_task_main_update_retries.sql +21 -0
- package/dist/src/storage/sqlite/upgrades/257_session_composer_history.sql +11 -0
- package/dist/src/storage/sqlite/upgrades/258_task_phase_changes.sql +20 -0
- package/dist/src/storage/sqlite/upgrades/259_personal_default_style.sql +10 -0
- package/dist/src/storage/sqlite/upgrades/260_browser_setup.sql +9 -0
- package/dist/src/storage/sqlite/windows-database-owners.js +33 -28
- package/dist/src/tasks/capabilities/relations.d.ts +2 -2
- package/dist/src/tui/clipboard-image.js +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/logger/index.js +1 -1
- package/dist/src/utils/logger.js +1 -1
- package/dist/src/work-discovery/probe.js +1 -1
- package/package.json +3 -3
- package/skills/tools/configure-xopc/SKILL.md +47 -0
- package/skills/tools/configure-xopc/references/browser/acceptance.md +31 -0
- package/skills/tools/configure-xopc/references/browser/chrome-extension.md +19 -0
- package/skills/tools/configure-xopc/references/browser/overview.md +22 -0
- package/skills/tools/configure-xopc/references/browser/permissions.md +25 -0
- package/skills/tools/configure-xopc/references/browser/troubleshooting.md +24 -0
- package/skills/tools/configure-xopc/references/phone/acceptance.md +25 -0
- package/skills/tools/configure-xopc/references/phone/aliyun.md +29 -0
- package/skills/tools/configure-xopc/references/phone/dependencies.md +18 -0
- package/skills/tools/configure-xopc/references/phone/local.md +19 -0
- package/skills/tools/configure-xopc/references/phone/models.md +18 -0
- package/skills/tools/configure-xopc/references/phone/overview.md +30 -0
- package/skills/tools/configure-xopc/references/phone/troubleshooting.md +24 -0
- package/skills/tools/configure-xopc/references/scene-index.md +12 -0
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-mf0jgEPE.js +0 -1
- package/dist/gateway/static/root/assets/agents-CKhZ4UYQ.js +0 -77
- package/dist/gateway/static/root/assets/apps-page-BZ_MaQJf.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CHUDHNVL.js +0 -8
- package/dist/gateway/static/root/assets/browser-automations-page-DStDm9y1.js +0 -3
- package/dist/gateway/static/root/assets/browser-settings-page-6I4oetKt.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-page-C-EecWbS.js +0 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BQoCPk3x.js +0 -8
- package/dist/gateway/static/root/assets/channels-BKf_-Mdt.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CUBg8spT.js +0 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-PmP_vGem.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-DMAzNlm-.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-CoIgC1Al.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-DnrQ28E2.js +0 -1
- package/dist/gateway/static/root/assets/highlight-code-AMjU04kR.js +0 -1
- package/dist/gateway/static/root/assets/home-page-pTwVME-g.js +0 -2
- package/dist/gateway/static/root/assets/index-BLL0wKRZ.css +0 -1
- package/dist/gateway/static/root/assets/index-ygkHNYyo.js +0 -710
- package/dist/gateway/static/root/assets/local-app-workbench-page-Cwl6EvuX.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CS3hcTOq.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-DC-Y_-GP.js +0 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-vckgHpON.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-C7u4dxEk.js +0 -5
- package/dist/gateway/static/root/assets/note-image-lightbox-jvqYtySx.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-Bs7F5Hpf.js +0 -8
- package/dist/gateway/static/root/assets/page-context-capture-button-DO_yhXS1.js +0 -1
- package/dist/gateway/static/root/assets/personal-page-BexL2-PQ.js +0 -1
- package/dist/gateway/static/root/assets/personal-settings-panel-BKA4fbYH.js +0 -1
- package/dist/gateway/static/root/assets/phone-dependencies-card-ChFtdFhA.js +0 -1
- package/dist/gateway/static/root/assets/phone-model-picker-CZoIAQ1j.js +0 -1
- package/dist/gateway/static/root/assets/phone-settings-page-DRyK0nHH.js +0 -1
- package/dist/gateway/static/root/assets/plugin-details-dialog-B-N61jJH.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DtKmFBml.js +0 -7
- package/dist/gateway/static/root/assets/projects-page-CFZIz9mc.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CWEc7W0m.js +0 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-q_oswAdV.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BuPqNxpd.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-QTVDCGJG.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-header-CYpuTXUW.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-ZmlE8jIE.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CtNxWqW-.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Egaf8PqZ.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-C6FKxf4J.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-Baxkhov7.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-C77-rpkt.js +0 -2
- package/dist/gateway/static/root/assets/usage-page-BFeIbpbi.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-u8zY5jea.js +0 -2
- package/dist/gateway/static/root/assets/xopc-cloud-account-card-CJ_akAvc.js +0 -1
|
@@ -8,9 +8,15 @@ import { PhoneInteractiveSession } from "./interactive-session.js";
|
|
|
8
8
|
import { AdbPhoneDriver, resolveAdbPath } from "./adb-driver.js";
|
|
9
9
|
import { LocalScrcpyProvider } from "./scrcpy.js";
|
|
10
10
|
import { CloudPhones } from "./cloud-phones.js";
|
|
11
|
+
import { advancePhonePlan, buildPhonePlan, createPhonePlanState } from "./planning.js";
|
|
12
|
+
import { canDispatchPhoneAction, observationSignature, phoneCompletionSatisfied } from "./reliability.js";
|
|
13
|
+
import { groundPhoneCoordinateAction, resolvePhoneSemanticAction } from "./semantic-controls.js";
|
|
11
14
|
import { createPhoneModel, isAboutScreen } from "./model-adapter.js";
|
|
12
15
|
import { PhoneRepository } from "./repository.js";
|
|
16
|
+
import { confirmPhoneFocusRecovery, phoneBackRecovery, phoneUnfocusedTypingHint, preparePhoneFocusRecovery } from "./recovery.js";
|
|
17
|
+
import { createPhoneNumericEntry, nextPhoneNumericEntry } from "./numeric-entry.js";
|
|
13
18
|
import { createHash, randomUUID } from "node:crypto";
|
|
19
|
+
import { setTimeout } from "node:timers/promises";
|
|
14
20
|
//#region src/phone/runtime.ts
|
|
15
21
|
init_logger();
|
|
16
22
|
init_contracts();
|
|
@@ -58,6 +64,16 @@ var PhoneRuntime = class {
|
|
|
58
64
|
if (!driver.applications) throw new PhoneError("PHONE_APPS_UNAVAILABLE", "The phone provider cannot list applications");
|
|
59
65
|
return driver.applications(serial, signal);
|
|
60
66
|
}
|
|
67
|
+
async textInputStatus(id, config, signal) {
|
|
68
|
+
const device = this.repository.get(id);
|
|
69
|
+
if (!device.enabled) throw new PhoneError("PHONE_DEVICE_DENIED", "Phone access is disabled", 403);
|
|
70
|
+
const driver = await this.driverFor(device, config);
|
|
71
|
+
if (!driver.textInputStatus) throw new PhoneError("PHONE_TEXT_INPUT_UNAVAILABLE", "This phone provider does not expose text input diagnostics", 409);
|
|
72
|
+
return {
|
|
73
|
+
...await driver.textInputStatus(device.serial, signal),
|
|
74
|
+
policy: device.textInput ?? "auto"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
61
77
|
async preview(id, config, signal) {
|
|
62
78
|
const device = this.repository.get(id);
|
|
63
79
|
if (!device.enabled) throw new PhoneError("PHONE_DEVICE_DENIED", "Phone access is disabled", 403);
|
|
@@ -168,6 +184,9 @@ var PhoneRuntime = class {
|
|
|
168
184
|
adbPath,
|
|
169
185
|
context,
|
|
170
186
|
applications,
|
|
187
|
+
trajectory: [],
|
|
188
|
+
trajectoryCount: 0,
|
|
189
|
+
trajectorySummary: [],
|
|
171
190
|
frames: new PhoneFrameCache(),
|
|
172
191
|
io: Promise.resolve(),
|
|
173
192
|
ioBusy: false,
|
|
@@ -194,7 +213,13 @@ var PhoneRuntime = class {
|
|
|
194
213
|
updatedAt: now,
|
|
195
214
|
verified: false,
|
|
196
215
|
verificationLevel: "none",
|
|
197
|
-
steps: []
|
|
216
|
+
steps: [],
|
|
217
|
+
diagnostics: {
|
|
218
|
+
stalePredictions: 0,
|
|
219
|
+
protocolRepairs: 0,
|
|
220
|
+
unchangedActions: 0,
|
|
221
|
+
completionCorrections: 0
|
|
222
|
+
}
|
|
198
223
|
}
|
|
199
224
|
};
|
|
200
225
|
this.sessions.set(owner, session);
|
|
@@ -206,7 +231,7 @@ var PhoneRuntime = class {
|
|
|
206
231
|
await this.dispatch(session, {
|
|
207
232
|
type: "launch",
|
|
208
233
|
package: input.appPackage
|
|
209
|
-
}, observation, context, signal, epoch);
|
|
234
|
+
}, observation, context, signal, epoch, false, input.settingsPage);
|
|
210
235
|
} finally {
|
|
211
236
|
observation.frame.fill(0);
|
|
212
237
|
}
|
|
@@ -259,6 +284,9 @@ var PhoneRuntime = class {
|
|
|
259
284
|
const startedAt = Date.now();
|
|
260
285
|
session.report.errorCode = void 0;
|
|
261
286
|
session.report.verified = false;
|
|
287
|
+
session.report.verificationLevel = "none";
|
|
288
|
+
session.report.stopReason = void 0;
|
|
289
|
+
session.report.message = void 0;
|
|
262
290
|
try {
|
|
263
291
|
await this.waitForAgent(session, signal);
|
|
264
292
|
session.report.status = "running";
|
|
@@ -282,7 +310,42 @@ var PhoneRuntime = class {
|
|
|
282
310
|
if (session.report.mode !== "control") throw new PhoneError("PHONE_OBSERVE_ONLY", "Reopen the phone in control mode to execute actions");
|
|
283
311
|
if (session.report.mock && input.scenario !== "settings-about") throw new PhoneError("PHONE_MOCK_SCENARIO_REQUIRED", "Mock mode only supports the explicit settings-about scenario");
|
|
284
312
|
const maxActions = input.op === "step" ? 1 : input.maxActions;
|
|
313
|
+
const requiredTexts = [...input.completion?.textAll ?? [], ...input.expectText ? [input.expectText] : []];
|
|
314
|
+
const completion = input.completion || input.expectText ? {
|
|
315
|
+
...input.completion,
|
|
316
|
+
textAll: requiredTexts.length ? requiredTexts : void 0
|
|
317
|
+
} : void 0;
|
|
285
318
|
let actions = 0;
|
|
319
|
+
let protocolFeedback;
|
|
320
|
+
let repairs = 0;
|
|
321
|
+
let completionCorrections = 0;
|
|
322
|
+
let recoveryHint;
|
|
323
|
+
const enhancements = {
|
|
324
|
+
semanticControls: context.config.phone.semanticControls,
|
|
325
|
+
hierarchicalPlanning: context.config.phone.hierarchicalPlanning
|
|
326
|
+
};
|
|
327
|
+
const derivedPlan = enhancements.hierarchicalPlanning ? buildPhonePlan(input.goal, completion) : void 0;
|
|
328
|
+
let planning = derivedPlan ? createPhonePlanState(derivedPlan) : void 0;
|
|
329
|
+
if (enhancements.hierarchicalPlanning) {
|
|
330
|
+
session.report.diagnostics.plannedSubgoals = planning?.steps.length ?? 0;
|
|
331
|
+
session.report.diagnostics.completedSubgoals = 0;
|
|
332
|
+
}
|
|
333
|
+
let changed = false;
|
|
334
|
+
const entryObservation = {
|
|
335
|
+
...observation,
|
|
336
|
+
frame: Buffer.alloc(0),
|
|
337
|
+
elements: structuredClone(observation.elements)
|
|
338
|
+
};
|
|
339
|
+
const trajectoryStart = session.trajectoryCount;
|
|
340
|
+
let pendingFocus;
|
|
341
|
+
let numericIntent;
|
|
342
|
+
let numericPending;
|
|
343
|
+
const focusedIntents = /* @__PURE__ */ new Set();
|
|
344
|
+
let backReplans = 0;
|
|
345
|
+
let focusReplans = 0;
|
|
346
|
+
let previousSignature = observationSignature(observation);
|
|
347
|
+
let controlEpoch = session.report.controlEpoch;
|
|
348
|
+
const attempts = /* @__PURE__ */ new Map();
|
|
286
349
|
while (true) {
|
|
287
350
|
if (await this.waitForAgent(session, signal)) {
|
|
288
351
|
observation.frame.fill(0);
|
|
@@ -292,45 +355,151 @@ var PhoneRuntime = class {
|
|
|
292
355
|
this.guard(session, context);
|
|
293
356
|
this.allowedScreen(session, observation);
|
|
294
357
|
const epoch = session.report.controlEpoch;
|
|
358
|
+
if (controlEpoch !== epoch) {
|
|
359
|
+
attempts.clear();
|
|
360
|
+
recoveryHint = "The user handed back control. Re-evaluate the fresh screen before continuing.";
|
|
361
|
+
pendingFocus = void 0;
|
|
362
|
+
numericIntent = void 0;
|
|
363
|
+
numericPending = void 0;
|
|
364
|
+
controlEpoch = epoch;
|
|
365
|
+
}
|
|
366
|
+
const signature = observationSignature(observation);
|
|
367
|
+
if (signature !== previousSignature) changed = true;
|
|
368
|
+
previousSignature = signature;
|
|
295
369
|
this.recordObservation(session, observation);
|
|
296
|
-
if (
|
|
297
|
-
|
|
298
|
-
session.report.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
370
|
+
if (planning) {
|
|
371
|
+
planning = advancePhonePlan(planning, observation);
|
|
372
|
+
session.report.diagnostics.completedSubgoals = planning.verifiedSteps;
|
|
373
|
+
}
|
|
374
|
+
let numericStep;
|
|
375
|
+
if (enhancements.hierarchicalPlanning) {
|
|
376
|
+
numericIntent ??= createPhoneNumericEntry(input.goal, completion, observation);
|
|
377
|
+
if (numericIntent) {
|
|
378
|
+
let next = nextPhoneNumericEntry(numericIntent, observation, numericPending);
|
|
379
|
+
for (let poll = 0; numericPending && next.kind === "blocked" && poll < 2; poll++) {
|
|
380
|
+
await setTimeout(150, void 0, { signal });
|
|
381
|
+
observation.frame.fill(0);
|
|
382
|
+
observation = await this.observe(session, signal);
|
|
383
|
+
this.guard(session, context);
|
|
384
|
+
this.allowedScreen(session, observation);
|
|
385
|
+
if (epoch !== session.report.controlEpoch || session.report.controlOwner !== "agent") break;
|
|
386
|
+
next = nextPhoneNumericEntry(numericIntent, observation, numericPending);
|
|
387
|
+
}
|
|
388
|
+
if (epoch !== session.report.controlEpoch || session.report.controlOwner !== "agent") continue;
|
|
389
|
+
this.recordObservation(session, observation);
|
|
390
|
+
if (next.kind === "blocked") {
|
|
391
|
+
session.report.diagnostics.numericMismatches = (session.report.diagnostics.numericMismatches ?? 0) + 1;
|
|
392
|
+
session.report.status = "paused";
|
|
393
|
+
session.report.controlOwner = "none";
|
|
394
|
+
session.report.controlEpoch++;
|
|
395
|
+
session.report.stopReason = "numeric_state_mismatch";
|
|
396
|
+
session.report.message = "Numeric input was not confirmed. Inspect the displayed value before continuing; no key was retried.";
|
|
397
|
+
session.budget?.pause();
|
|
398
|
+
await session.stream?.revoke();
|
|
399
|
+
return this.publish(session);
|
|
400
|
+
}
|
|
401
|
+
if (numericPending) session.report.diagnostics.numericConfirmedSteps = (session.report.diagnostics.numericConfirmedSteps ?? 0) + 1;
|
|
402
|
+
numericPending = void 0;
|
|
403
|
+
if (next.kind === "action") numericStep = next.step;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (session.report.mock ? isAboutScreen(observation) : Boolean(completion && phoneCompletionSatisfied(completion, observation, changed))) {
|
|
407
|
+
const confirmation = await this.observe(session, signal);
|
|
408
|
+
try {
|
|
409
|
+
signal.throwIfAborted();
|
|
410
|
+
this.guard(session, context);
|
|
411
|
+
this.allowedScreen(session, confirmation);
|
|
412
|
+
const confirmed = session.report.mock ? isAboutScreen(confirmation) : Boolean(completion && phoneCompletionSatisfied(completion, confirmation, changed));
|
|
413
|
+
if (epoch !== session.report.controlEpoch || session.report.controlOwner !== "agent" || !confirmed) {
|
|
414
|
+
observation.frame.fill(0);
|
|
415
|
+
observation = confirmation;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
this.recordObservation(session, confirmation);
|
|
419
|
+
if (planning) {
|
|
420
|
+
planning = advancePhonePlan(planning, confirmation);
|
|
421
|
+
session.report.diagnostics.completedSubgoals = planning.verifiedSteps;
|
|
422
|
+
}
|
|
423
|
+
session.report.verified = true;
|
|
424
|
+
session.report.verificationLevel = "ui";
|
|
425
|
+
session.report.status = "completed";
|
|
426
|
+
session.report.stopReason = actions ? "condition_satisfied" : "condition_present";
|
|
427
|
+
return this.publish(session);
|
|
428
|
+
} finally {
|
|
429
|
+
if (observation !== confirmation) confirmation.frame.fill(0);
|
|
430
|
+
}
|
|
302
431
|
}
|
|
303
432
|
if (actions >= maxActions) {
|
|
304
433
|
session.report.status = "ready";
|
|
305
434
|
session.report.stopReason = "action_limit";
|
|
306
435
|
return this.publish(session);
|
|
307
436
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
437
|
+
let decision = numericStep ? {
|
|
438
|
+
kind: "action",
|
|
439
|
+
action: numericStep.action
|
|
440
|
+
} : void 0;
|
|
441
|
+
let resumedText = false;
|
|
442
|
+
if (!decision && pendingFocus) {
|
|
443
|
+
const pending = pendingFocus;
|
|
444
|
+
pendingFocus = void 0;
|
|
445
|
+
const intended = confirmPhoneFocusRecovery(pending, observation);
|
|
446
|
+
if (intended) {
|
|
447
|
+
decision = {
|
|
448
|
+
kind: "action",
|
|
449
|
+
action: intended
|
|
450
|
+
};
|
|
451
|
+
resumedText = true;
|
|
452
|
+
} else recoveryHint = "The focus transition was not confirmed. No text was sent. Reinspect the intended editable field before another action.";
|
|
453
|
+
}
|
|
454
|
+
if (!decision) {
|
|
455
|
+
if (session.report.modelRequests >= context.config.phone.maxModelRequests) throw new PhoneError("PHONE_MODEL_LIMIT", "Phone model request limit reached");
|
|
456
|
+
session.report.modelRequests++;
|
|
457
|
+
session.report.currentAction = void 0;
|
|
458
|
+
this.publish(session);
|
|
459
|
+
session.prediction = new AbortController();
|
|
460
|
+
try {
|
|
461
|
+
decision = await session.adapter.predict({
|
|
462
|
+
goal: input.goal,
|
|
463
|
+
observation,
|
|
464
|
+
completion,
|
|
465
|
+
allowedApps: session.device.allowedApps,
|
|
466
|
+
appAccess: phoneAppAccess(session.device),
|
|
467
|
+
applications: session.applications.filter((app) => phoneAllowsApp(session.device, app.packageName)),
|
|
468
|
+
history: session.report.steps.map((step) => step.action),
|
|
469
|
+
trajectory: session.trajectory,
|
|
470
|
+
progressSummary: JSON.stringify({
|
|
471
|
+
dispatched: session.trajectoryCount,
|
|
472
|
+
earlier: [...session.trajectorySummary, ...session.trajectory.slice(0, -8).map((entry) => JSON.stringify({
|
|
473
|
+
action: entry.action,
|
|
474
|
+
effect: entry.effect,
|
|
475
|
+
afterApp: entry.afterApp
|
|
476
|
+
}).slice(0, 250))].slice(-12)
|
|
477
|
+
}).slice(-1500),
|
|
478
|
+
recoveryHint,
|
|
479
|
+
protocolFeedback,
|
|
480
|
+
scenario: input.scenario,
|
|
481
|
+
enhancements,
|
|
482
|
+
planning
|
|
483
|
+
}, AbortSignal.any([signal, session.prediction.signal]));
|
|
484
|
+
} catch (error) {
|
|
485
|
+
if (!signal.aborted && epoch !== session.report.controlEpoch) {
|
|
486
|
+
await this.waitForAgent(session, signal);
|
|
487
|
+
observation.frame.fill(0);
|
|
488
|
+
observation = await this.observe(session, signal);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
if (!signal.aborted && error instanceof PhoneError && ["PHONE_MODEL_PROTOCOL", "PHONE_MODEL_TRUNCATED"].includes(error.code) && repairs < 1 && session.report.modelRequests < context.config.phone.maxModelRequests) {
|
|
492
|
+
repairs++;
|
|
493
|
+
session.report.diagnostics.protocolRepairs++;
|
|
494
|
+
protocolFeedback = "Your previous output was invalid or truncated. Return exactly one complete action in the specified format with no extra prose.";
|
|
495
|
+
observation.frame.fill(0);
|
|
496
|
+
observation = await this.observe(session, signal);
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
throw error;
|
|
500
|
+
} finally {
|
|
501
|
+
session.prediction = void 0;
|
|
330
502
|
}
|
|
331
|
-
throw error;
|
|
332
|
-
} finally {
|
|
333
|
-
session.prediction = void 0;
|
|
334
503
|
}
|
|
335
504
|
signal.throwIfAborted();
|
|
336
505
|
this.guard(session, context);
|
|
@@ -340,9 +509,26 @@ var PhoneRuntime = class {
|
|
|
340
509
|
observation = await this.observe(session, signal);
|
|
341
510
|
continue;
|
|
342
511
|
}
|
|
512
|
+
protocolFeedback = void 0;
|
|
513
|
+
if (enhancements.hierarchicalPlanning && !planning && decision.plan) {
|
|
514
|
+
planning = advancePhonePlan(createPhonePlanState(decision.plan), observation);
|
|
515
|
+
session.report.diagnostics.plannedSubgoals = planning.steps.length;
|
|
516
|
+
session.report.diagnostics.completedSubgoals = planning.verifiedSteps;
|
|
517
|
+
}
|
|
343
518
|
if (decision.kind !== "action") {
|
|
519
|
+
if (decision.kind === "complete" && !session.report.mock && (input.completion || input.expectText) && completionCorrections < 1 && session.report.modelRequests < context.config.phone.maxModelRequests) {
|
|
520
|
+
completionCorrections++;
|
|
521
|
+
session.report.diagnostics.completionCorrections++;
|
|
522
|
+
recoveryHint = `Your completion claim is not verified. These required native UI conditions are not all satisfied: ${JSON.stringify({
|
|
523
|
+
expectText: input.expectText,
|
|
524
|
+
...input.completion
|
|
525
|
+
})}. Recheck the fresh screen, preserve user constraints, and continue if a safe authorized action can satisfy the goal; otherwise report unfinished.`;
|
|
526
|
+
observation.frame.fill(0);
|
|
527
|
+
observation = await this.observe(session, signal);
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
344
530
|
session.report.status = decision.kind === "needsUser" ? "needs_user" : "completed";
|
|
345
|
-
session.report.message = decision.kind === "needsUser" ? decision.reason :
|
|
531
|
+
session.report.message = decision.kind === "needsUser" ? decision.reason : decision.summary;
|
|
346
532
|
session.report.stopReason = decision.kind === "needsUser" ? "user_takeover" : "model_finished_unverified";
|
|
347
533
|
if (decision.kind === "needsUser" && !session.report.mock) {
|
|
348
534
|
session.report.controlOwner = "none";
|
|
@@ -356,24 +542,142 @@ var PhoneRuntime = class {
|
|
|
356
542
|
}
|
|
357
543
|
return this.publish(session);
|
|
358
544
|
}
|
|
545
|
+
let preparedFocus;
|
|
546
|
+
if (enhancements.hierarchicalPlanning) {
|
|
547
|
+
const operationActions = session.trajectoryCount - trajectoryStart;
|
|
548
|
+
const back = phoneBackRecovery({
|
|
549
|
+
action: decision.action,
|
|
550
|
+
observation,
|
|
551
|
+
entryObservation,
|
|
552
|
+
completion,
|
|
553
|
+
trajectory: operationActions ? session.trajectory.slice(-operationActions) : []
|
|
554
|
+
});
|
|
555
|
+
if (back) {
|
|
556
|
+
session.report.diagnostics.backReplans = (session.report.diagnostics.backReplans ?? 0) + 1;
|
|
557
|
+
if (backReplans++ >= 2) {
|
|
558
|
+
session.report.status = "paused";
|
|
559
|
+
session.report.controlOwner = "none";
|
|
560
|
+
session.report.controlEpoch++;
|
|
561
|
+
session.report.stopReason = "back_boundary";
|
|
562
|
+
session.report.message = back.hint;
|
|
563
|
+
session.budget?.pause();
|
|
564
|
+
await session.stream?.revoke();
|
|
565
|
+
return this.publish(session);
|
|
566
|
+
}
|
|
567
|
+
recoveryHint = back.hint;
|
|
568
|
+
observation.frame.fill(0);
|
|
569
|
+
observation = await this.observe(session, signal);
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
const focusHint = phoneUnfocusedTypingHint(decision.action, observation, completion);
|
|
573
|
+
if (focusHint) {
|
|
574
|
+
const key = JSON.stringify(decision.action);
|
|
575
|
+
preparedFocus = !focusedIntents.has(key) ? preparePhoneFocusRecovery(decision.action, observation, completion) : void 0;
|
|
576
|
+
if (preparedFocus) decision = {
|
|
577
|
+
kind: "action",
|
|
578
|
+
action: preparedFocus.focusAction
|
|
579
|
+
};
|
|
580
|
+
else {
|
|
581
|
+
session.report.diagnostics.focusReplans = (session.report.diagnostics.focusReplans ?? 0) + 1;
|
|
582
|
+
if (focusReplans++ >= 2) throw new PhoneError("PHONE_INPUT_NOT_FOCUSED", "The requested editable field could not be focused; inspect before typing", 409);
|
|
583
|
+
recoveryHint = focusHint;
|
|
584
|
+
observation.frame.fill(0);
|
|
585
|
+
observation = await this.observe(session, signal);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
359
590
|
const fresh = await this.observe(session, signal);
|
|
360
591
|
try {
|
|
361
592
|
this.allowedScreen(session, fresh);
|
|
362
|
-
if (
|
|
593
|
+
if (decision.action.type !== "tapElement" && !canDispatchPhoneAction(decision.action, observation, fresh)) {
|
|
594
|
+
session.report.diagnostics.stalePredictions++;
|
|
595
|
+
recoveryHint = "The proposed action was not dispatched because its target changed. Locate it again on the fresh screen.";
|
|
596
|
+
observation.frame.fill(0);
|
|
597
|
+
observation = fresh;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
let action = enhancements.semanticControls ? groundPhoneCoordinateAction(decision.action, observation) : decision.action;
|
|
601
|
+
const semanticAction = action.type === "tapElement";
|
|
602
|
+
if (action.type === "tapElement") {
|
|
603
|
+
if (!enhancements.semanticControls && !preparedFocus) throw new PhoneError("PHONE_SEMANTIC_DISABLED", "Semantic controls are disabled");
|
|
604
|
+
try {
|
|
605
|
+
action = resolvePhoneSemanticAction(action, observation, fresh);
|
|
606
|
+
} catch (error) {
|
|
607
|
+
if (!(error instanceof PhoneError) || !error.code.startsWith("PHONE_SEMANTIC_")) throw error;
|
|
608
|
+
session.report.diagnostics.semanticRejections = (session.report.diagnostics.semanticRejections ?? 0) + 1;
|
|
609
|
+
recoveryHint = "The semantic target was not dispatched: select one unique fully visible non-password control from the fresh native UI.";
|
|
610
|
+
observation.frame.fill(0);
|
|
611
|
+
observation = fresh;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (!canDispatchPhoneAction(action, observation, fresh)) {
|
|
616
|
+
session.report.diagnostics.stalePredictions++;
|
|
617
|
+
recoveryHint = "The proposed action was not dispatched because its target changed. Locate it again on the fresh screen.";
|
|
363
618
|
observation.frame.fill(0);
|
|
364
619
|
observation = fresh;
|
|
365
620
|
continue;
|
|
366
621
|
}
|
|
367
622
|
if (epoch !== session.report.controlEpoch || session.report.controlOwner !== "agent") continue;
|
|
368
|
-
|
|
623
|
+
const attemptKey = `${observationSignature(fresh)}:${JSON.stringify(action)}`;
|
|
624
|
+
const repetitions = attempts.get(attemptKey) ?? 0;
|
|
625
|
+
if (repetitions >= (action.type === "wait" ? 3 : 2)) {
|
|
626
|
+
session.report.status = "paused";
|
|
627
|
+
session.report.controlOwner = "none";
|
|
628
|
+
session.report.controlEpoch++;
|
|
629
|
+
session.report.stopReason = "no_progress";
|
|
630
|
+
session.report.message = "Repeated actions made no progress. Inspect the phone and hand back before continuing.";
|
|
631
|
+
session.budget?.pause();
|
|
632
|
+
await session.stream?.revoke();
|
|
633
|
+
return this.publish(session);
|
|
634
|
+
}
|
|
635
|
+
attempts.set(attemptKey, repetitions + 1);
|
|
636
|
+
if (await this.dispatch(session, action, fresh, context, signal, epoch)) {
|
|
637
|
+
actions++;
|
|
638
|
+
if (semanticAction && enhancements.semanticControls) session.report.diagnostics.semanticActions = (session.report.diagnostics.semanticActions ?? 0) + 1;
|
|
639
|
+
if (preparedFocus) {
|
|
640
|
+
pendingFocus = preparedFocus;
|
|
641
|
+
focusedIntents.add(JSON.stringify(preparedFocus.intendedAction));
|
|
642
|
+
session.report.diagnostics.focusRecoveries = (session.report.diagnostics.focusRecoveries ?? 0) + 1;
|
|
643
|
+
}
|
|
644
|
+
if (resumedText) session.report.diagnostics.resumedTextInputs = (session.report.diagnostics.resumedTextInputs ?? 0) + 1;
|
|
645
|
+
if (numericStep) {
|
|
646
|
+
numericPending = numericStep;
|
|
647
|
+
session.report.diagnostics.numericActions = (session.report.diagnostics.numericActions ?? 0) + 1;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
369
650
|
} finally {
|
|
370
651
|
if (observation !== fresh) fresh.frame.fill(0);
|
|
371
652
|
}
|
|
653
|
+
const beforeSignature = observationSignature(observation);
|
|
372
654
|
observation.frame.fill(0);
|
|
373
655
|
observation = await this.observe(session, signal);
|
|
656
|
+
const entry = session.trajectory.at(-1);
|
|
657
|
+
if (entry && entry.actor === "agent" && epoch === session.report.controlEpoch) {
|
|
658
|
+
const unchanged = beforeSignature === observationSignature(observation);
|
|
659
|
+
entry.afterApp = observation.package;
|
|
660
|
+
entry.effect = unchanged ? "unchanged" : "changed";
|
|
661
|
+
entry.facts = observation.elements.filter((node) => !node.password).flatMap((node) => [node.text, node.description]).filter(Boolean).slice(0, 12).map((text) => text.slice(0, 160));
|
|
662
|
+
if (unchanged) session.report.diagnostics.unchangedActions++;
|
|
663
|
+
recoveryHint = unchanged ? "The last dispatched action produced no observable change. Wait if loading, otherwise try a different target or route; do not repeat an uncertain input." : void 0;
|
|
664
|
+
}
|
|
374
665
|
}
|
|
375
666
|
} catch (error) {
|
|
376
667
|
const failure = signal.aborted && signal.reason instanceof PhoneError ? signal.reason : error;
|
|
668
|
+
if (!signal.aborted && failure instanceof PhoneError && ["PHONE_TEXT_INPUT_UNAVAILABLE", "PHONE_TEXT_INPUT_UNCONFIRMED"].includes(failure.code)) {
|
|
669
|
+
session.report.status = "needs_user";
|
|
670
|
+
session.human = void 0;
|
|
671
|
+
session.report.controlOwner = "none";
|
|
672
|
+
session.report.controlEpoch++;
|
|
673
|
+
session.report.errorCode = failure.code;
|
|
674
|
+
session.report.message = failure.message;
|
|
675
|
+
session.report.currentAction = void 0;
|
|
676
|
+
session.report.stopReason = failure.code === "PHONE_TEXT_INPUT_UNAVAILABLE" ? "text_input_required" : "text_input_unconfirmed";
|
|
677
|
+
session.budget?.pause();
|
|
678
|
+
await session.stream?.revoke();
|
|
679
|
+
return this.publish(session);
|
|
680
|
+
}
|
|
377
681
|
if (failure instanceof PhoneError && failure.code === "PHONE_OPERATION_TIMEOUT" && !terminal.has(session.report.status) && session.report.status !== "paused") {
|
|
378
682
|
session.report.status = "paused";
|
|
379
683
|
session.report.controlOwner = "none";
|
|
@@ -427,7 +731,8 @@ var PhoneRuntime = class {
|
|
|
427
731
|
status: session.report.status,
|
|
428
732
|
stopReason: session.report.stopReason,
|
|
429
733
|
actions: session.report.actions,
|
|
430
|
-
modelRequests: session.report.modelRequests
|
|
734
|
+
modelRequests: session.report.modelRequests,
|
|
735
|
+
diagnostics: session.report.diagnostics
|
|
431
736
|
}, "Phone goal finished");
|
|
432
737
|
}
|
|
433
738
|
}
|
|
@@ -435,7 +740,7 @@ var PhoneRuntime = class {
|
|
|
435
740
|
session.report.foregroundApp = observation.package;
|
|
436
741
|
session.report.facts = [...new Set(observation.elements.flatMap((node) => node.password ? [] : [node.text, node.description]).filter(Boolean))].slice(0, 60);
|
|
437
742
|
}
|
|
438
|
-
async dispatch(session, action, observation, context, signal, epoch = session.report.controlEpoch, resetTask = false) {
|
|
743
|
+
async dispatch(session, action, observation, context, signal, epoch = session.report.controlEpoch, resetTask = false, settingsPage) {
|
|
439
744
|
return this.io(session, async () => {
|
|
440
745
|
signal.throwIfAborted();
|
|
441
746
|
this.guard(session, context);
|
|
@@ -445,6 +750,7 @@ var PhoneRuntime = class {
|
|
|
445
750
|
if (session.human && (session.report.humanActions ?? 0) >= 1200) throw new PhoneError("PHONE_ACTION_LIMIT", "Manual input limit reached; reopen the session");
|
|
446
751
|
if (action.type === "launch" && !phoneAllowsApp(session.device, action.package)) throw new PhoneError("PHONE_APP_DENIED", "Application is not authorized");
|
|
447
752
|
if (action.type === "home" && phoneAppAccess(session.device) !== "all") throw new PhoneError("PHONE_APP_DENIED", "Home leaves the app allowlist");
|
|
753
|
+
if (action.type === "typeText" && session.device.textInput === "manual") throw new PhoneError("PHONE_TEXT_INPUT_UNAVAILABLE", "Automatic text input is disabled for this phone. Ask the user to take over and type with the phone keyboard.", 409);
|
|
448
754
|
if (action.type === "typeText" && !observation.elements.some((node) => node.focused && node.editable && !node.password)) throw new PhoneError("PHONE_INPUT_NOT_FOCUSED", "Focus a non-password editable field before typing", 409);
|
|
449
755
|
const step = {
|
|
450
756
|
action: action.type,
|
|
@@ -460,14 +766,51 @@ var PhoneRuntime = class {
|
|
|
460
766
|
session.report.steps = session.report.steps.slice(-200);
|
|
461
767
|
}
|
|
462
768
|
this.publish(session);
|
|
769
|
+
const entry = {
|
|
770
|
+
action: structuredClone(action),
|
|
771
|
+
dispatch: "unknown",
|
|
772
|
+
actor: step.actor,
|
|
773
|
+
beforeApp: observation.package,
|
|
774
|
+
effect: "unknown"
|
|
775
|
+
};
|
|
776
|
+
session.trajectory.push(entry);
|
|
777
|
+
session.trajectoryCount++;
|
|
778
|
+
if (session.trajectory.length > 24) {
|
|
779
|
+
const earlier = session.trajectory.shift();
|
|
780
|
+
session.trajectorySummary.push(JSON.stringify({
|
|
781
|
+
action: earlier.action,
|
|
782
|
+
effect: earlier.effect,
|
|
783
|
+
afterApp: earlier.afterApp
|
|
784
|
+
}).slice(0, 250));
|
|
785
|
+
session.trajectorySummary = session.trajectorySummary.slice(-12);
|
|
786
|
+
}
|
|
463
787
|
try {
|
|
464
|
-
await session.driver.execute(session.device.serial, action, observation, signal,
|
|
788
|
+
await session.driver.execute(session.device.serial, action, observation, signal, settingsPage ? {
|
|
789
|
+
settleMs: session.human ? 0 : 350,
|
|
790
|
+
settingsPage
|
|
791
|
+
} : session.human ? {
|
|
465
792
|
settleMs: 0,
|
|
466
793
|
...resetTask ? { resetTask: true } : {}
|
|
467
794
|
} : void 0);
|
|
468
795
|
step.dispatch = "completed";
|
|
796
|
+
entry.dispatch = "completed";
|
|
469
797
|
} catch (error) {
|
|
470
|
-
|
|
798
|
+
const textFailure = error instanceof PhoneError && ["PHONE_TEXT_INPUT_UNAVAILABLE", "PHONE_TEXT_INPUT_UNCONFIRMED"].includes(error.code);
|
|
799
|
+
if (textFailure && error.code === "PHONE_TEXT_INPUT_UNAVAILABLE") {
|
|
800
|
+
session.report.steps.pop();
|
|
801
|
+
session.report.actions--;
|
|
802
|
+
session.trajectory.pop();
|
|
803
|
+
session.trajectoryCount--;
|
|
804
|
+
if (session.human) session.report.humanActions--;
|
|
805
|
+
} else session.report.status = "outcome_unknown";
|
|
806
|
+
if (textFailure && session.human) {
|
|
807
|
+
session.report.status = "paused";
|
|
808
|
+
session.report.errorCode = error.code;
|
|
809
|
+
session.report.message = error.message;
|
|
810
|
+
session.report.stopReason = error.code === "PHONE_TEXT_INPUT_UNAVAILABLE" ? "text_input_required" : "text_input_unconfirmed";
|
|
811
|
+
session.report.currentAction = void 0;
|
|
812
|
+
this.publish(session);
|
|
813
|
+
}
|
|
471
814
|
session.frames.clear();
|
|
472
815
|
throw error;
|
|
473
816
|
}
|
|
@@ -497,6 +840,8 @@ var PhoneRuntime = class {
|
|
|
497
840
|
if (op !== "pause") {
|
|
498
841
|
session.report.facts = void 0;
|
|
499
842
|
session.report.message = void 0;
|
|
843
|
+
session.trajectory = [];
|
|
844
|
+
session.trajectorySummary = [];
|
|
500
845
|
session.frames.clear();
|
|
501
846
|
session.adapter = { predict: async () => {
|
|
502
847
|
throw new PhoneError("PHONE_OPEN_REQUIRED", "Reopen the phone session");
|
|
@@ -625,6 +970,7 @@ var PhoneRuntime = class {
|
|
|
625
970
|
ownControl: Boolean(session.human === client),
|
|
626
971
|
allowedApps: [...session.device.allowedApps],
|
|
627
972
|
appAccess: phoneAppAccess(session.device),
|
|
973
|
+
textInput: session.device.textInput ?? "auto",
|
|
628
974
|
frame: session.frames.get() ? {
|
|
629
975
|
seq: session.frames.get().seq,
|
|
630
976
|
capturedAt: session.frames.get().capturedAt
|
|
@@ -855,7 +1201,7 @@ var PhoneRuntime = class {
|
|
|
855
1201
|
const video = input.geometry !== void 0 && session.stream?.verifyGeometry(input.geometry);
|
|
856
1202
|
if (!video && (!frame || Date.now() - frame.capturedAt > 5e3)) throw new PhoneError("PHONE_FRAME_STALE", "Wait for a fresh phone image before interacting", 409);
|
|
857
1203
|
if (video && input.action?.type !== "typeText" && input.action?.type !== "back") throw new PhoneError("PHONE_INVALID_INPUT", "Use the continuous input channel for video gestures", 409);
|
|
858
|
-
if (!input.action || input.action.type === "launch" || input.action.type === "home" || input.action.type === "wait") throw new PhoneError("PHONE_INVALID_INPUT", "Unsupported manual input");
|
|
1204
|
+
if (!input.action || input.action.type === "launch" || input.action.type === "home" || input.action.type === "wait" || input.action.type === "tapElement") throw new PhoneError("PHONE_INVALID_INPUT", "Unsupported manual input");
|
|
859
1205
|
const observation = input.action.type === "typeText" ? await this.observe(session, session.controller.signal, true) : await this.capture(session, session.controller.signal);
|
|
860
1206
|
try {
|
|
861
1207
|
if (input.epoch !== session.report.controlEpoch || session.human !== client || Date.now() > (session.humanExpiresAt ?? 0)) throw new PhoneError("PHONE_CONTROL_CHANGED", "Manual control expired while observing the phone", 409);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Only supplied text is sent to Android; clipboard autosync and reads stay off. */
|
|
2
|
+
export declare class ScrcpyTextChannel {
|
|
3
|
+
private write;
|
|
4
|
+
private buffer;
|
|
5
|
+
private sequence;
|
|
6
|
+
private pending;
|
|
7
|
+
constructor(write: (bytes: Buffer) => Promise<void>);
|
|
8
|
+
receive(bytes: Buffer): void;
|
|
9
|
+
paste(text: string, signal: AbortSignal): Promise<void>;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PhoneError, init_contracts } from "./contracts.js";
|
|
2
|
+
//#region src/phone/scrcpy-text.ts
|
|
3
|
+
init_contracts();
|
|
4
|
+
/** Only supplied text is sent to Android; clipboard autosync and reads stay off. */
|
|
5
|
+
var ScrcpyTextChannel = class {
|
|
6
|
+
buffer = Buffer.alloc(0);
|
|
7
|
+
sequence = 0n;
|
|
8
|
+
pending = /* @__PURE__ */ new Map();
|
|
9
|
+
constructor(write) {
|
|
10
|
+
this.write = write;
|
|
11
|
+
}
|
|
12
|
+
receive(bytes) {
|
|
13
|
+
this.buffer = Buffer.concat([this.buffer, bytes]);
|
|
14
|
+
while (this.buffer.length) {
|
|
15
|
+
const type = this.buffer[0];
|
|
16
|
+
let length;
|
|
17
|
+
if (type === 1) {
|
|
18
|
+
if (this.buffer.length < 9) return;
|
|
19
|
+
const seq = this.buffer.readBigUInt64BE(1);
|
|
20
|
+
this.pending.get(seq)?.resolve();
|
|
21
|
+
this.pending.delete(seq);
|
|
22
|
+
length = 9;
|
|
23
|
+
} else if (type === 0 || type === 2) {
|
|
24
|
+
if (this.buffer.length < 5) return;
|
|
25
|
+
length = 5 + (type === 0 ? this.buffer.readUInt32BE(1) : this.buffer.readUInt16BE(3));
|
|
26
|
+
if (length > 262144) throw new Error("Invalid device message");
|
|
27
|
+
if (this.buffer.length < length) return;
|
|
28
|
+
} else throw new Error("Unknown device message");
|
|
29
|
+
this.buffer = this.buffer.subarray(length);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async paste(text, signal) {
|
|
33
|
+
signal.throwIfAborted();
|
|
34
|
+
if (!text || text.length > 4e3 || this.pending.size) throw new PhoneError("PHONE_INVALID_INPUT", "Invalid or concurrent phone text input");
|
|
35
|
+
const sequence = ++this.sequence;
|
|
36
|
+
const payload = Buffer.from(text);
|
|
37
|
+
const bytes = Buffer.alloc(14 + payload.length);
|
|
38
|
+
bytes[0] = 9;
|
|
39
|
+
bytes.writeBigUInt64BE(sequence, 1);
|
|
40
|
+
bytes[9] = 1;
|
|
41
|
+
bytes.writeUInt32BE(payload.length, 10);
|
|
42
|
+
payload.copy(bytes, 14);
|
|
43
|
+
payload.fill(0);
|
|
44
|
+
const deadline = AbortSignal.any([signal, AbortSignal.timeout(1e4)]);
|
|
45
|
+
let abort;
|
|
46
|
+
const ack = new Promise((resolve, reject) => {
|
|
47
|
+
abort = () => reject(new PhoneError("PHONE_TEXT_INPUT_UNCONFIRMED", "Text may have been pasted. Take over and inspect the input field before retrying.", 409));
|
|
48
|
+
this.pending.set(sequence, {
|
|
49
|
+
resolve,
|
|
50
|
+
reject
|
|
51
|
+
});
|
|
52
|
+
deadline.addEventListener("abort", abort, { once: true });
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
await Promise.all([this.write(bytes), ack]);
|
|
56
|
+
} catch {
|
|
57
|
+
throw new PhoneError("PHONE_TEXT_INPUT_UNCONFIRMED", "Text may have been pasted. Take over and inspect the input field before retrying.", 409);
|
|
58
|
+
} finally {
|
|
59
|
+
bytes.fill(0);
|
|
60
|
+
deadline.removeEventListener("abort", abort);
|
|
61
|
+
this.pending.delete(sequence);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
close() {
|
|
65
|
+
for (const request of this.pending.values()) request.reject(new PhoneError("PHONE_TEXT_INPUT_UNCONFIRMED", "Phone text channel disconnected; inspect the field before retrying.", 409));
|
|
66
|
+
this.pending.clear();
|
|
67
|
+
this.buffer.fill(0);
|
|
68
|
+
this.buffer = Buffer.alloc(0);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { ScrcpyTextChannel };
|