@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.
Files changed (359) hide show
  1. package/dist/browser-ext/_locales/en/messages.json +4 -1
  2. package/dist/browser-ext/_locales/zh_CN/messages.json +4 -1
  3. package/dist/browser-ext/dist/assets/{page-context-MuzjMBlJ.js → page-context-CVvmTWZb.js} +33 -9
  4. package/dist/browser-ext/dist/background.js +39 -10
  5. package/dist/browser-ext/dist/sidepanel.html +1 -1
  6. package/dist/browser-ext/dist/sidepanel.js +22 -3
  7. package/dist/browser-ext/manifest.json +1 -1
  8. package/dist/extensions/telegram/xopc.extension.json +1 -1
  9. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-ClobpdW3.js → agent-avatar-dicebear-CufU7cqe.js} +1 -1
  10. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DHDAcss8.js +1 -0
  11. package/dist/gateway/static/root/assets/agents-BV3dAoa0.js +77 -0
  12. package/dist/gateway/static/root/assets/{agents-admin-api-CeBkHnl8.js → agents-admin-api-B1p-ghg9.js} +1 -1
  13. package/dist/gateway/static/root/assets/{app-management-settings-panel-CLunLNGp.js → app-management-settings-panel-D4-n1uBg.js} +1 -1
  14. package/dist/gateway/static/root/assets/{appearance-settings-DBEgoE9g.js → appearance-settings-Cgn4eNsX.js} +1 -1
  15. package/dist/gateway/static/root/assets/apps-page-BOYzD7Zz.js +1 -0
  16. package/dist/gateway/static/root/assets/{archive-plugin-JElK4Goq.js → archive-plugin-B4btCsiV.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-page-CZ0UqwyU.js → automations-page-yb1EL_3N.js} +1 -1
  18. package/dist/gateway/static/root/assets/automations-workspace-J7LJ4RuV.js +8 -0
  19. package/dist/gateway/static/root/assets/{binary-plugins-CXFawow6.js → binary-plugins-DQT9e258.js} +1 -1
  20. package/dist/gateway/static/root/assets/{block-editor-BoduwSYI.js → block-editor-B50rU9tL.js} +30 -30
  21. package/dist/gateway/static/root/assets/{browser-automation-inputs-D1pDgMJu.js → browser-automation-inputs-D6AccXaA.js} +1 -1
  22. package/dist/gateway/static/root/assets/browser-automations-page-BiQz6lJA.js +3 -0
  23. package/dist/gateway/static/root/assets/browser-settings-page-W9kuxBbE.js +3 -0
  24. package/dist/gateway/static/root/assets/{capabilities-Bpeh6E22.js → capabilities-BlxF36t-.js} +1 -1
  25. package/dist/gateway/static/root/assets/capabilities-page-iXe87MdG.js +2 -0
  26. package/dist/gateway/static/root/assets/capabilities-settings-panel-CRLSXe7Z.js +8 -0
  27. package/dist/gateway/static/root/assets/{capability-header-actions-BasrAWA0.js → capability-header-actions-BMnbzHms.js} +1 -1
  28. package/dist/gateway/static/root/assets/channels-CrRJkOKX.js +1 -0
  29. package/dist/gateway/static/root/assets/{chat-terminal-dock-CwQbzcZ_.js → chat-terminal-dock-Bd3af4gL.js} +2 -2
  30. package/dist/gateway/static/root/assets/{computer-settings-page-DNWeJKfF.js → computer-settings-page-DXfqy7xh.js} +1 -1
  31. package/dist/gateway/static/root/assets/{connector-service-page-CxHgC5RM.js → connector-service-page-B-cw0CPU.js} +1 -1
  32. package/dist/gateway/static/root/assets/connectors-page-DbFxc0Fd.js +1 -0
  33. package/dist/gateway/static/root/assets/{date-picker-CXxLbLJb.js → date-picker-CqzXevH6.js} +1 -1
  34. package/dist/gateway/static/root/assets/{dependency-picker-DVuWMrSj.js → dependency-picker-pgT4Gyaf.js} +1 -1
  35. package/dist/gateway/static/root/assets/{desktop-pet-settings-BDlg9g4s.js → desktop-pet-settings-Dy_-i2L8.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-KbVLtAlO.js → desktop-pet-zICeqw9c.js} +1 -1
  37. package/dist/gateway/static/root/assets/device-pairing-wizard-ByGbxqkg.js +1 -0
  38. package/dist/gateway/static/root/assets/{directory-picker-path-field-a7xEodzo.js → directory-picker-path-field-C-aQ7qoM.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-debug-page-CHelH5u_.js → extension-debug-page-2NwpYkS5.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-page-CrVHmS9-.js → extension-page-y9J0z7_Q.js} +1 -1
  41. package/dist/gateway/static/root/assets/{extension-settings-page-CiMybi0r.js → extension-settings-page-BtowusUh.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-config-swr-DF_HV6NP.js → gateway-config-swr-fQKBHBi1.js} +1 -1
  43. package/dist/gateway/static/root/assets/gateway-realtime-C52ghnBK.js +1 -0
  44. package/dist/gateway/static/root/assets/gateway-realtime-store-Bx9KCID-.js +1 -0
  45. package/dist/gateway/static/root/assets/gateway-settings-BYSKzUMR.js +1 -0
  46. package/dist/gateway/static/root/assets/{gateway-startup-retry-B91CBTzO.js → gateway-startup-retry-Cfwxof4k.js} +1 -1
  47. package/dist/gateway/static/root/assets/highlight-code-Cz6eeDH5.js +1 -0
  48. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-8ACAVktj.js → highlighted-body-KQOG7T2V-BiAa8HKC.js} +1 -1
  49. package/dist/gateway/static/root/assets/home-page-Cd1BjYHj.js +2 -0
  50. package/dist/gateway/static/root/assets/{image-generation-api-CVBaWmrV.js → image-generation-api-gBFro48x.js} +1 -1
  51. package/dist/gateway/static/root/assets/{imports-page-C5IP3e6d.js → imports-page-BZQpXgjj.js} +1 -1
  52. package/dist/gateway/static/root/assets/index-Cy16gQST.css +1 -0
  53. package/dist/gateway/static/root/assets/index-DRyGCING.js +710 -0
  54. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BhU6VYvd.js → keyboard-shortcuts-settings-CYunR34k.js} +1 -1
  55. package/dist/gateway/static/root/assets/local-app-workbench-page-B_Ac1lly.js +1 -0
  56. package/dist/gateway/static/root/assets/{local-apps-page-DcP1Bdlk.js → local-apps-page-w-J5bY02.js} +1 -1
  57. package/dist/gateway/static/root/assets/{local-session-drafts-DvmwiLUx.js → local-session-drafts-iGX_6O0O.js} +1 -1
  58. package/dist/gateway/static/root/assets/{locale-store-JogcXC4J.js → locale-store-B7s2Hb35.js} +1 -1
  59. package/dist/gateway/static/root/assets/logs-page-Dnjvvx2i.js +2 -0
  60. package/dist/gateway/static/root/assets/management-settings-w1EDwgLW.js +1 -0
  61. package/dist/gateway/static/root/assets/{media-plugins-BnPpcJ2J.js → media-plugins-CIx1koXw.js} +1 -1
  62. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-DISkHmEC.js +1 -0
  63. package/dist/gateway/static/root/assets/{messages-RzwPiQNL.js → messages-BYq0cPbn.js} +2 -2
  64. package/dist/gateway/static/root/assets/note-detail-panel-CNkxMTFU.js +5 -0
  65. package/dist/gateway/static/root/assets/note-image-lightbox-D5GH2wuC.js +1 -0
  66. package/dist/gateway/static/root/assets/notes-page-DZgKqFBG.js +8 -0
  67. package/dist/gateway/static/root/assets/page-context-capture-button-DusR2Itk.js +1 -0
  68. package/dist/gateway/static/root/assets/personal-page-CR5JFkQ9.js +1 -0
  69. package/dist/gateway/static/root/assets/personal-settings-panel-B7undvlr.js +1 -0
  70. package/dist/gateway/static/root/assets/phone-model-picker-fWDltRUJ.js +1 -0
  71. package/dist/gateway/static/root/assets/phone-settings-page-CsOirAiy.js +1 -0
  72. package/dist/gateway/static/root/assets/plugin-details-dialog-BOBVIB3j.js +1 -0
  73. package/dist/gateway/static/root/assets/{preview-open-alternatives-FGqN-mQx.js → preview-open-alternatives-CMxjsKSw.js} +1 -1
  74. package/dist/gateway/static/root/assets/{product-open-page-CwnHLfdL.js → product-open-page-CrlyJx5M.js} +1 -1
  75. package/dist/gateway/static/root/assets/{product-preview-content-BD6k5hF9.js → product-preview-content-B-Jhzi7W.js} +1 -1
  76. package/dist/gateway/static/root/assets/project-detail-page-DoYUbtcI.js +7 -0
  77. package/dist/gateway/static/root/assets/projects-page-xGQd9oAZ.js +1 -0
  78. package/dist/gateway/static/root/assets/refresh-cw-BRlGaq2w.js +1 -0
  79. package/dist/gateway/static/root/assets/{registry-api-BGqSwITi.js → registry-api-BcfoLEna.js} +1 -1
  80. package/dist/gateway/static/root/assets/remote-access-hub-Gs0Xkws9.js +1 -0
  81. package/dist/gateway/static/root/assets/{runtime-tools-api-CSm5SpnR.js → runtime-tools-api-DesqGCnE.js} +1 -1
  82. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bwg7U7TR.js +1 -0
  83. package/dist/gateway/static/root/assets/{schema-form-DoVn5jJK.js → schema-form-ByzTNR_C.js} +1 -1
  84. package/dist/gateway/static/root/assets/{session-api-DTxZyMta.js → session-api-DdQnMwkl.js} +1 -1
  85. package/dist/gateway/static/root/assets/{session-manager-B2HDomj4.js → session-manager-B_h0jlLb.js} +1 -1
  86. package/dist/gateway/static/root/assets/sessions-page-XzK1ftbR.js +1 -0
  87. package/dist/gateway/static/root/assets/settings-advanced-gate-D_8Mvnog.js +1 -0
  88. package/dist/gateway/static/root/assets/{settings-form-section-Ce8vVv-9.js → settings-form-section-Brgd8IOV.js} +1 -1
  89. package/dist/gateway/static/root/assets/{settings-page-DP2w3ejC.js → settings-page-B6Mv02eg.js} +1 -1
  90. package/dist/gateway/static/root/assets/settings-page-header-BWyxJKOG.js +1 -0
  91. package/dist/gateway/static/root/assets/{settings-page-layout-B20AfmFG.js → settings-page-layout-DLHcS-0T.js} +1 -1
  92. package/dist/gateway/static/root/assets/setup-status-panel-DSCj5yis.js +1 -0
  93. package/dist/gateway/static/root/assets/{share-preview-page-DV4dKrmG.js → share-preview-page-DF8Of0aZ.js} +1 -1
  94. package/dist/gateway/static/root/assets/shares-settings-DXNPe4Tl.js +1 -0
  95. package/dist/gateway/static/root/assets/{skill-api-DTdejInH.js → skill-api-CKCDCHLq.js} +1 -1
  96. package/dist/gateway/static/root/assets/skill-reload-api-BH0WF6Br.js +1 -0
  97. package/dist/gateway/static/root/assets/skills-page-DFWMVRW4.js +2 -0
  98. package/dist/gateway/static/root/assets/system-settings-panel-DB-ttubV.js +1 -0
  99. package/dist/gateway/static/root/assets/task-detail-page-BJY7c8wb.js +2 -0
  100. package/dist/gateway/static/root/assets/{task-result-evidence-DIGSC4qF.js → task-result-evidence-B-vt1BgK.js} +1 -1
  101. package/dist/gateway/static/root/assets/{tracing-settings-page-BaU8frtc.js → tracing-settings-page-Dt51Z_ws.js} +1 -1
  102. package/dist/gateway/static/root/assets/{tunnel-api-BCcOUsqu.js → tunnel-api-Dok3t7Qe.js} +1 -1
  103. package/dist/gateway/static/root/assets/usage-page-lJym5G7F.js +1 -0
  104. package/dist/gateway/static/root/assets/{use-autosave-C1X47WVb.js → use-autosave-D4EMIB-V.js} +1 -1
  105. package/dist/gateway/static/root/assets/user-model-page-BXdNkITp.js +2 -0
  106. package/dist/gateway/static/root/assets/{voice-api-key-field-Bk4DQMTw.js → voice-api-key-field-CO3KuanA.js} +1 -1
  107. package/dist/gateway/static/root/assets/{voice-config-api-D7xsWrdh.js → voice-config-api-BkUlN7GH.js} +1 -1
  108. package/dist/gateway/static/root/assets/{work-discovery-overlay-B7_NmTB5.js → work-discovery-overlay-BJRtgQM3.js} +1 -1
  109. package/dist/gateway/static/root/assets/wrench-DFb4r8bH.js +1 -0
  110. package/dist/gateway/static/root/assets/xopc-cloud-account-card-CS-_GxHV.js +1 -0
  111. package/dist/gateway/static/root/browser-setup-test.html +5 -0
  112. package/dist/gateway/static/root/browser-setup-test.js +7 -0
  113. package/dist/gateway/static/root/index.html +17 -14
  114. package/dist/package.js +1 -1
  115. package/dist/packages/gateway-contract/src/browser-setup.js +6 -0
  116. package/dist/packages/gateway-contract/src/index.js +4 -0
  117. package/dist/packages/gateway-contract/src/phone-setup.js +6 -0
  118. package/dist/packages/realtime-client/src/index.js +1 -0
  119. package/dist/packages/realtime-protocol/src/index.js +1 -0
  120. package/dist/src/agent/agent-manager.d.ts +4 -0
  121. package/dist/src/agent/agent-manager.js +12 -1
  122. package/dist/src/agent/coding/workspace-revision.js +1 -1
  123. package/dist/src/agent/commands/command-registry.js +1 -1
  124. package/dist/src/agent/embedded/tool-search-extension.js +14 -1
  125. package/dist/src/agent/memory/context-recovery.d.ts +1 -1
  126. package/dist/src/agent/service.d.ts +1 -0
  127. package/dist/src/agent/service.js +5 -0
  128. package/dist/src/agent/service.types.d.ts +2 -0
  129. package/dist/src/agent/skills/installer.js +3 -3
  130. package/dist/src/agent/tool-manuals/phone.d.ts +1 -1
  131. package/dist/src/agent/tool-manuals/phone.js +4 -2
  132. package/dist/src/agent/tool-manuals/xopc-configuration.d.ts +2 -0
  133. package/dist/src/agent/tool-manuals/xopc-configuration.js +25 -0
  134. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +2 -0
  135. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +6 -2
  136. package/dist/src/agent/tools/factory.d.ts +3 -0
  137. package/dist/src/agent/tools/factory.js +11 -1
  138. package/dist/src/agent/tools/personal-task-tool.d.ts +1 -1
  139. package/dist/src/agent/tools/personal-task-tool.js +23 -21
  140. package/dist/src/agent/tools/phone-use-tool.d.ts +1 -0
  141. package/dist/src/agent/tools/phone-use-tool.js +29 -1
  142. package/dist/src/agent/tools/tool-manual-tool.d.ts +1 -1
  143. package/dist/src/agent/tools/tool-manual-tool.js +3 -1
  144. package/dist/src/agent/tools/toolExposure.js +3 -0
  145. package/dist/src/agent/tools/xopc-use-tool.d.ts +4 -2
  146. package/dist/src/agent/tools/xopc-use-tool.js +40 -2
  147. package/dist/src/backup/archive.js +2 -1
  148. package/dist/src/browser/drivers/browser-driver.d.ts +2 -2
  149. package/dist/src/browser/drivers/extension-driver.d.ts +2 -2
  150. package/dist/src/browser/drivers/extension-driver.js +6 -3
  151. package/dist/src/browser/providers/browser-ext-install.js +3 -2
  152. package/dist/src/browser/runtime/browser-runtime.d.ts +4 -1
  153. package/dist/src/browser/runtime/browser-runtime.js +29 -17
  154. package/dist/src/browser/setup/repository.d.ts +5 -0
  155. package/dist/src/browser/setup/repository.js +42 -0
  156. package/dist/src/browser/setup/service.d.ts +152 -0
  157. package/dist/src/browser/setup/service.js +404 -0
  158. package/dist/src/browser/setup/types.d.ts +38 -0
  159. package/dist/src/browser/setup/types.js +1 -0
  160. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  161. package/dist/src/cli/commands/extension-marketplace.js +3 -3
  162. package/dist/src/cli/commands/extension-pack.js +1 -1
  163. package/dist/src/cli/commands/extension.js +2 -2
  164. package/dist/src/config/schema.d.ts +2 -0
  165. package/dist/src/extensions/install.js +1 -1
  166. package/dist/src/extensions/update.js +1 -1
  167. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  168. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  169. package/dist/src/gateway/hono/routes/browser-setup.d.ts +3 -0
  170. package/dist/src/gateway/hono/routes/browser-setup.js +114 -0
  171. package/dist/src/gateway/hono/routes/browser.d.ts +2 -1
  172. package/dist/src/gateway/hono/routes/browser.js +1 -1
  173. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  174. package/dist/src/gateway/hono/routes/phone-dependencies.js +1 -1
  175. package/dist/src/gateway/hono/routes/phone-setup.d.ts +7 -0
  176. package/dist/src/gateway/hono/routes/phone-setup.js +162 -0
  177. package/dist/src/gateway/hono/routes/phone.js +11 -7
  178. package/dist/src/gateway/hono/routes/public-gateway.js +2 -0
  179. package/dist/src/gateway/provider-model-setup.js +1 -1
  180. package/dist/src/gateway/service/config-coordinator.d.ts +2 -0
  181. package/dist/src/gateway/service/config-coordinator.js +1 -1
  182. package/dist/src/gateway/service/session-input-coordinator.js +1 -1
  183. package/dist/src/gateway/service.d.ts +5 -0
  184. package/dist/src/gateway/service.js +52 -7
  185. package/dist/src/gateway/xopc-cloud-capability-setup.js +7 -1
  186. package/dist/src/home-intelligence/host.js +2 -2
  187. package/dist/src/infra/unhandled-rejections.js +2 -2
  188. package/dist/src/infra/update-runner.js +1 -1
  189. package/dist/src/personal-agent/prompts.js +1 -1
  190. package/dist/src/phone/adb-driver.d.ts +8 -2
  191. package/dist/src/phone/adb-driver.js +124 -54
  192. package/dist/src/phone/cloud-adb.js +8 -0
  193. package/dist/src/phone/cloud-scrcpy.d.ts +3 -1
  194. package/dist/src/phone/cloud-scrcpy.js +17 -3
  195. package/dist/src/phone/contracts.d.ts +85 -0
  196. package/dist/src/phone/contracts.js +31 -5
  197. package/dist/src/phone/model-adapter.d.ts +141 -2
  198. package/dist/src/phone/model-adapter.js +176 -24
  199. package/dist/src/phone/numeric-entry.d.ts +31 -0
  200. package/dist/src/phone/numeric-entry.js +126 -0
  201. package/dist/src/phone/planning.d.ts +27 -0
  202. package/dist/src/phone/planning.js +79 -0
  203. package/dist/src/phone/recovery.d.ts +37 -0
  204. package/dist/src/phone/recovery.js +81 -0
  205. package/dist/src/phone/reliability.d.ts +7 -0
  206. package/dist/src/phone/reliability.js +66 -0
  207. package/dist/src/phone/repository.d.ts +1 -0
  208. package/dist/src/phone/repository.js +3 -0
  209. package/dist/src/phone/runtime.d.ts +8 -0
  210. package/dist/src/phone/runtime.js +387 -41
  211. package/dist/src/phone/scrcpy-text.d.ts +11 -0
  212. package/dist/src/phone/scrcpy-text.js +72 -0
  213. package/dist/src/phone/scrcpy.d.ts +5 -1
  214. package/dist/src/phone/scrcpy.js +48 -3
  215. package/dist/src/phone/semantic-controls.d.ts +13 -0
  216. package/dist/src/phone/semantic-controls.js +76 -0
  217. package/dist/src/phone/setup/service.d.ts +148 -0
  218. package/dist/src/phone/setup/service.js +251 -0
  219. package/dist/src/providers/presentation.js +2 -2
  220. package/dist/src/providers/xopc-cloud-model-source.js +6 -2
  221. package/dist/src/realtime/runtime.js +1 -1
  222. package/dist/src/storage/sqlite/connection.js +2 -2
  223. package/dist/src/storage/sqlite/offline-access.js +13 -7
  224. package/dist/src/storage/sqlite/schema-errors.d.ts +12 -0
  225. package/dist/src/storage/sqlite/schema-errors.js +21 -3
  226. package/dist/src/storage/sqlite/schema-upgrade.d.ts +4 -0
  227. package/dist/src/storage/sqlite/schema-upgrade.js +78 -0
  228. package/dist/src/storage/sqlite/schema.d.ts +4 -3
  229. package/dist/src/storage/sqlite/schema.js +14 -8
  230. package/dist/src/storage/sqlite/schema.sql +10 -0
  231. package/dist/src/storage/sqlite/upgrades/203_remove_retired_proactive_contracts.sql +70 -0
  232. package/dist/src/storage/sqlite/upgrades/204_home_intelligence.sql +78 -0
  233. package/dist/src/storage/sqlite/upgrades/205_agent_catalog.sql +66 -0
  234. package/dist/src/storage/sqlite/upgrades/206_home_advice_strategy_version.sql +2 -0
  235. package/dist/src/storage/sqlite/upgrades/207_user_model_policy_contract.sql +121 -0
  236. package/dist/src/storage/sqlite/upgrades/208_automation_management.sql +2 -0
  237. package/dist/src/storage/sqlite/upgrades/209_automation_event_hub.sql +48 -0
  238. package/dist/src/storage/sqlite/upgrades/210_remove_legacy_automation_timeout.sql +14 -0
  239. package/dist/src/storage/sqlite/upgrades/211_automation_result_deliveries.sql +16 -0
  240. package/dist/src/storage/sqlite/upgrades/212_automation_delivery_policy.sql +30 -0
  241. package/dist/src/storage/sqlite/upgrades/213_automation_reliability_contract.sql +188 -0
  242. package/dist/src/storage/sqlite/upgrades/214_ai_usage_ledger.sql +41 -0
  243. package/dist/src/storage/sqlite/upgrades/215_scene_execution_adapters.sql +6 -0
  244. package/dist/src/storage/sqlite/upgrades/216_remove_scene_model_usage.sql +1 -0
  245. package/dist/src/storage/sqlite/upgrades/217_remove_legacy_memory_tables.sql +4 -0
  246. package/dist/src/storage/sqlite/upgrades/218_core_relation_indexes.sql +26 -0
  247. package/dist/src/storage/sqlite/upgrades/219_json_contracts.sql +123 -0
  248. package/dist/src/storage/sqlite/upgrades/220_normalize_timestamps.sql +339 -0
  249. package/dist/src/storage/sqlite/upgrades/221_ai_usage_retention_index.sql +2 -0
  250. package/dist/src/storage/sqlite/upgrades/222_session_config_authority.sql +13 -0
  251. package/dist/src/storage/sqlite/upgrades/223_session_creation_receipts.sql +59 -0
  252. package/dist/src/storage/sqlite/upgrades/224_task_origin_links.sql +8 -0
  253. package/dist/src/storage/sqlite/upgrades/225_task_collaboration.sql +32 -0
  254. package/dist/src/storage/sqlite/upgrades/226_task_main_updates.sql +9 -0
  255. package/dist/src/storage/sqlite/upgrades/227_task_main_update_decisions.sql +8 -0
  256. package/dist/src/storage/sqlite/upgrades/228_task_main_agent_links.sql +14 -0
  257. package/dist/src/storage/sqlite/upgrades/229_task_criterion_reviews.sql +12 -0
  258. package/dist/src/storage/sqlite/upgrades/230_personal_agent_onboarding.sql +8 -0
  259. package/dist/src/storage/sqlite/upgrades/231_task_result_deliveries.sql +32 -0
  260. package/dist/src/storage/sqlite/upgrades/232_personal_requests.sql +28 -0
  261. package/dist/src/storage/sqlite/upgrades/233_observability_usage_links.sql +3 -0
  262. package/dist/src/storage/sqlite/upgrades/234_task_result_reply.sql +14 -0
  263. package/dist/src/storage/sqlite/upgrades/235_personal_conversation_priority.sql +3 -0
  264. package/dist/src/storage/sqlite/upgrades/236_personal_proactivity.sql +53 -0
  265. package/dist/src/storage/sqlite/upgrades/237_personal_strategy_versions.sql +18 -0
  266. package/dist/src/storage/sqlite/upgrades/238_browser_record_replay.sql +45 -0
  267. package/dist/src/storage/sqlite/upgrades/239_clarification_notifications.sql +26 -0
  268. package/dist/src/storage/sqlite/upgrades/240_device_settings.sql +5 -0
  269. package/dist/src/storage/sqlite/upgrades/241_device_grant_audit.sql +13 -0
  270. package/dist/src/storage/sqlite/upgrades/242_cloud_usage_receipts.sql +5 -0
  271. package/dist/src/storage/sqlite/upgrades/243_voice_opening_greetings.sql +12 -0
  272. package/dist/src/storage/sqlite/upgrades/244_device_request_proofs.sql +8 -0
  273. package/dist/src/storage/sqlite/upgrades/245_memory_learning.sql +125 -0
  274. package/dist/src/storage/sqlite/upgrades/246_personal_session_thinking.sql +22 -0
  275. package/dist/src/storage/sqlite/upgrades/247_agent_selection_records.sql +32 -0
  276. package/dist/src/storage/sqlite/upgrades/248_next_turn_suggestions.sql +20 -0
  277. package/dist/src/storage/sqlite/upgrades/249_task_allocations.sql +17 -0
  278. package/dist/src/storage/sqlite/upgrades/250_research_checkpoints.sql +15 -0
  279. package/dist/src/storage/sqlite/upgrades/251_personal_result_reads.sql +40 -0
  280. package/dist/src/storage/sqlite/upgrades/252_task_work_revisions.sql +15 -0
  281. package/dist/src/storage/sqlite/upgrades/253_discussion_processing_recovery.sql +20 -0
  282. package/dist/src/storage/sqlite/upgrades/254_discussion_annotations.sql +17 -0
  283. package/dist/src/storage/sqlite/upgrades/255_discussion_chapter_progress.sql +10 -0
  284. package/dist/src/storage/sqlite/upgrades/256_task_main_update_retries.sql +21 -0
  285. package/dist/src/storage/sqlite/upgrades/257_session_composer_history.sql +11 -0
  286. package/dist/src/storage/sqlite/upgrades/258_task_phase_changes.sql +20 -0
  287. package/dist/src/storage/sqlite/upgrades/259_personal_default_style.sql +10 -0
  288. package/dist/src/storage/sqlite/upgrades/260_browser_setup.sql +9 -0
  289. package/dist/src/storage/sqlite/windows-database-owners.js +33 -28
  290. package/dist/src/tasks/capabilities/relations.d.ts +2 -2
  291. package/dist/src/tui/clipboard-image.js +1 -1
  292. package/dist/src/tui/tui.js +1 -1
  293. package/dist/src/utils/index.js +1 -1
  294. package/dist/src/utils/logger/index.js +1 -1
  295. package/dist/src/utils/logger.js +1 -1
  296. package/dist/src/work-discovery/probe.js +1 -1
  297. package/package.json +3 -3
  298. package/skills/tools/configure-xopc/SKILL.md +47 -0
  299. package/skills/tools/configure-xopc/references/browser/acceptance.md +31 -0
  300. package/skills/tools/configure-xopc/references/browser/chrome-extension.md +19 -0
  301. package/skills/tools/configure-xopc/references/browser/overview.md +22 -0
  302. package/skills/tools/configure-xopc/references/browser/permissions.md +25 -0
  303. package/skills/tools/configure-xopc/references/browser/troubleshooting.md +24 -0
  304. package/skills/tools/configure-xopc/references/phone/acceptance.md +25 -0
  305. package/skills/tools/configure-xopc/references/phone/aliyun.md +29 -0
  306. package/skills/tools/configure-xopc/references/phone/dependencies.md +18 -0
  307. package/skills/tools/configure-xopc/references/phone/local.md +19 -0
  308. package/skills/tools/configure-xopc/references/phone/models.md +18 -0
  309. package/skills/tools/configure-xopc/references/phone/overview.md +30 -0
  310. package/skills/tools/configure-xopc/references/phone/troubleshooting.md +24 -0
  311. package/skills/tools/configure-xopc/references/scene-index.md +12 -0
  312. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-mf0jgEPE.js +0 -1
  313. package/dist/gateway/static/root/assets/agents-CKhZ4UYQ.js +0 -77
  314. package/dist/gateway/static/root/assets/apps-page-BZ_MaQJf.js +0 -1
  315. package/dist/gateway/static/root/assets/automations-workspace-CHUDHNVL.js +0 -8
  316. package/dist/gateway/static/root/assets/browser-automations-page-DStDm9y1.js +0 -3
  317. package/dist/gateway/static/root/assets/browser-settings-page-6I4oetKt.js +0 -3
  318. package/dist/gateway/static/root/assets/capabilities-page-C-EecWbS.js +0 -2
  319. package/dist/gateway/static/root/assets/capabilities-settings-panel-BQoCPk3x.js +0 -8
  320. package/dist/gateway/static/root/assets/channels-BKf_-Mdt.js +0 -1
  321. package/dist/gateway/static/root/assets/connectors-page-CUBg8spT.js +0 -1
  322. package/dist/gateway/static/root/assets/device-pairing-wizard-PmP_vGem.js +0 -1
  323. package/dist/gateway/static/root/assets/gateway-realtime-DMAzNlm-.js +0 -1
  324. package/dist/gateway/static/root/assets/gateway-realtime-store-CoIgC1Al.js +0 -1
  325. package/dist/gateway/static/root/assets/gateway-settings-DnrQ28E2.js +0 -1
  326. package/dist/gateway/static/root/assets/highlight-code-AMjU04kR.js +0 -1
  327. package/dist/gateway/static/root/assets/home-page-pTwVME-g.js +0 -2
  328. package/dist/gateway/static/root/assets/index-BLL0wKRZ.css +0 -1
  329. package/dist/gateway/static/root/assets/index-ygkHNYyo.js +0 -710
  330. package/dist/gateway/static/root/assets/local-app-workbench-page-Cwl6EvuX.js +0 -1
  331. package/dist/gateway/static/root/assets/logs-page-CS3hcTOq.js +0 -2
  332. package/dist/gateway/static/root/assets/management-settings-DC-Y_-GP.js +0 -1
  333. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-vckgHpON.js +0 -1
  334. package/dist/gateway/static/root/assets/note-detail-panel-C7u4dxEk.js +0 -5
  335. package/dist/gateway/static/root/assets/note-image-lightbox-jvqYtySx.js +0 -1
  336. package/dist/gateway/static/root/assets/notes-page-Bs7F5Hpf.js +0 -8
  337. package/dist/gateway/static/root/assets/page-context-capture-button-DO_yhXS1.js +0 -1
  338. package/dist/gateway/static/root/assets/personal-page-BexL2-PQ.js +0 -1
  339. package/dist/gateway/static/root/assets/personal-settings-panel-BKA4fbYH.js +0 -1
  340. package/dist/gateway/static/root/assets/phone-dependencies-card-ChFtdFhA.js +0 -1
  341. package/dist/gateway/static/root/assets/phone-model-picker-CZoIAQ1j.js +0 -1
  342. package/dist/gateway/static/root/assets/phone-settings-page-DRyK0nHH.js +0 -1
  343. package/dist/gateway/static/root/assets/plugin-details-dialog-B-N61jJH.js +0 -1
  344. package/dist/gateway/static/root/assets/project-detail-page-DtKmFBml.js +0 -7
  345. package/dist/gateway/static/root/assets/projects-page-CFZIz9mc.js +0 -1
  346. package/dist/gateway/static/root/assets/remote-access-hub-CWEc7W0m.js +0 -1
  347. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-q_oswAdV.js +0 -1
  348. package/dist/gateway/static/root/assets/sessions-page-BuPqNxpd.js +0 -1
  349. package/dist/gateway/static/root/assets/settings-advanced-gate-QTVDCGJG.js +0 -1
  350. package/dist/gateway/static/root/assets/settings-page-header-CYpuTXUW.js +0 -1
  351. package/dist/gateway/static/root/assets/setup-status-panel-ZmlE8jIE.js +0 -1
  352. package/dist/gateway/static/root/assets/shares-settings-CtNxWqW-.js +0 -1
  353. package/dist/gateway/static/root/assets/skill-reload-api-Egaf8PqZ.js +0 -1
  354. package/dist/gateway/static/root/assets/skills-page-C6FKxf4J.js +0 -2
  355. package/dist/gateway/static/root/assets/system-settings-panel-Baxkhov7.js +0 -1
  356. package/dist/gateway/static/root/assets/task-detail-page-C77-rpkt.js +0 -2
  357. package/dist/gateway/static/root/assets/usage-page-BFeIbpbi.js +0 -1
  358. package/dist/gateway/static/root/assets/user-model-page-u8zY5jea.js +0 -2
  359. 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 (session.report.mock ? isAboutScreen(observation) : Boolean(input.expectText && session.report.facts?.some((text) => text.includes(input.expectText)))) {
297
- session.report.verified = true;
298
- session.report.verificationLevel = "ui";
299
- session.report.status = "completed";
300
- session.report.stopReason = actions ? "condition_satisfied" : "condition_present";
301
- return this.publish(session);
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
- if (session.report.modelRequests >= context.config.phone.maxModelRequests) throw new PhoneError("PHONE_MODEL_LIMIT", "Phone model request limit reached");
309
- session.report.modelRequests++;
310
- session.report.currentAction = void 0;
311
- this.publish(session);
312
- session.prediction = new AbortController();
313
- let decision;
314
- try {
315
- decision = await session.adapter.predict({
316
- goal: input.goal,
317
- observation,
318
- allowedApps: session.device.allowedApps,
319
- appAccess: phoneAppAccess(session.device),
320
- applications: session.applications.filter((app) => phoneAllowsApp(session.device, app.packageName)),
321
- history: session.report.steps.map((step) => step.action),
322
- scenario: input.scenario
323
- }, AbortSignal.any([signal, session.prediction.signal]));
324
- } catch (error) {
325
- if (!signal.aborted && epoch !== session.report.controlEpoch) {
326
- await this.waitForAgent(session, signal);
327
- observation.frame.fill(0);
328
- observation = await this.observe(session, signal);
329
- continue;
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 : void 0;
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 (fresh.package !== observation.package || fresh.width !== observation.width || fresh.height !== observation.height || fresh.rotation !== observation.rotation || JSON.stringify(fresh.elements) !== JSON.stringify(observation.elements) || !fresh.elements.length && !fresh.frame.equals(observation.frame)) {
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
- if (await this.dispatch(session, decision.action, fresh, context, signal, epoch)) actions++;
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, session.human ? {
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
- session.report.status = "outcome_unknown";
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 };