@xopcai/xopc 0.0.411 → 0.0.413

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 (307) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-sGJnq-SA.js → agent-avatar-dicebear-BT6oqCMD.js} +1 -1
  4. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BFmRRD_4.js +1 -0
  5. package/dist/gateway/static/root/assets/agents-Clwskw2J.js +77 -0
  6. package/dist/gateway/static/root/assets/{agents-admin-api-uGDeJR1f.js → agents-admin-api-CeBkHnl8.js} +1 -1
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-BdCgtTfT.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-C3-hCFlF.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-DJbKg3va.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-CGdU_E5B.js → archive-plugin-BviFGCy4.js} +1 -1
  11. package/dist/gateway/static/root/assets/{automations-page-BAPZY56r.js → automations-page-CfzazXE5.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-workspace-D_X0_1X3.js +8 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-B0ispXo2.js → binary-plugins-Dp-gtJEk.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-B9Ci-prO.js → block-editor-D-DEPdpi.js} +4 -4
  15. package/dist/gateway/static/root/assets/{browser-automation-inputs-D4-vQc4g.js → browser-automation-inputs-D1pDgMJu.js} +1 -1
  16. package/dist/gateway/static/root/assets/browser-automations-page-BI-ep6uM.js +3 -0
  17. package/dist/gateway/static/root/assets/browser-settings-page-BTyQ4-vN.js +3 -0
  18. package/dist/gateway/static/root/assets/capabilities-Bpeh6E22.js +1 -0
  19. package/dist/gateway/static/root/assets/capabilities-page-GNS95mG9.js +2 -0
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-DBiv1HN-.js +8 -0
  21. package/dist/gateway/static/root/assets/{capability-header-actions-Cic05oWh.js → capability-header-actions-CP2fI9Fe.js} +1 -1
  22. package/dist/gateway/static/root/assets/channels-DWlrUKBr.js +1 -0
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-Bm-IGeDe.js → chat-terminal-dock-BL3tFntQ.js} +2 -2
  24. package/dist/gateway/static/root/assets/computer-settings-page-DEQ5GYfC.js +1 -0
  25. package/dist/gateway/static/root/assets/{connector-service-page-DcdASUU9.js → connector-service-page-CecwMnC5.js} +1 -1
  26. package/dist/gateway/static/root/assets/connectors-page-BcpUvrtl.js +1 -0
  27. package/dist/gateway/static/root/assets/{date-picker-gVLWu9R0.js → date-picker-N5jnlvPs.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-C0LARyok.js → dependency-picker-C4jddxFl.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-v_le3sCs.js → desktop-pet-BCbiUNQG.js} +1 -1
  30. package/dist/gateway/static/root/assets/desktop-pet-settings-CkKU0JMY.js +1 -0
  31. package/dist/gateway/static/root/assets/device-pairing-wizard--E2GQoY1.js +1 -0
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-CBefVUPR.js → directory-picker-path-field-CbMbPimD.js} +1 -1
  33. package/dist/gateway/static/root/assets/extension-debug-page-OE1nJMQ8.js +1 -0
  34. package/dist/gateway/static/root/assets/{extension-page-C0-oP7S_.js → extension-page-BEomiKhy.js} +1 -1
  35. package/dist/gateway/static/root/assets/extension-settings-page-BFOjQeSX.js +1 -0
  36. package/dist/gateway/static/root/assets/{gateway-config-swr-BVqYVaGy.js → gateway-config-swr-DF_HV6NP.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-realtime-CY1LBGBS.js → gateway-realtime-DMAzNlm-.js} +1 -1
  38. package/dist/gateway/static/root/assets/gateway-realtime-store-CoIgC1Al.js +1 -0
  39. package/dist/gateway/static/root/assets/gateway-settings-CR4CsfNN.js +1 -0
  40. package/dist/gateway/static/root/assets/{gateway-startup-retry-CPKGkr6D.js → gateway-startup-retry-B91CBTzO.js} +1 -1
  41. package/dist/gateway/static/root/assets/highlight-code-6ONPRH5r.js +1 -0
  42. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-CN5PNRN3.js → highlighted-body-KQOG7T2V-EJ9Kg4iQ.js} +1 -1
  43. package/dist/gateway/static/root/assets/home-page-B9w3a6r2.js +2 -0
  44. package/dist/gateway/static/root/assets/{image-generation-api-DRLXG9Ws.js → image-generation-api-D0HNic89.js} +1 -1
  45. package/dist/gateway/static/root/assets/imports-page-bxTINe-2.js +1 -0
  46. package/dist/gateway/static/root/assets/index-D1oivYvN.js +710 -0
  47. package/dist/gateway/static/root/assets/index-D_7q1UkI.css +1 -0
  48. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-Cmi-2SIh.js +1 -0
  49. package/dist/gateway/static/root/assets/local-app-workbench-page-NGCmXpa_.js +1 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-BChE6nUD.js → local-apps-page-jgaogH9Z.js} +1 -1
  51. package/dist/gateway/static/root/assets/{local-session-drafts-BCaC-1rH.js → local-session-drafts-DvmwiLUx.js} +1 -1
  52. package/dist/gateway/static/root/assets/{locale-store-DAgpZxAS.js → locale-store-JogcXC4J.js} +1 -1
  53. package/dist/gateway/static/root/assets/logs-page-drrr-c2W.js +2 -0
  54. package/dist/gateway/static/root/assets/management-settings-Dc1opXVr.js +1 -0
  55. package/dist/gateway/static/root/assets/{media-plugins-BmLuWkkZ.js → media-plugins-BRS9puQV.js} +1 -1
  56. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-B--edI1I.js +1 -0
  57. package/dist/gateway/static/root/assets/{messages-DMXSIJUO.js → messages-RzwPiQNL.js} +2 -2
  58. package/dist/gateway/static/root/assets/note-detail-panel-C3s4-ytB.js +5 -0
  59. package/dist/gateway/static/root/assets/note-image-lightbox-D7q5-KuS.js +1 -0
  60. package/dist/gateway/static/root/assets/notes-page-qVxoErUS.js +8 -0
  61. package/dist/gateway/static/root/assets/{page-context-capture-button-B7rDRlS7.js → page-context-capture-button-D_VOB2_C.js} +1 -1
  62. package/dist/gateway/static/root/assets/personal-page-B-T8NzQo.js +1 -0
  63. package/dist/gateway/static/root/assets/personal-settings-panel-BKA4fbYH.js +1 -0
  64. package/dist/gateway/static/root/assets/phone-dependencies-card-DhEsfEUN.js +1 -0
  65. package/dist/gateway/static/root/assets/phone-model-picker-J4mFDk21.js +1 -0
  66. package/dist/gateway/static/root/assets/phone-settings-page-BLflz8CQ.js +1 -0
  67. package/dist/gateway/static/root/assets/plugin-details-dialog-1BwvmKZi.js +1 -0
  68. package/dist/gateway/static/root/assets/{preview-open-alternatives-Z4NM7_Dn.js → preview-open-alternatives-DaTaSKox.js} +1 -1
  69. package/dist/gateway/static/root/assets/{product-open-page-C5TcIaJj.js → product-open-page-wYlC0IVZ.js} +1 -1
  70. package/dist/gateway/static/root/assets/{product-preview-content-5xID6jIj.js → product-preview-content-Bxur-p6S.js} +1 -1
  71. package/dist/gateway/static/root/assets/project-detail-page-DwowzxzD.js +7 -0
  72. package/dist/gateway/static/root/assets/projects-page-Bwvn4i_e.js +1 -0
  73. package/dist/gateway/static/root/assets/{registry-api-B6kqbuw8.js → registry-api-BGqSwITi.js} +1 -1
  74. package/dist/gateway/static/root/assets/remote-access-hub-DrHisOUe.js +1 -0
  75. package/dist/gateway/static/root/assets/runtime-tools-api-CSm5SpnR.js +5 -0
  76. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-DXNidliV.js +1 -0
  77. package/dist/gateway/static/root/assets/{schema-form-DtPkiYwm.js → schema-form-DeSZ7SiO.js} +1 -1
  78. package/dist/gateway/static/root/assets/{session-api-D6-Vz8xK.js → session-api-DTxZyMta.js} +1 -1
  79. package/dist/gateway/static/root/assets/{session-manager-DWbcMHcj.js → session-manager-B2HDomj4.js} +1 -1
  80. package/dist/gateway/static/root/assets/sessions-page-seP7t0kv.js +1 -0
  81. package/dist/gateway/static/root/assets/settings-advanced-gate-VqBu7gHu.js +1 -0
  82. package/dist/gateway/static/root/assets/{settings-form-section-DD3iD5t5.js → settings-form-section-BNYQjZU4.js} +1 -1
  83. package/dist/gateway/static/root/assets/{settings-page-iLY3LRDq.js → settings-page-29Ix0jSQ.js} +1 -1
  84. package/dist/gateway/static/root/assets/{settings-page-layout-Dx5S-Msc.js → settings-page-header-CYpuTXUW.js} +1 -1
  85. package/dist/gateway/static/root/assets/settings-page-layout-B20AfmFG.js +1 -0
  86. package/dist/gateway/static/root/assets/setup-status-panel-COQZgKX9.js +1 -0
  87. package/dist/gateway/static/root/assets/{share-preview-page-B8h9lqDL.js → share-preview-page-CwMRULXc.js} +1 -1
  88. package/dist/gateway/static/root/assets/shares-settings-BWaykw9E.js +1 -0
  89. package/dist/gateway/static/root/assets/{skill-api-C9RsrvOp.js → skill-api-xfB5fUAh.js} +1 -1
  90. package/dist/gateway/static/root/assets/skill-reload-api-Bq-3_MCt.js +1 -0
  91. package/dist/gateway/static/root/assets/skills-page-C3LfWsAZ.js +2 -0
  92. package/dist/gateway/static/root/assets/system-settings-panel-DRJu1ehM.js +1 -0
  93. package/dist/gateway/static/root/assets/task-detail-page-XCJFP-Aa.js +2 -0
  94. package/dist/gateway/static/root/assets/{task-result-evidence-DjNWPpn_.js → task-result-evidence-C4o_Yue_.js} +1 -1
  95. package/dist/gateway/static/root/assets/tracing-settings-page-CYslh-Pu.js +1 -0
  96. package/dist/gateway/static/root/assets/{tunnel-api-C6XfsSWy.js → tunnel-api-Bi_kw6bv.js} +1 -1
  97. package/dist/gateway/static/root/assets/usage-page-CTTmklCs.js +1 -0
  98. package/dist/gateway/static/root/assets/{use-autosave-DO-Twmbm.js → use-autosave-BkB9uD93.js} +1 -1
  99. package/dist/gateway/static/root/assets/user-model-page-BDqguzRE.js +2 -0
  100. package/dist/gateway/static/root/assets/{voice-api-key-field-MGe3HkS_.js → voice-api-key-field-bt8_Agih.js} +1 -1
  101. package/dist/gateway/static/root/assets/{voice-config-api-CPKzUb4R.js → voice-config-api-D7xsWrdh.js} +1 -1
  102. package/dist/gateway/static/root/assets/{work-discovery-overlay-DptHqYh5.js → work-discovery-overlay-D3NG14dX.js} +1 -1
  103. package/dist/gateway/static/root/assets/{xopc-cloud-account-card-Y_UIryBH.js → xopc-cloud-account-card-B2OUKOQi.js} +1 -1
  104. package/dist/gateway/static/root/index.html +14 -14
  105. package/dist/package.js +1 -1
  106. package/dist/packages/gateway-contract/src/capabilities.js +1 -0
  107. package/dist/src/agent/agent-manager.js +1 -1
  108. package/dist/src/agent/background-review/prompts.js +4 -3
  109. package/dist/src/agent/background-review/run-background-review.js +1 -1
  110. package/dist/src/agent/embedded/run-turn.js +1 -1
  111. package/dist/src/agent/embedded/xopc-stream-bridge.js +7 -3
  112. package/dist/src/agent/external-tools/cliProvider.js +2 -2
  113. package/dist/src/agent/external-tools/composio-provider.js +2 -2
  114. package/dist/src/agent/external-tools/endpoint-provider.js +2 -2
  115. package/dist/src/agent/prompt/system-prompt.js +1 -1
  116. package/dist/src/agent/service.js +1 -1
  117. package/dist/src/agent/skills/index.js +1 -1
  118. package/dist/src/agent/skills/managed-store.js +1 -1
  119. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  120. package/dist/src/agent/tool-manuals/index.js +7 -0
  121. package/dist/src/agent/tool-manuals/phone.d.ts +1 -0
  122. package/dist/src/agent/tool-manuals/phone.js +16 -0
  123. package/dist/src/agent/tools/factory.js +15 -0
  124. package/dist/src/agent/tools/knowledge-memory-tool.js +1 -1
  125. package/dist/src/agent/tools/personal-read-tool.js +1 -1
  126. package/dist/src/agent/tools/personal-task-tool.d.ts +2 -1
  127. package/dist/src/agent/tools/personal-task-tool.js +43 -20
  128. package/dist/src/agent/tools/phone-use-tool.d.ts +8 -0
  129. package/dist/src/agent/tools/phone-use-tool.js +49 -0
  130. package/dist/src/agent/tools/session-recall-tool.js +2 -1
  131. package/dist/src/agent/tools/session-search-tool.js +11 -5
  132. package/dist/src/agent/tools/user-context-tool.js +1 -1
  133. package/dist/src/agent/tools/xopc-use-tool.js +2 -2
  134. package/dist/src/agent-catalog/capabilities.js +2 -2
  135. package/dist/src/agent-catalog/repository.js +5 -1
  136. package/dist/src/agent-config/index.js +2 -2
  137. package/dist/src/agent-config/resolver.js +5 -0
  138. package/dist/src/agent-config/schema.d.ts +24 -0
  139. package/dist/src/agent-config/schema.js +5 -2
  140. package/dist/src/automations/capabilities/drafts.js +1 -1
  141. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  142. package/dist/src/capabilities/runtime/dispatcher.js +1 -1
  143. package/dist/src/capabilities/runtime/product.js +1 -1
  144. package/dist/src/cli/command-manifest.js +1 -1
  145. package/dist/src/cli/commands/agents.js +1 -1
  146. package/dist/src/cli/commands/models.js +1 -1
  147. package/dist/src/cli/commands/onboard/model.js +1 -1
  148. package/dist/src/cli/commands/onboard.js +1 -1
  149. package/dist/src/cli/commands/runtime.js +32 -4
  150. package/dist/src/cli/utils/init-workspace-core.js +6 -4
  151. package/dist/src/computer/diagnostics.d.ts +1 -1
  152. package/dist/src/config/agent-profile.js +1 -1
  153. package/dist/src/config/config-file.d.ts +6 -0
  154. package/dist/src/config/config-file.js +35 -0
  155. package/dist/src/config/loader.js +5 -4
  156. package/dist/src/config/models-json.d.ts +36 -0
  157. package/dist/src/config/models-json.js +9 -0
  158. package/dist/src/config/schema.d.ts +12 -0
  159. package/dist/src/config/schema.js +6 -2
  160. package/dist/src/execution-environments/local-worktree-manager.js +1 -1
  161. package/dist/src/extensions/agent-plugins/skill-catalog.js +1 -1
  162. package/dist/src/extensions/agent-plugins/validation.js +1 -1
  163. package/dist/src/gateway/agent-builtin-tools.d.ts +7 -1
  164. package/dist/src/gateway/agent-builtin-tools.js +7 -0
  165. package/dist/src/gateway/agents-admin.js +2 -2
  166. package/dist/src/gateway/global-defaults-admin.js +2 -0
  167. package/dist/src/gateway/hono/lib/config-payload.d.ts +8 -0
  168. package/dist/src/gateway/hono/routes/agents.js +1 -1
  169. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  170. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  171. package/dist/src/gateway/hono/routes/models.js +3 -0
  172. package/dist/src/gateway/hono/routes/notes.js +2 -2
  173. package/dist/src/gateway/hono/routes/phone-dependencies.d.ts +3 -0
  174. package/dist/src/gateway/hono/routes/phone-dependencies.js +137 -0
  175. package/dist/src/gateway/hono/routes/phone.d.ts +4 -0
  176. package/dist/src/gateway/hono/routes/phone.js +445 -0
  177. package/dist/src/gateway/hono/routes/projects.js +2 -2
  178. package/dist/src/gateway/hono/routes/runtime-tools.js +2 -0
  179. package/dist/src/gateway/hono/routes/session-input-handler.js +1 -1
  180. package/dist/src/gateway/hono/routes/tasks.js +1 -1
  181. package/dist/src/gateway/image-generation-setup.js +1 -1
  182. package/dist/src/gateway/server.js +1 -0
  183. package/dist/src/gateway/service/config-coordinator.d.ts +8 -0
  184. package/dist/src/gateway/service.d.ts +2 -0
  185. package/dist/src/gateway/service.js +17 -12
  186. package/dist/src/gateway/xopc-cloud-capability-setup.js +1 -1
  187. package/dist/src/home-intelligence/host.js +2 -2
  188. package/dist/src/imports/importService.js +1 -1
  189. package/dist/src/knowledge-memory/repository.js +5 -0
  190. package/dist/src/local-apps/service.js +1 -1
  191. package/dist/src/memory-learning/forget-capture.js +12 -3
  192. package/dist/src/memory-learning/forgotten-history.d.ts +4 -0
  193. package/dist/src/memory-learning/forgotten-history.js +71 -4
  194. package/dist/src/memory-learning/work-capture.d.ts +1 -0
  195. package/dist/src/memory-learning/work-capture.js +28 -17
  196. package/dist/src/personal-agent/prompts.js +3 -2
  197. package/dist/src/personal-agent/service.js +1 -1
  198. package/dist/src/phone/adb-driver.d.ts +35 -0
  199. package/dist/src/phone/adb-driver.js +368 -0
  200. package/dist/src/phone/cloud-adb.d.ts +34 -0
  201. package/dist/src/phone/cloud-adb.js +223 -0
  202. package/dist/src/phone/cloud-phones.d.ts +29 -0
  203. package/dist/src/phone/cloud-phones.js +141 -0
  204. package/dist/src/phone/cloud-scrcpy.d.ts +20 -0
  205. package/dist/src/phone/cloud-scrcpy.js +122 -0
  206. package/dist/src/phone/contracts.d.ts +204 -0
  207. package/dist/src/phone/contracts.js +115 -0
  208. package/dist/src/phone/interactive-session.d.ts +34 -0
  209. package/dist/src/phone/interactive-session.js +164 -0
  210. package/dist/src/phone/live-provider.d.ts +57 -0
  211. package/dist/src/phone/live-provider.js +18 -0
  212. package/dist/src/phone/live-state.d.ts +28 -0
  213. package/dist/src/phone/live-state.js +71 -0
  214. package/dist/src/phone/model-adapter.d.ts +25 -0
  215. package/dist/src/phone/model-adapter.js +340 -0
  216. package/dist/src/phone/repository.d.ts +19 -0
  217. package/dist/src/phone/repository.js +100 -0
  218. package/dist/src/phone/runtime.d.ts +83 -0
  219. package/dist/src/phone/runtime.js +896 -0
  220. package/dist/src/phone/scrcpy.d.ts +62 -0
  221. package/dist/src/phone/scrcpy.js +345 -0
  222. package/dist/src/phone/stream-gateway.d.ts +26 -0
  223. package/dist/src/phone/stream-gateway.js +210 -0
  224. package/dist/src/process/phone-process.d.ts +4 -0
  225. package/dist/src/process/phone-process.js +38 -0
  226. package/dist/src/providers/extension-stream-bridge.js +8 -1
  227. package/dist/src/providers/model-call.js +6 -2
  228. package/dist/src/providers/model-catalog-persistence.js +3 -0
  229. package/dist/src/providers/model-catalog-types.d.ts +3 -0
  230. package/dist/src/providers/model-reference-auditor.js +5 -1
  231. package/dist/src/providers/model-registry.js +3 -0
  232. package/dist/src/runtime-tools/archive.d.ts +2 -2
  233. package/dist/src/runtime-tools/archive.js +1 -1
  234. package/dist/src/runtime-tools/downloader.d.ts +2 -2
  235. package/dist/src/runtime-tools/errors.d.ts +3 -3
  236. package/dist/src/runtime-tools/phone-dependencies.d.ts +40 -0
  237. package/dist/src/runtime-tools/phone-dependencies.js +188 -0
  238. package/dist/src/runtime-tools/phone-dependency-catalog.d.ts +16 -0
  239. package/dist/src/runtime-tools/phone-dependency-catalog.js +51 -0
  240. package/dist/src/runtime-tools/types.d.ts +1 -0
  241. package/dist/src/storage/sqlite/context-extraction-repository.d.ts +1 -0
  242. package/dist/src/storage/sqlite/context-extraction-repository.js +12 -2
  243. package/dist/src/tasks/capabilities/read.js +2 -2
  244. package/dist/src/tasks/capabilities/write.js +1 -1
  245. package/dist/src/tasks/task-research-result.js +19 -2
  246. package/dist/src/tui/backends/embedded-backend.js +1 -1
  247. package/dist/src/usage/cloud-receipts.d.ts +5 -1
  248. package/dist/src/usage/cloud-receipts.js +10 -4
  249. package/dist/src/usage/cloud-wire.d.ts +37 -0
  250. package/dist/src/usage/cloud-wire.js +181 -0
  251. package/dist/src/usage/recorder.js +5 -4
  252. package/dist/src/user-model/capture/semantic.js +2 -2
  253. package/dist/src/voice/platform-catalog.d.ts +3 -0
  254. package/dist/src/voice/realtime/persona-context.js +1 -1
  255. package/package.json +9 -4
  256. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BI7OTo-T.js +0 -1
  257. package/dist/gateway/static/root/assets/agents-RIXL0p7_.js +0 -77
  258. package/dist/gateway/static/root/assets/app-management-settings-panel-BGzhSS6H.js +0 -1
  259. package/dist/gateway/static/root/assets/appearance-settings-DtEZq4b2.js +0 -1
  260. package/dist/gateway/static/root/assets/apps-page-DZqBof2D.js +0 -1
  261. package/dist/gateway/static/root/assets/automations-workspace-CI-yQnSj.js +0 -8
  262. package/dist/gateway/static/root/assets/browser-automations-page-Xzdif447.js +0 -3
  263. package/dist/gateway/static/root/assets/browser-settings-page-Bhu-83eC.js +0 -3
  264. package/dist/gateway/static/root/assets/capabilities-B9b5KCBb.js +0 -1
  265. package/dist/gateway/static/root/assets/capabilities-page-BIc0Zlsw.js +0 -2
  266. package/dist/gateway/static/root/assets/capabilities-settings-panel-CQEfpLdj.js +0 -8
  267. package/dist/gateway/static/root/assets/channels-DQbEoo_o.js +0 -1
  268. package/dist/gateway/static/root/assets/computer-settings-page-C9xMfwXK.js +0 -1
  269. package/dist/gateway/static/root/assets/connectors-page-eh-xpMPK.js +0 -1
  270. package/dist/gateway/static/root/assets/desktop-pet-settings-B_-j-D4W.js +0 -1
  271. package/dist/gateway/static/root/assets/device-pairing-wizard-CxG_FcQ6.js +0 -1
  272. package/dist/gateway/static/root/assets/extension-debug-page-CTe7Molh.js +0 -1
  273. package/dist/gateway/static/root/assets/extension-settings-page-DYJmgMUg.js +0 -1
  274. package/dist/gateway/static/root/assets/gateway-realtime-store-Dafw95ol.js +0 -1
  275. package/dist/gateway/static/root/assets/gateway-settings-C13P4lQd.js +0 -1
  276. package/dist/gateway/static/root/assets/highlight-code-CslBKXdS.js +0 -1
  277. package/dist/gateway/static/root/assets/home-page-B_XrkGmA.js +0 -2
  278. package/dist/gateway/static/root/assets/imports-page--cuF5vwU.js +0 -1
  279. package/dist/gateway/static/root/assets/index-6YjAt50A.js +0 -710
  280. package/dist/gateway/static/root/assets/index-caRW34rg.css +0 -1
  281. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-5g2PxgBs.js +0 -1
  282. package/dist/gateway/static/root/assets/local-app-workbench-page-B6U1HQpp.js +0 -1
  283. package/dist/gateway/static/root/assets/logs-page-B9mq03SK.js +0 -2
  284. package/dist/gateway/static/root/assets/management-settings-2W_qJsha.js +0 -1
  285. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-61Il2HQR.js +0 -1
  286. package/dist/gateway/static/root/assets/note-detail-panel-C4gZsNBL.js +0 -5
  287. package/dist/gateway/static/root/assets/note-image-lightbox-XqJIaaRV.js +0 -1
  288. package/dist/gateway/static/root/assets/notes-page-Chdwrjni.js +0 -8
  289. package/dist/gateway/static/root/assets/personal-page-mQl9BftY.js +0 -1
  290. package/dist/gateway/static/root/assets/personal-settings-panel-BgcJLmZN.js +0 -1
  291. package/dist/gateway/static/root/assets/plugin-details-dialog-FvwSxZPB.js +0 -1
  292. package/dist/gateway/static/root/assets/project-detail-page-CGOyx7zX.js +0 -7
  293. package/dist/gateway/static/root/assets/projects-page-Dd11tbRX.js +0 -1
  294. package/dist/gateway/static/root/assets/remote-access-hub-Bintk9nL.js +0 -1
  295. package/dist/gateway/static/root/assets/runtime-tools-api-CY3R7unQ.js +0 -5
  296. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-CbmiiLsq.js +0 -1
  297. package/dist/gateway/static/root/assets/sessions-page-BBlEP7y3.js +0 -1
  298. package/dist/gateway/static/root/assets/settings-advanced-gate-BCQUth4g.js +0 -1
  299. package/dist/gateway/static/root/assets/setup-status-panel-v4P0IAkG.js +0 -1
  300. package/dist/gateway/static/root/assets/shares-settings-DMzej6z2.js +0 -1
  301. package/dist/gateway/static/root/assets/skill-reload-api-B20x7EE9.js +0 -1
  302. package/dist/gateway/static/root/assets/skills-page-C_ulsnv7.js +0 -2
  303. package/dist/gateway/static/root/assets/system-settings-panel-PTRGMKkq.js +0 -1
  304. package/dist/gateway/static/root/assets/task-detail-page-DEPwo4vf.js +0 -2
  305. package/dist/gateway/static/root/assets/tracing-settings-page-CVJt7IXC.js +0 -1
  306. package/dist/gateway/static/root/assets/usage-page-DgqLD8Y5.js +0 -1
  307. package/dist/gateway/static/root/assets/user-model-page-BwK37aob.js +0 -2
@@ -0,0 +1,62 @@
1
+ import { SCRCPY_SHA256, SCRCPY_VERSION } from '../runtime-tools/phone-dependency-catalog.js';
2
+ import type { PhoneInteractiveProvider, PhonePointer, PhoneVideoGeometry, PhoneVideoPacket } from './live-provider.js';
3
+ export { SCRCPY_VERSION, SCRCPY_SHA256 };
4
+ export declare const scrcpyServerPath: (stateDir?: string) => string;
5
+ /** The pinned server sends codec metadata followed by bounded, length-prefixed packets. */
6
+ export declare class ScrcpyVideoParser {
7
+ private buffer;
8
+ private metadata;
9
+ push(chunk: Buffer, packet: (packet: PhoneVideoPacket) => void): void;
10
+ }
11
+ export declare function scrcpyTouch(phase: PhonePointer['phase'], x: number, y: number, width: number, height: number): Buffer;
12
+ export declare function readScrcpyServer(): Promise<Buffer>;
13
+ /** Local and cloud transports share geometry, gesture sequencing and revocation. */
14
+ export declare abstract class ScrcpyProvider implements PhoneInteractiveProvider {
15
+ private onFailure;
16
+ readonly descriptor: {
17
+ readonly kind: "scrcpy-h264";
18
+ readonly protocolVersion: 1;
19
+ readonly continuousTouch: true;
20
+ readonly maxPointers: 1;
21
+ };
22
+ geometry: PhoneVideoGeometry;
23
+ protected closing: boolean;
24
+ private touch?;
25
+ private listeners;
26
+ private config?;
27
+ private opening?;
28
+ private startResult?;
29
+ private closeResult?;
30
+ constructor(onFailure: () => void);
31
+ abstract foreground(signal: AbortSignal): Promise<string>;
32
+ protected abstract startTransport(): Promise<void>;
33
+ protected abstract write(buffer: Buffer): Promise<void>;
34
+ protected abstract cleanup(): Promise<void>;
35
+ start(): Promise<void>;
36
+ protected packet(packet: PhoneVideoPacket): void;
37
+ subscribe(listener: (packet: PhoneVideoPacket) => void): () => void;
38
+ pointer(input: PhonePointer): Promise<void>;
39
+ revoke(): Promise<void>;
40
+ protected fail(): void;
41
+ refresh(): void;
42
+ close(): Promise<void>;
43
+ }
44
+ export declare class LocalScrcpyProvider extends ScrcpyProvider {
45
+ private adb;
46
+ private serial;
47
+ private tuning;
48
+ private process?;
49
+ private video?;
50
+ private control?;
51
+ private port?;
52
+ private remote;
53
+ private scid;
54
+ constructor(adb: string, serial: string, onFailure: () => void, tuning?: {
55
+ maxSize: number;
56
+ bitRate: number;
57
+ });
58
+ foreground(signal: AbortSignal): Promise<string>;
59
+ protected startTransport(): Promise<void>;
60
+ protected write(buffer: Buffer): Promise<void>;
61
+ protected cleanup(): Promise<void>;
62
+ }
@@ -0,0 +1,345 @@
1
+ import { PhoneError, init_contracts } from "./contracts.js";
2
+ import { spawnPhoneCommand } from "../process/phone-process.js";
3
+ import { SCRCPY_SHA256, SCRCPY_VERSION, managedScrcpyServerPath } from "../runtime-tools/phone-dependency-catalog.js";
4
+ import { AdbPhoneDriver, runAdb } from "./adb-driver.js";
5
+ import { createHash, randomBytes } from "node:crypto";
6
+ import { readFile } from "node:fs/promises";
7
+ import { connect } from "node:net";
8
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
9
+ import { h264ParseConfiguration } from "@yume-chan/scrcpy";
10
+ //#region src/phone/scrcpy.ts
11
+ init_contracts();
12
+ const scrcpyServerPath = managedScrcpyServerPath;
13
+ /** The pinned server sends codec metadata followed by bounded, length-prefixed packets. */
14
+ var ScrcpyVideoParser = class {
15
+ buffer = Buffer.alloc(0);
16
+ metadata = false;
17
+ push(chunk, packet) {
18
+ if (chunk.length + this.buffer.length > 8 * 1024 * 1024) throw new Error("Scrcpy video buffer exceeded");
19
+ this.buffer = Buffer.concat([this.buffer, chunk]);
20
+ if (!this.metadata) {
21
+ if (this.buffer.length < 12) return;
22
+ if (this.buffer.readUInt32BE(0) !== 1748121140) throw new Error("Unsupported scrcpy codec");
23
+ this.buffer = this.buffer.subarray(12);
24
+ this.metadata = true;
25
+ }
26
+ while (this.buffer.length >= 12) {
27
+ const size = this.buffer.readUInt32BE(8);
28
+ if (!size || size > 4 * 1024 * 1024) throw new Error("Invalid scrcpy video packet");
29
+ if (this.buffer.length < size + 12) return;
30
+ const flags = this.buffer.readBigUInt64BE(0);
31
+ packet({
32
+ data: Buffer.from(this.buffer.subarray(12, size + 12)),
33
+ config: Boolean(flags & 1n << 63n),
34
+ key: Boolean(flags & 1n << 62n),
35
+ pts: Number(flags & (1n << 62n) - 1n)
36
+ });
37
+ this.buffer = this.buffer.subarray(size + 12);
38
+ }
39
+ }
40
+ };
41
+ function scrcpyTouch(phase, x, y, width, height) {
42
+ const buffer = Buffer.alloc(32);
43
+ buffer[0] = 2;
44
+ buffer[1] = {
45
+ down: 0,
46
+ up: 1,
47
+ move: 2,
48
+ cancel: 3
49
+ }[phase];
50
+ buffer.writeBigUInt64BE(0n, 2);
51
+ buffer.writeInt32BE(Math.min(width - 1, Math.round(x * width / 1e3)), 10);
52
+ buffer.writeInt32BE(Math.min(height - 1, Math.round(y * height / 1e3)), 14);
53
+ buffer.writeUInt16BE(width, 18);
54
+ buffer.writeUInt16BE(height, 20);
55
+ buffer.writeUInt16BE(phase === "up" || phase === "cancel" ? 0 : 65535, 22);
56
+ return buffer;
57
+ }
58
+ async function readScrcpyServer() {
59
+ const binary = await readFile(scrcpyServerPath()).catch(() => {
60
+ throw new PhoneError("PHONE_VIDEO_SETUP_REQUIRED", "Install scrcpy server in Settings → Phone Use → Dependencies");
61
+ });
62
+ if (createHash("sha256").update(binary).digest("hex") !== "7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0") throw new PhoneError("PHONE_VIDEO_HASH_MISMATCH", "Phone video server checksum mismatch");
63
+ return binary;
64
+ }
65
+ /** Local and cloud transports share geometry, gesture sequencing and revocation. */
66
+ var ScrcpyProvider = class {
67
+ descriptor = {
68
+ kind: "scrcpy-h264",
69
+ protocolVersion: 1,
70
+ continuousTouch: true,
71
+ maxPointers: 1
72
+ };
73
+ geometry = {
74
+ width: 0,
75
+ height: 0,
76
+ version: 0,
77
+ codec: ""
78
+ };
79
+ closing = false;
80
+ touch;
81
+ listeners = /* @__PURE__ */ new Set();
82
+ config;
83
+ opening;
84
+ startResult;
85
+ closeResult;
86
+ constructor(onFailure) {
87
+ this.onFailure = onFailure;
88
+ }
89
+ start() {
90
+ if (this.closing) return Promise.reject(new PhoneError("PHONE_VIDEO_ENDED", "Phone video ended", 409));
91
+ if (!this.startResult) {
92
+ this.opening = this.startTransport();
93
+ this.startResult = this.opening.catch(async (error) => {
94
+ await this.close();
95
+ throw error;
96
+ });
97
+ }
98
+ return this.startResult;
99
+ }
100
+ packet(packet) {
101
+ if (packet.config) {
102
+ const info = h264ParseConfiguration(packet.data);
103
+ this.geometry = {
104
+ width: info.croppedWidth,
105
+ height: info.croppedHeight,
106
+ version: this.geometry.version + 1,
107
+ codec: `avc1.${[
108
+ info.profileIndex,
109
+ info.constraintSet,
110
+ info.levelIndex
111
+ ].map((value) => value.toString(16).padStart(2, "0")).join("")}`
112
+ };
113
+ this.config = {
114
+ ...packet,
115
+ geometry: this.geometry
116
+ };
117
+ if (this.touch) this.revoke().catch(() => this.fail());
118
+ }
119
+ for (const listener of this.listeners) listener({
120
+ ...packet,
121
+ geometry: this.geometry
122
+ });
123
+ }
124
+ subscribe(listener) {
125
+ this.listeners.add(listener);
126
+ if (this.config) listener(this.config);
127
+ return () => this.listeners.delete(listener);
128
+ }
129
+ async pointer(input) {
130
+ const { width, height, version } = this.geometry;
131
+ if (!width || input.geometry !== version) throw new PhoneError("PHONE_GEOMETRY_CHANGED", "Phone geometry changed; start a new gesture", 409);
132
+ if (input.phase === "down" ? Boolean(this.touch) : !this.touch) throw new PhoneError("PHONE_POINTER_SEQUENCE", "Invalid pointer sequence", 409);
133
+ await this.write(scrcpyTouch(input.phase, input.x, input.y, width, height));
134
+ this.touch = input.phase === "up" || input.phase === "cancel" ? void 0 : {
135
+ x: input.x,
136
+ y: input.y
137
+ };
138
+ }
139
+ async revoke() {
140
+ if (!this.touch) return;
141
+ const point = this.touch;
142
+ this.touch = void 0;
143
+ await this.write(scrcpyTouch("cancel", point.x, point.y, this.geometry.width, this.geometry.height));
144
+ }
145
+ fail() {
146
+ if (this.closing) return;
147
+ this.onFailure();
148
+ this.close();
149
+ }
150
+ refresh() {
151
+ if (this.geometry.version) this.write(Buffer.from([17])).catch(() => this.fail());
152
+ }
153
+ close() {
154
+ this.closing = true;
155
+ return this.closeResult ??= (async () => {
156
+ await this.opening?.catch(() => {});
157
+ try {
158
+ await this.cleanup();
159
+ } finally {
160
+ this.listeners.clear();
161
+ this.config = void 0;
162
+ }
163
+ })();
164
+ }
165
+ };
166
+ var LocalScrcpyProvider = class extends ScrcpyProvider {
167
+ process;
168
+ video;
169
+ control;
170
+ port;
171
+ remote = "";
172
+ scid = "";
173
+ constructor(adb, serial, onFailure, tuning = {
174
+ maxSize: 960,
175
+ bitRate: 2e6
176
+ }) {
177
+ super(onFailure);
178
+ this.adb = adb;
179
+ this.serial = serial;
180
+ this.tuning = tuning;
181
+ }
182
+ foreground(signal) {
183
+ return new AdbPhoneDriver(this.adb).foreground(this.serial, signal);
184
+ }
185
+ async startTransport() {
186
+ await readScrcpyServer();
187
+ const scid = randomBytes(4).readUInt32BE() & 2147483647;
188
+ this.scid = scid.toString(16);
189
+ const socketName = `scrcpy_${scid.toString(16).padStart(8, "0")}`;
190
+ this.remote = `/data/local/tmp/xopc-scrcpy-${socketName}.jar`;
191
+ try {
192
+ await runAdb(this.adb, [
193
+ "-s",
194
+ this.serial,
195
+ "push",
196
+ scrcpyServerPath(),
197
+ this.remote
198
+ ]);
199
+ if (this.closing) throw new Error("Video closed");
200
+ this.port = (await runAdb(this.adb, [
201
+ "-s",
202
+ this.serial,
203
+ "forward",
204
+ "tcp:0",
205
+ `localabstract:${socketName}`
206
+ ])).toString().trim();
207
+ if (!/^\d+$/.test(this.port)) throw new Error("Invalid ADB forwarding port");
208
+ if (this.closing) throw new Error("Video closed");
209
+ this.process = spawnPhoneCommand(this.adb, [
210
+ "-s",
211
+ this.serial,
212
+ "shell",
213
+ `CLASSPATH=${this.remote}`,
214
+ "app_process",
215
+ "/",
216
+ "com.genymobile.scrcpy.Server",
217
+ SCRCPY_VERSION,
218
+ `scid=${scid.toString(16)}`,
219
+ "tunnel_forward=true",
220
+ "audio=false",
221
+ "control=true",
222
+ "cleanup=false",
223
+ `max_size=${this.tuning.maxSize}`,
224
+ "max_fps=30",
225
+ `video_bit_rate=${this.tuning.bitRate}`,
226
+ "video_codec=h264",
227
+ "video_codec_options=i-frame-interval=1",
228
+ "send_dummy_byte=true",
229
+ "send_device_meta=false",
230
+ "send_codec_meta=true",
231
+ "send_frame_meta=true",
232
+ "clipboard_autosync=false"
233
+ ]);
234
+ this.process.once("error", () => this.fail());
235
+ this.process.once("exit", () => this.fail());
236
+ for (let attempt = 0; attempt < 60; attempt++) {
237
+ if (this.closing) throw new Error("Video closed");
238
+ const socket = connect({
239
+ host: "127.0.0.1",
240
+ port: Number(this.port)
241
+ });
242
+ if (await new Promise((resolve) => {
243
+ const timer = setTimeout(() => {
244
+ socket.destroy();
245
+ resolve(false);
246
+ }, 250);
247
+ socket.once("error", () => {
248
+ clearTimeout(timer);
249
+ resolve(false);
250
+ });
251
+ socket.once("end", () => {
252
+ clearTimeout(timer);
253
+ resolve(false);
254
+ });
255
+ socket.once("data", (data) => {
256
+ clearTimeout(timer);
257
+ if (data.length !== 1 || data[0] !== 0) {
258
+ socket.destroy();
259
+ resolve(false);
260
+ } else resolve(true);
261
+ });
262
+ })) {
263
+ this.video = socket;
264
+ break;
265
+ }
266
+ socket.destroy();
267
+ await setTimeout$1(50);
268
+ }
269
+ if (!this.video) throw new Error("Scrcpy connection timed out");
270
+ const parser = new ScrcpyVideoParser();
271
+ this.video.on("data", (data) => {
272
+ try {
273
+ parser.push(Buffer.from(data), (packet) => this.packet(packet));
274
+ } catch {
275
+ this.fail();
276
+ }
277
+ });
278
+ this.video.on("error", () => this.fail());
279
+ this.video.on("end", () => this.fail());
280
+ this.control = connect({
281
+ host: "127.0.0.1",
282
+ port: Number(this.port)
283
+ });
284
+ this.control.setNoDelay(true);
285
+ this.control.on("error", () => this.fail());
286
+ this.control.on("end", () => this.fail());
287
+ this.control.on("data", () => {});
288
+ await new Promise((resolve, reject) => {
289
+ this.control.once("connect", resolve);
290
+ this.control.once("error", reject);
291
+ });
292
+ } catch (error) {
293
+ throw error;
294
+ }
295
+ }
296
+ async write(buffer) {
297
+ if (!this.control || this.control.destroyed || this.control.writableLength > 64 * 1024) throw new PhoneError("PHONE_INPUT_DISCONNECTED", "Phone input channel unavailable");
298
+ await new Promise((resolve, reject) => this.control.write(buffer, (error) => error ? reject(error) : resolve()));
299
+ }
300
+ async cleanup() {
301
+ await this.revoke().catch(() => {});
302
+ this.video?.destroy();
303
+ this.control?.destroy();
304
+ this.process?.kill();
305
+ if (this.scid) {
306
+ const processes = await runAdb(this.adb, [
307
+ "-s",
308
+ this.serial,
309
+ "shell",
310
+ "ps",
311
+ "-A",
312
+ "-o",
313
+ "PID,ARGS"
314
+ ]).catch(() => Buffer.alloc(0));
315
+ for (const line of processes.toString().split("\n")) {
316
+ const pid = /^\s*(\d+)\s+/.exec(line)?.[1];
317
+ if (pid && line.includes("com.genymobile.scrcpy.Server ") && new RegExp(`(?:^|\\s)scid=${this.scid}(?:\\s|$)`).test(line)) await runAdb(this.adb, [
318
+ "-s",
319
+ this.serial,
320
+ "shell",
321
+ "kill",
322
+ "-TERM",
323
+ pid
324
+ ]).catch(() => {});
325
+ }
326
+ }
327
+ if (this.port) await runAdb(this.adb, [
328
+ "-s",
329
+ this.serial,
330
+ "forward",
331
+ "--remove",
332
+ `tcp:${this.port}`
333
+ ]).catch(() => {});
334
+ if (this.remote) await runAdb(this.adb, [
335
+ "-s",
336
+ this.serial,
337
+ "shell",
338
+ "rm",
339
+ "-f",
340
+ this.remote
341
+ ]).catch(() => {});
342
+ }
343
+ };
344
+ //#endregion
345
+ export { LocalScrcpyProvider, SCRCPY_SHA256, SCRCPY_VERSION, ScrcpyProvider, ScrcpyVideoParser, readScrcpyServer, scrcpyServerPath, scrcpyTouch };
@@ -0,0 +1,26 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { Socket } from 'node:net';
3
+ import type { PhoneInteractiveSession } from './interactive-session.js';
4
+ type Claim = {
5
+ origin: string;
6
+ principal: string;
7
+ expiresAt: number;
8
+ client: string;
9
+ connect: () => Promise<PhoneInteractiveSession>;
10
+ validate: () => Promise<void>;
11
+ disconnect: () => Promise<void>;
12
+ };
13
+ export declare class PhoneStreamGateway {
14
+ private principalActive;
15
+ private tickets;
16
+ private wss;
17
+ constructor(principalActive?: (principal: string) => boolean);
18
+ issue(claim: Omit<Claim, 'expiresAt'>): {
19
+ ticket: string;
20
+ path: string;
21
+ };
22
+ handleUpgrade(req: IncomingMessage, socket: Socket, head: Buffer): boolean;
23
+ private connection;
24
+ close(): void;
25
+ }
26
+ export {};
@@ -0,0 +1,210 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
3
+ import { PhoneError, init_contracts } from "./contracts.js";
4
+ import { PhonePointerSchema } from "./live-provider.js";
5
+ import { createRequire } from "node:module";
6
+ import { createHash, randomBytes } from "node:crypto";
7
+ import { z } from "zod";
8
+ //#region src/phone/stream-gateway.ts
9
+ init_contracts();
10
+ init_logger();
11
+ const log = createLogger("PhoneStream");
12
+ const { WebSocketServer } = createRequire(import.meta.url)("ws");
13
+ const hash = (value) => createHash("sha256").update(value).digest("hex");
14
+ const releaseSchema = z.object({
15
+ type: z.literal("cancelPointers"),
16
+ epoch: z.number().int().positive()
17
+ }).strict();
18
+ var PhoneStreamGateway = class {
19
+ tickets = /* @__PURE__ */ new Map();
20
+ wss = new WebSocketServer({
21
+ noServer: true,
22
+ maxPayload: 16 * 1024,
23
+ perMessageDeflate: false,
24
+ handleProtocols: (protocols) => protocols.has("xopc-phone-v1") ? "xopc-phone-v1" : false
25
+ });
26
+ constructor(principalActive = () => true) {
27
+ this.principalActive = principalActive;
28
+ }
29
+ issue(claim) {
30
+ for (const [key, value] of this.tickets) if (value.expiresAt < Date.now()) this.tickets.delete(key);
31
+ if (this.tickets.size >= 100) throw new PhoneError("PHONE_VIEW_BUSY", "Too many pending phone viewers", 409);
32
+ const ticket = randomBytes(32).toString("base64url");
33
+ this.tickets.set(hash(ticket), {
34
+ ...claim,
35
+ expiresAt: Date.now() + 3e4
36
+ });
37
+ return {
38
+ ticket,
39
+ path: "/api/phone/live/v1/ws"
40
+ };
41
+ }
42
+ handleUpgrade(req, socket, head) {
43
+ if (new URL(req.url ?? "/", "http://gateway.local").pathname !== "/api/phone/live/v1/ws") return false;
44
+ const protocols = (req.headers["sec-websocket-protocol"] ?? "").split(",").map((value) => value.trim());
45
+ const key = hash(protocols.find((value) => /^[\w-]{43}$/.test(value)) ?? "");
46
+ const claim = this.tickets.get(key);
47
+ this.tickets.delete(key);
48
+ if (!protocols.includes("xopc-phone-v1") || !claim || claim.expiresAt < Date.now() || req.headers.origin !== claim.origin || !this.principalActive(claim.principal) || this.wss.clients.size >= 16) {
49
+ socket.destroy();
50
+ return true;
51
+ }
52
+ this.wss.handleUpgrade(req, socket, head, (ws) => {
53
+ this.connection(ws, claim);
54
+ });
55
+ return true;
56
+ }
57
+ async connection(ws, claim) {
58
+ let stream;
59
+ let unsubscribe;
60
+ let disposed = false;
61
+ let validating = false;
62
+ let lastSeen = Date.now();
63
+ let lastFault = "";
64
+ let packets = 0;
65
+ let windowAt = Date.now();
66
+ let events = 0;
67
+ const send = (body) => {
68
+ if (ws.readyState === ws.OPEN) ws.send(JSON.stringify(body));
69
+ };
70
+ const fail = (code) => {
71
+ if (code !== lastFault) send({
72
+ type: "fault",
73
+ code
74
+ });
75
+ lastFault = code;
76
+ };
77
+ const timer = setInterval(() => {
78
+ if (disposed) return;
79
+ if (!this.principalActive(claim.principal) || Date.now() - lastSeen > 12e3) {
80
+ ws.close(4401, "Viewer expired");
81
+ return;
82
+ }
83
+ if (ws.readyState === ws.OPEN) ws.ping();
84
+ if (!validating) {
85
+ validating = true;
86
+ claim.validate().catch(() => ws.close(4403, "Phone access changed")).finally(() => {
87
+ validating = false;
88
+ });
89
+ }
90
+ }, 2e3);
91
+ const cleanup = async () => {
92
+ if (disposed) return;
93
+ disposed = true;
94
+ clearInterval(timer);
95
+ unsubscribe?.();
96
+ await claim.disconnect().catch(() => {});
97
+ };
98
+ ws.on("error", () => ws.terminate());
99
+ ws.once("close", () => {
100
+ cleanup();
101
+ });
102
+ ws.on("pong", () => {
103
+ lastSeen = Date.now();
104
+ });
105
+ ws.on("message", (bytes, binary) => {
106
+ try {
107
+ if (binary) throw new Error("Unexpected binary input");
108
+ const input = JSON.parse(bytes.toString());
109
+ if (input.type === "ping") {
110
+ lastSeen = Date.now();
111
+ send({ type: "pong" });
112
+ return;
113
+ }
114
+ if (!stream || disposed) throw new Error("Phone video not ready");
115
+ const cancel = releaseSchema.safeParse(input);
116
+ if (cancel.success) {
117
+ stream.authorizeClient(claim.client, cancel.data.epoch);
118
+ stream.revoke().catch(() => ws.close(4411, "Touch release failed"));
119
+ return;
120
+ }
121
+ const pointer = PhonePointerSchema.parse(input);
122
+ if (Date.now() - windowAt > 1e3) {
123
+ windowAt = Date.now();
124
+ events = 0;
125
+ }
126
+ if (++events > 120) throw new Error("Input rate exceeded");
127
+ lastSeen = Date.now();
128
+ const startedAt = performance.now();
129
+ stream.input(claim.client, pointer).then(() => send({
130
+ type: "ack",
131
+ seq: pointer.seq,
132
+ phase: "transport-written",
133
+ durationMs: performance.now() - startedAt
134
+ }), (error) => {
135
+ const code = error instanceof PhoneError ? error.code : "PHONE_INPUT_FAILED";
136
+ log.warn({
137
+ phase: "input_dispatch",
138
+ errorCode: code
139
+ }, "Phone input channel closed after refused input");
140
+ fail(code);
141
+ ws.close(4409, "Input rejected");
142
+ });
143
+ } catch (error) {
144
+ const code = error instanceof PhoneError ? error.code : "PHONE_INVALID_INPUT";
145
+ log.info({
146
+ phase: "input_validation",
147
+ errorCode: code,
148
+ issues: error instanceof z.ZodError ? error.issues.map((issue) => ({
149
+ path: issue.path.join("."),
150
+ code: issue.code
151
+ })) : void 0
152
+ }, "Phone input refused");
153
+ fail(code);
154
+ ws.close(4400, "Invalid input");
155
+ }
156
+ });
157
+ try {
158
+ await claim.validate();
159
+ stream = await claim.connect();
160
+ if (disposed || ws.readyState !== ws.OPEN) {
161
+ await claim.disconnect();
162
+ return;
163
+ }
164
+ send({
165
+ type: "ready",
166
+ descriptor: stream.provider.descriptor
167
+ });
168
+ unsubscribe = stream.subscribe(claim.client, (packet) => {
169
+ if (ws.readyState !== ws.OPEN) return;
170
+ if (ws.bufferedAmount > 1024 * 1024) {
171
+ ws.close(4408, "Video consumer too slow");
172
+ return;
173
+ }
174
+ const geometry = packet.geometry ?? stream.provider.geometry;
175
+ if (packet.config) send({
176
+ type: "geometry",
177
+ ...geometry
178
+ });
179
+ const header = Buffer.alloc(32);
180
+ header[0] = (packet.config ? 1 : 0) | (packet.key ? 2 : 0);
181
+ header.writeUInt32BE(geometry.version, 4);
182
+ header.writeUInt16BE(geometry.width, 8);
183
+ header.writeUInt16BE(geometry.height, 10);
184
+ header.writeBigUInt64BE(BigInt(packet.pts), 12);
185
+ header.writeDoubleBE(Date.now(), 20);
186
+ header.writeUInt32BE(++packets, 28);
187
+ lastFault = "";
188
+ ws.send(Buffer.concat([header, packet.data]));
189
+ }, (code) => {
190
+ fail(code);
191
+ if (code === "PHONE_VIDEO_ENDED") ws.close(1e3, "Phone session ended");
192
+ });
193
+ } catch (error) {
194
+ const code = error instanceof PhoneError ? error.code : "PHONE_VIDEO_FAILED";
195
+ fail(code);
196
+ log.info({
197
+ phase: "stream_start",
198
+ errorCode: code
199
+ }, "Phone video unavailable");
200
+ ws.close(4411, "Phone video unavailable");
201
+ }
202
+ }
203
+ close() {
204
+ this.tickets.clear();
205
+ for (const ws of this.wss.clients) ws.terminate();
206
+ this.wss.close();
207
+ }
208
+ };
209
+ //#endregion
210
+ export { PhoneStreamGateway };
@@ -0,0 +1,4 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ export declare function runPhoneCommandBuffer(program: string, args: string[], signal?: AbortSignal, timeoutMs?: number): Promise<Buffer>;
3
+ export declare function runPhoneCommandText(program: string, args: string[], signal: AbortSignal): Promise<string>;
4
+ export declare function spawnPhoneCommand(program: string, args: string[]): ChildProcess;
@@ -0,0 +1,38 @@
1
+ import { execFile, spawn } from "node:child_process";
2
+ //#region src/process/phone-process.ts
3
+ function runPhoneCommandBuffer(program, args, signal, timeoutMs = 15e3) {
4
+ signal?.throwIfAborted();
5
+ return new Promise((resolve, reject) => {
6
+ execFile(program, args, {
7
+ encoding: "buffer",
8
+ maxBuffer: 16 * 1024 * 1024,
9
+ timeout: timeoutMs,
10
+ signal,
11
+ windowsHide: true
12
+ }, (error, stdout) => error ? reject(error) : resolve(stdout));
13
+ });
14
+ }
15
+ function runPhoneCommandText(program, args, signal) {
16
+ signal.throwIfAborted();
17
+ return new Promise((resolve, reject) => {
18
+ execFile(program, args, {
19
+ encoding: "utf8",
20
+ maxBuffer: 1024 * 1024,
21
+ timeout: 1e4,
22
+ signal,
23
+ windowsHide: true
24
+ }, (error, stdout) => error ? reject(error) : resolve(stdout));
25
+ });
26
+ }
27
+ function spawnPhoneCommand(program, args) {
28
+ return spawn(program, args, {
29
+ stdio: [
30
+ "ignore",
31
+ "ignore",
32
+ "ignore"
33
+ ],
34
+ windowsHide: true
35
+ });
36
+ }
37
+ //#endregion
38
+ export { runPhoneCommandBuffer, runPhoneCommandText, spawnPhoneCommand };