@hienlh/ppm 0.23.11 → 0.23.12

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 (641) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/CLAUDE.md +13 -2
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/cli-reference.md +4 -4
  5. package/assets/skills/ppm/references/http-api.md +37 -1
  6. package/bun.lock +34 -0
  7. package/dist/web/assets/accounts-settings-section-CGe5ikvs.js +1 -0
  8. package/dist/web/assets/accounts-settings-section-CGe5ikvs.js.br +0 -0
  9. package/dist/web/assets/accounts-settings-section-CGe5ikvs.js.gz +0 -0
  10. package/dist/web/assets/{agent-session-sheet-CBMsnl_p.js → agent-session-sheet-vBhfHYrC.js} +2 -2
  11. package/dist/web/assets/agent-session-sheet-vBhfHYrC.js.br +0 -0
  12. package/dist/web/assets/agent-session-sheet-vBhfHYrC.js.gz +0 -0
  13. package/dist/web/assets/{agent-session-window-content-D9C9FA7E.js → agent-session-window-content-BxIxDN5i.js} +1 -1
  14. package/dist/web/assets/agent-session-window-content-BxIxDN5i.js.br +0 -0
  15. package/dist/web/assets/agent-session-window-content-BxIxDN5i.js.gz +0 -0
  16. package/dist/web/assets/{ai-resource-editor-DhUVgDEG.js → ai-resource-editor-Y8clBPRv.js} +1 -1
  17. package/dist/web/assets/ai-resource-editor-Y8clBPRv.js.br +0 -0
  18. package/dist/web/assets/ai-resource-editor-Y8clBPRv.js.gz +0 -0
  19. package/dist/web/assets/{ai-settings-section-DOckWvp4.js → ai-settings-section-BB8vscte.js} +1 -1
  20. package/dist/web/assets/{ai-settings-section-CETpSpYd.js → ai-settings-section-Ck8uN_Bw.js} +1 -1
  21. package/dist/web/assets/ai-settings-section-Ck8uN_Bw.js.br +0 -0
  22. package/dist/web/assets/ai-settings-section-Ck8uN_Bw.js.gz +0 -0
  23. package/dist/web/assets/android-tab-BIOUVVoW.js +2 -0
  24. package/dist/web/assets/android-tab-BIOUVVoW.js.br +0 -0
  25. package/dist/web/assets/android-tab-BIOUVVoW.js.gz +0 -0
  26. package/dist/web/assets/{api-settings-JIgKfcCx.js → api-settings-D1axn9vm.js} +1 -1
  27. package/dist/web/assets/{appearance-settings-section-BJUiLUb7.js → appearance-settings-section-Bv5_n9lH.js} +1 -1
  28. package/dist/web/assets/appearance-settings-section-Bv5_n9lH.js.br +0 -0
  29. package/dist/web/assets/appearance-settings-section-Bv5_n9lH.js.gz +0 -0
  30. package/dist/web/assets/{apps-panel-1VElRgV3.js → apps-panel-DXHF0QEv.js} +1 -1
  31. package/dist/web/assets/apps-panel-DXHF0QEv.js.br +0 -0
  32. package/dist/web/assets/apps-panel-DXHF0QEv.js.gz +0 -0
  33. package/dist/web/assets/{audio-preview-DYkyHu5X.js → audio-preview-DpjOKEm4.js} +1 -1
  34. package/dist/web/assets/audio-preview-DpjOKEm4.js.br +0 -0
  35. package/dist/web/assets/audio-preview-DpjOKEm4.js.gz +0 -0
  36. package/dist/web/assets/branch-review-tab-4dgMNadQ.js +1 -0
  37. package/dist/web/assets/branch-review-tab-4dgMNadQ.js.br +0 -0
  38. package/dist/web/assets/branch-review-tab-4dgMNadQ.js.gz +0 -0
  39. package/dist/web/assets/chat-tab-Bbe_77oJ.js +15 -0
  40. package/dist/web/assets/chat-tab-Bbe_77oJ.js.br +0 -0
  41. package/dist/web/assets/chat-tab-Bbe_77oJ.js.gz +0 -0
  42. package/dist/web/assets/chat-tab-D3i5O3dO.js +1 -0
  43. package/dist/web/assets/chat-tab-D3i5O3dO.js.br +0 -0
  44. package/dist/web/assets/chat-tab-D3i5O3dO.js.gz +0 -0
  45. package/dist/web/assets/code-editor-DXsIWoQ1.js +7 -0
  46. package/dist/web/assets/code-editor-DXsIWoQ1.js.br +0 -0
  47. package/dist/web/assets/code-editor-DXsIWoQ1.js.gz +0 -0
  48. package/dist/web/assets/{codex-reset-credit-button-Fr45FUxi.js → codex-reset-credit-button-DRhievFQ.js} +1 -1
  49. package/dist/web/assets/codex-reset-credit-button-DRhievFQ.js.br +0 -0
  50. package/dist/web/assets/codex-reset-credit-button-DRhievFQ.js.gz +0 -0
  51. package/dist/web/assets/{conflict-editor-B-wdjSXI.js → conflict-editor-D_RImo_V.js} +3 -3
  52. package/dist/web/assets/conflict-editor-D_RImo_V.js.br +0 -0
  53. package/dist/web/assets/conflict-editor-D_RImo_V.js.gz +0 -0
  54. package/dist/web/assets/{csv-preview-B6RodObB.js → csv-preview-BuFdfLo3.js} +1 -1
  55. package/dist/web/assets/csv-preview-BuFdfLo3.js.br +0 -0
  56. package/dist/web/assets/csv-preview-BuFdfLo3.js.gz +0 -0
  57. package/dist/web/assets/{database-viewer-CdPBUQPY.js → database-viewer-ChcbYn9E.js} +1 -1
  58. package/dist/web/assets/database-viewer-ChcbYn9E.js.br +0 -0
  59. package/dist/web/assets/database-viewer-ChcbYn9E.js.gz +0 -0
  60. package/dist/web/assets/{design-settings-section-BpCpaBwL.js → design-settings-section-B_xOf51h.js} +1 -1
  61. package/dist/web/assets/design-settings-section-B_xOf51h.js.br +0 -0
  62. package/dist/web/assets/design-settings-section-B_xOf51h.js.gz +0 -0
  63. package/dist/web/assets/{design-skill-suggestion-DkT2E2IV.js → design-skill-suggestion-BbEDg15Z.js} +1 -1
  64. package/dist/web/assets/design-skill-suggestion-BbEDg15Z.js.br +0 -0
  65. package/dist/web/assets/design-skill-suggestion-BbEDg15Z.js.gz +0 -0
  66. package/dist/web/assets/{design-tab-BZb9eemI.js → design-tab-BQSYJ4cS.js} +6 -6
  67. package/dist/web/assets/design-tab-BQSYJ4cS.js.br +0 -0
  68. package/dist/web/assets/design-tab-BQSYJ4cS.js.gz +0 -0
  69. package/dist/web/assets/{designs-sidebar-panel-CF4tp6j-.js → designs-sidebar-panel-AiPaYfSU.js} +1 -1
  70. package/dist/web/assets/designs-sidebar-panel-AiPaYfSU.js.br +0 -0
  71. package/dist/web/assets/designs-sidebar-panel-AiPaYfSU.js.gz +0 -0
  72. package/dist/web/assets/{diff-viewer-BqEqwSw6.js → diff-viewer-BZ6glGK-.js} +1 -1
  73. package/dist/web/assets/diff-viewer-BZ6glGK-.js.br +0 -0
  74. package/dist/web/assets/diff-viewer-BZ6glGK-.js.gz +0 -0
  75. package/dist/web/assets/{edit-diff-preview-DD4HayXY.js → edit-diff-preview-D-FNLOU2.js} +1 -1
  76. package/dist/web/assets/edit-diff-preview-D-FNLOU2.js.br +0 -0
  77. package/dist/web/assets/edit-diff-preview-D-FNLOU2.js.gz +0 -0
  78. package/dist/web/assets/{editor-language-service-CkA5sEdV.js → editor-language-service-4sbsdqBV.js} +1 -1
  79. package/dist/web/assets/editor-language-service-4sbsdqBV.js.br +0 -0
  80. package/dist/web/assets/editor-language-service-4sbsdqBV.js.gz +0 -0
  81. package/dist/web/assets/explorer-body-DbgrG1fe.js +2 -0
  82. package/dist/web/assets/explorer-body-DbgrG1fe.js.br +0 -0
  83. package/dist/web/assets/explorer-body-DbgrG1fe.js.gz +0 -0
  84. package/dist/web/assets/{explorer-window-content-CRJ2eMZ4.js → explorer-window-content-BCjWvHpp.js} +1 -1
  85. package/dist/web/assets/explorer-window-content-BCjWvHpp.js.br +0 -0
  86. package/dist/web/assets/explorer-window-content-BCjWvHpp.js.gz +0 -0
  87. package/dist/web/assets/{extension-manager-section-DwQTdCII.js → extension-manager-section-DiMF4RnT.js} +1 -1
  88. package/dist/web/assets/extension-manager-section-DiMF4RnT.js.br +0 -0
  89. package/dist/web/assets/extension-manager-section-DiMF4RnT.js.gz +0 -0
  90. package/dist/web/assets/{extension-webview-CMq-VTLu.js → extension-webview-Coti6Vfw.js} +1 -1
  91. package/dist/web/assets/extension-webview-Coti6Vfw.js.br +0 -0
  92. package/dist/web/assets/extension-webview-Coti6Vfw.js.gz +0 -0
  93. package/dist/web/assets/file-store-Cm7-pHux.js +1 -0
  94. package/dist/web/assets/file-store-Cm7-pHux.js.br +0 -0
  95. package/dist/web/assets/file-store-Cm7-pHux.js.gz +0 -0
  96. package/dist/web/assets/{files-settings-section-B2lcyh-6.js → files-settings-section-ZTVwOwx0.js} +1 -1
  97. package/dist/web/assets/files-settings-section-ZTVwOwx0.js.br +0 -0
  98. package/dist/web/assets/files-settings-section-ZTVwOwx0.js.gz +0 -0
  99. package/dist/web/assets/{general-settings-section-Doepm2sH.js → general-settings-section-B7Hjx_fb.js} +1 -1
  100. package/dist/web/assets/general-settings-section-B7Hjx_fb.js.br +0 -0
  101. package/dist/web/assets/general-settings-section-B7Hjx_fb.js.gz +0 -0
  102. package/dist/web/assets/{git-log-panel-CJakNMDc.js → git-log-panel-CbcJ_YEH.js} +1 -1
  103. package/dist/web/assets/git-log-panel-CbcJ_YEH.js.br +0 -0
  104. package/dist/web/assets/git-log-panel-CbcJ_YEH.js.gz +0 -0
  105. package/dist/web/assets/{glide-data-grid-C_SeOhSq.js → glide-data-grid-BfByGSf1.js} +3 -3
  106. package/dist/web/assets/glide-data-grid-BfByGSf1.js.br +0 -0
  107. package/dist/web/assets/glide-data-grid-BfByGSf1.js.gz +0 -0
  108. package/dist/web/assets/group-chat-tab-DCo9OP3D.js +1 -0
  109. package/dist/web/assets/group-chat-tab-DCo9OP3D.js.br +0 -0
  110. package/dist/web/assets/group-chat-tab-DCo9OP3D.js.gz +0 -0
  111. package/dist/web/assets/{image-preview-C1Frlx22.js → image-preview-Cjlps7Pt.js} +1 -1
  112. package/dist/web/assets/index-CyDLBddf.js +52 -0
  113. package/dist/web/assets/index-CyDLBddf.js.br +0 -0
  114. package/dist/web/assets/index-CyDLBddf.js.gz +0 -0
  115. package/dist/web/assets/index-Dh5apC3I.css +1 -0
  116. package/dist/web/assets/index-Dh5apC3I.css.br +0 -0
  117. package/dist/web/assets/index-Dh5apC3I.css.gz +0 -0
  118. package/dist/web/assets/{jira-watcher-section-BmkIGQFV.js → jira-watcher-section-Dz_-sUC2.js} +1 -1
  119. package/dist/web/assets/keybindings-store-BTq5Z7XP.js +1 -0
  120. package/dist/web/assets/{keyboard-shortcuts-section-BgZe3QDr.js → keyboard-shortcuts-section-Ba5NYwlG.js} +1 -1
  121. package/dist/web/assets/keyboard-shortcuts-section-Ba5NYwlG.js.br +0 -0
  122. package/dist/web/assets/keyboard-shortcuts-section-Ba5NYwlG.js.gz +0 -0
  123. package/dist/web/assets/{language-servers-section-CCMzgOaE.js → language-servers-section-DJJ7SFXo.js} +2 -2
  124. package/dist/web/assets/language-servers-section-DJJ7SFXo.js.br +0 -0
  125. package/dist/web/assets/language-servers-section-DJJ7SFXo.js.gz +0 -0
  126. package/dist/web/assets/{lsp-client-B10suuaZ.js → lsp-client-Dr3vQ1bb.js} +1 -1
  127. package/dist/web/assets/lsp-client-Dr3vQ1bb.js.br +0 -0
  128. package/dist/web/assets/lsp-client-Dr3vQ1bb.js.gz +0 -0
  129. package/dist/web/assets/{markdown-renderer-AHHFS3jc.js → markdown-renderer-CmnqFfTU.js} +3 -3
  130. package/dist/web/assets/markdown-renderer-CmnqFfTU.js.br +0 -0
  131. package/dist/web/assets/markdown-renderer-CmnqFfTU.js.gz +0 -0
  132. package/dist/web/assets/markdown-renderer-LJdVMbGl.js +1 -0
  133. package/dist/web/assets/{mobile-explorer-sheet-CqCsLWSr.js → mobile-explorer-sheet-BiIhZtJ2.js} +1 -1
  134. package/dist/web/assets/mobile-explorer-sheet-BiIhZtJ2.js.br +0 -0
  135. package/dist/web/assets/mobile-explorer-sheet-BiIhZtJ2.js.gz +0 -0
  136. package/dist/web/assets/new-design-dialog-DI_hxvFV.js +1 -0
  137. package/dist/web/assets/new-design-dialog-DI_hxvFV.js.br +0 -0
  138. package/dist/web/assets/new-design-dialog-DI_hxvFV.js.gz +0 -0
  139. package/dist/web/assets/notification-store-9lBSplOV.js +1 -0
  140. package/dist/web/assets/{notifications-settings-section-CXgzH_bK.js → notifications-settings-section-0s-2OKRv.js} +1 -1
  141. package/dist/web/assets/notifications-settings-section-0s-2OKRv.js.br +0 -0
  142. package/dist/web/assets/notifications-settings-section-0s-2OKRv.js.gz +0 -0
  143. package/dist/web/assets/{overview-panel-BYB8mgRE.js → overview-panel-3htxfZS2.js} +1 -1
  144. package/dist/web/assets/overview-panel-3htxfZS2.js.br +0 -0
  145. package/dist/web/assets/overview-panel-3htxfZS2.js.gz +0 -0
  146. package/dist/web/assets/panel-store-B6PoCwBA.js +1 -0
  147. package/dist/web/assets/panel-store-B6PoCwBA.js.br +0 -0
  148. package/dist/web/assets/panel-store-B6PoCwBA.js.gz +0 -0
  149. package/dist/web/assets/{performance-panel-Dpuq3g0W.js → performance-panel-V8gpnnf7.js} +2 -2
  150. package/dist/web/assets/performance-panel-V8gpnnf7.js.br +0 -0
  151. package/dist/web/assets/performance-panel-V8gpnnf7.js.gz +0 -0
  152. package/dist/web/assets/{postgres-viewer-DW0Gkmow.js → postgres-viewer-sWS-ogTC.js} +1 -1
  153. package/dist/web/assets/postgres-viewer-sWS-ogTC.js.br +0 -0
  154. package/dist/web/assets/postgres-viewer-sWS-ogTC.js.gz +0 -0
  155. package/dist/web/assets/{ppmbot-settings-section-DFtlGoW6.js → ppmbot-settings-section-CT8vvlzk.js} +1 -1
  156. package/dist/web/assets/ppmbot-settings-section-CT8vvlzk.js.br +0 -0
  157. package/dist/web/assets/ppmbot-settings-section-CT8vvlzk.js.gz +0 -0
  158. package/dist/web/assets/{pptx-export-CNyG32Xr.js → pptx-export-Ugjv0hso.js} +4 -4
  159. package/dist/web/assets/pptx-export-Ugjv0hso.js.br +0 -0
  160. package/dist/web/assets/pptx-export-Ugjv0hso.js.gz +0 -0
  161. package/dist/web/assets/{problems-panel-V5zqpuXq.js → problems-panel-Gcy79pSS.js} +1 -1
  162. package/dist/web/assets/problems-panel-Gcy79pSS.js.br +0 -0
  163. package/dist/web/assets/problems-panel-Gcy79pSS.js.gz +0 -0
  164. package/dist/web/assets/{process-row-format-CiJJSf_V.js → process-row-format-u6y7lOee.js} +1 -1
  165. package/dist/web/assets/process-table-BUTIp9Oy.js +1 -0
  166. package/dist/web/assets/process-table-BUTIp9Oy.js.br +0 -0
  167. package/dist/web/assets/process-table-BUTIp9Oy.js.gz +0 -0
  168. package/dist/web/assets/{proxy-settings-section-B7AVlTfY.js → proxy-settings-section-Buv_8y54.js} +1 -1
  169. package/dist/web/assets/proxy-settings-section-Buv_8y54.js.br +0 -0
  170. package/dist/web/assets/proxy-settings-section-Buv_8y54.js.gz +0 -0
  171. package/dist/web/assets/{query-audit-section-gHmRfWKr.js → query-audit-section-N2DQtgJx.js} +1 -1
  172. package/dist/web/assets/query-audit-section-N2DQtgJx.js.br +0 -0
  173. package/dist/web/assets/query-audit-section-N2DQtgJx.js.gz +0 -0
  174. package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js +1 -0
  175. package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js.br +0 -0
  176. package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js.gz +0 -0
  177. package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js +2 -0
  178. package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js.br +0 -0
  179. package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js.gz +0 -0
  180. package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js +1 -0
  181. package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js.br +0 -0
  182. package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js.gz +0 -0
  183. package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js +1 -0
  184. package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js.br +0 -0
  185. package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js.gz +0 -0
  186. package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js +1 -0
  187. package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js.br +0 -0
  188. package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js.gz +0 -0
  189. package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js +1 -0
  190. package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js.br +0 -0
  191. package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js.gz +0 -0
  192. package/dist/web/assets/{run-in-terminal-DKBcEGVu.js → run-in-terminal-DCBNtYHQ.js} +1 -1
  193. package/dist/web/assets/{schedules-settings-section-sYDAsBMO.js → schedules-settings-section-_cHX2qOa.js} +1 -1
  194. package/dist/web/assets/schedules-settings-section-_cHX2qOa.js.br +0 -0
  195. package/dist/web/assets/schedules-settings-section-_cHX2qOa.js.gz +0 -0
  196. package/dist/web/assets/{send-to-chat-CCdOrKc7.js → send-to-chat-dNqNV7Y4.js} +1 -1
  197. package/dist/web/assets/send-to-chat-dNqNV7Y4.js.br +0 -0
  198. package/dist/web/assets/send-to-chat-dNqNV7Y4.js.gz +0 -0
  199. package/dist/web/assets/{services-panel-CKa2aP1d.js → services-panel-Dm54cnW3.js} +1 -1
  200. package/dist/web/assets/services-panel-Dm54cnW3.js.br +0 -0
  201. package/dist/web/assets/services-panel-Dm54cnW3.js.gz +0 -0
  202. package/dist/web/assets/settings-body-DRRQNaDA.js +1 -0
  203. package/dist/web/assets/settings-body-DRRQNaDA.js.br +0 -0
  204. package/dist/web/assets/settings-body-DRRQNaDA.js.gz +0 -0
  205. package/dist/web/assets/settings-section-content-DRaHfvm8.js +1 -0
  206. package/dist/web/assets/settings-section-content-U3mIx6hF.js +2 -0
  207. package/dist/web/assets/settings-section-content-U3mIx6hF.js.br +0 -0
  208. package/dist/web/assets/settings-section-content-U3mIx6hF.js.gz +0 -0
  209. package/dist/web/assets/{settings-store-DfuiLq_9.js → settings-store-Cyuo8ceh.js} +2 -2
  210. package/dist/web/assets/settings-store-Cyuo8ceh.js.br +0 -0
  211. package/dist/web/assets/settings-store-Cyuo8ceh.js.gz +0 -0
  212. package/dist/web/assets/settings-tab-CB_BhHTK.js +1 -0
  213. package/dist/web/assets/settings-window-content-CgZIMNX8.js +1 -0
  214. package/dist/web/assets/{slash-command-picker-CLevA_Gf.js → slash-command-picker-CQlIqMW0.js} +1 -1
  215. package/dist/web/assets/slash-command-picker-CQlIqMW0.js.br +0 -0
  216. package/dist/web/assets/slash-command-picker-CQlIqMW0.js.gz +0 -0
  217. package/dist/web/assets/{sql-query-editor-Db8b0jEr.js → sql-query-editor--Z4bcqd8.js} +1 -1
  218. package/dist/web/assets/sql-query-editor--Z4bcqd8.js.br +0 -0
  219. package/dist/web/assets/sql-query-editor--Z4bcqd8.js.gz +0 -0
  220. package/dist/web/assets/{sqlite-viewer-VzYLMqkD.js → sqlite-viewer-CSmX3qaj.js} +1 -1
  221. package/dist/web/assets/sqlite-viewer-CSmX3qaj.js.br +0 -0
  222. package/dist/web/assets/sqlite-viewer-CSmX3qaj.js.gz +0 -0
  223. package/dist/web/assets/{system-monitor-body-BR60W_mG.js → system-monitor-body-LannpU6H.js} +2 -2
  224. package/dist/web/assets/system-monitor-body-LannpU6H.js.br +0 -0
  225. package/dist/web/assets/system-monitor-body-LannpU6H.js.gz +0 -0
  226. package/dist/web/assets/system-monitor-tab-BfVucwEF.js +1 -0
  227. package/dist/web/assets/{system-monitor-window-content-BLw1QBXo.js → system-monitor-window-content-kLNW9Ln3.js} +1 -1
  228. package/dist/web/assets/{tab-host-window-content-BL61SB5m.js → tab-host-window-content-II_FtOYM.js} +1 -1
  229. package/dist/web/assets/tab-host-window-content-II_FtOYM.js.br +0 -0
  230. package/dist/web/assets/tab-host-window-content-II_FtOYM.js.gz +0 -0
  231. package/dist/web/assets/{tab-store-CbPh8CAX.js → tab-store-DCpc0g0Q.js} +1 -1
  232. package/dist/web/assets/{terminal-tab-B4y6at4h.js → terminal-tab-CTe2polt.js} +1 -1
  233. package/dist/web/assets/terminal-tab-CTe2polt.js.br +0 -0
  234. package/dist/web/assets/terminal-tab-CTe2polt.js.gz +0 -0
  235. package/dist/web/assets/{tool-cards-K0r_yxI0.js → tool-cards-rxLXbBSm.js} +5 -5
  236. package/dist/web/assets/tool-cards-rxLXbBSm.js.br +0 -0
  237. package/dist/web/assets/tool-cards-rxLXbBSm.js.gz +0 -0
  238. package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js +1 -0
  239. package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js.br +0 -0
  240. package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js.gz +0 -0
  241. package/dist/web/assets/{use-inline-blame-BK23icsE.js → use-inline-blame-CxZ_QWzS.js} +3 -3
  242. package/dist/web/assets/use-inline-blame-CxZ_QWzS.js.br +0 -0
  243. package/dist/web/assets/use-inline-blame-CxZ_QWzS.js.gz +0 -0
  244. package/dist/web/assets/{use-lsp-CRdCPCKW.js → use-lsp-gCNE5A9K.js} +1 -1
  245. package/dist/web/assets/use-lsp-gCNE5A9K.js.br +0 -0
  246. package/dist/web/assets/use-lsp-gCNE5A9K.js.gz +0 -0
  247. package/dist/web/assets/{use-monaco-theme-CpXT2uh3.js → use-monaco-theme-DvNGcCvz.js} +1 -1
  248. package/dist/web/assets/{use-process-kill-BWYX03KF.js → use-process-kill-Cbiu1mbY.js} +1 -1
  249. package/dist/web/assets/use-process-kill-Cbiu1mbY.js.br +0 -0
  250. package/dist/web/assets/use-process-kill-Cbiu1mbY.js.gz +0 -0
  251. package/dist/web/assets/{use-websocket-CiWQKhHr.js → use-websocket-AC7EG1LK.js} +1 -1
  252. package/dist/web/assets/video-preview-C2Y61WUE.js +1 -0
  253. package/dist/web/assets/video-preview-C2Y61WUE.js.br +0 -0
  254. package/dist/web/assets/video-preview-C2Y61WUE.js.gz +0 -0
  255. package/dist/web/assets/{voice-settings-section-Ceihggqf.js → voice-settings-section-DCXZeLYI.js} +1 -1
  256. package/dist/web/assets/voice-settings-section-DCXZeLYI.js.br +0 -0
  257. package/dist/web/assets/voice-settings-section-DCXZeLYI.js.gz +0 -0
  258. package/dist/web/assets/{window-pip-registry-mDgwpAwP.js → window-pip-registry-9Y9LQQYS.js} +1 -1
  259. package/dist/web/index.html +50 -7
  260. package/dist/web/index.html.br +0 -0
  261. package/dist/web/index.html.gz +0 -0
  262. package/dist/web/sw.js +1 -1
  263. package/dist/web/sw.js.br +0 -0
  264. package/dist/web/sw.js.gz +0 -0
  265. package/docs/architecture/android-emulator-phase0-report-260921.md +310 -0
  266. package/docs/architecture/android-emulator-phase2-report-260921.md +163 -0
  267. package/docs/architecture/android-emulator-phase3-report-260921.md +203 -0
  268. package/docs/architecture/android-emulator-phase4-report-260921.md +191 -0
  269. package/docs/architecture/android-emulator-plan-260920.md +376 -0
  270. package/docs/architecture/plugins-and-tracing.md +48 -7
  271. package/package.json +4 -2
  272. package/scripts/gen-android-proto.ts +37 -0
  273. package/scripts/release.sh +3 -1
  274. package/src/cli/commands/chat-cmd.ts +2 -2
  275. package/src/providers/claude-agent-sdk-query-options.ts +28 -0
  276. package/src/providers/claude-agent-sdk.ts +153 -71
  277. package/src/providers/claude-warm-spare.ts +176 -0
  278. package/src/providers/provider.interface.ts +1 -0
  279. package/src/server/index.ts +53 -0
  280. package/src/server/middleware/gzip-json.ts +13 -1
  281. package/src/server/routes/android.ts +616 -0
  282. package/src/server/routes/chat.ts +31 -0
  283. package/src/server/routes/files.ts +52 -5
  284. package/src/server/routes/remote-desktop.ts +95 -2
  285. package/src/server/routes/trace.ts +66 -0
  286. package/src/server/ws/android.ts +101 -0
  287. package/src/server/ws/chat.ts +12 -17
  288. package/src/server/ws/global.ts +13 -1
  289. package/src/server/ws/remote-desktop.ts +6 -1
  290. package/src/services/android/android-apk.ts +387 -0
  291. package/src/services/android/android-capabilities.ts +154 -0
  292. package/src/services/android/android-flag.ts +12 -0
  293. package/src/services/android/android-grpc.ts +124 -0
  294. package/src/services/android/android-input.ts +129 -0
  295. package/src/services/android/android-logcat.ts +169 -0
  296. package/src/services/android/android-nonce.ts +50 -0
  297. package/src/services/android/android-operations.ts +124 -0
  298. package/src/services/android/android-screenshot.ts +53 -0
  299. package/src/services/android/android-session.ts +510 -0
  300. package/src/services/android/android-video.ts +495 -0
  301. package/src/services/android/avd-list.ts +131 -0
  302. package/src/services/android/avd-manager.ts +397 -0
  303. package/src/services/android/device-registry.ts +223 -0
  304. package/src/services/android/emulator-discovery.ts +160 -0
  305. package/src/services/android/emulator-launcher.ts +290 -0
  306. package/src/services/android/proto/emulator-controller-descriptor.ts +10 -0
  307. package/src/services/android/proto/emulator_controller.proto +1791 -0
  308. package/src/services/android/sdk-discovery.ts +178 -0
  309. package/src/services/android/system-images.ts +124 -0
  310. package/src/services/chat.service.ts +81 -4
  311. package/src/services/config.service.ts +1 -1
  312. package/src/services/file-filter.service.ts +2 -61
  313. package/src/services/file-glob.ts +67 -0
  314. package/src/services/file-index/file-index-runner.ts +169 -0
  315. package/src/services/file-index/file-index-worker.ts +73 -0
  316. package/src/services/file-index/index-search.ts +152 -0
  317. package/src/services/file-index/index-walk.ts +109 -0
  318. package/src/services/file-list-index.service.ts +189 -70
  319. package/src/services/file-watcher/linux-inotify.ts +238 -0
  320. package/src/services/file-watcher/watch-tree.ts +37 -6
  321. package/src/services/file-watcher.service.ts +40 -8
  322. package/src/services/file.service.ts +17 -6
  323. package/src/services/group-chat/group-chat.service.ts +1 -1
  324. package/src/services/jira-debug-session.service.ts +1 -1
  325. package/src/services/ppmbot/ppmbot-delegation.ts +1 -1
  326. package/src/services/ppmbot/ppmbot-service.ts +1 -1
  327. package/src/services/project-content-search.service.ts +45 -11
  328. package/src/services/proxy-agent-turn.ts +7 -3
  329. package/src/services/remote-desktop/mediamtx-catalog.ts +89 -0
  330. package/src/services/remote-desktop/mediamtx-config.ts +91 -0
  331. package/src/services/remote-desktop/mediamtx-install.service.ts +191 -0
  332. package/src/services/remote-desktop/mediamtx-paths.ts +51 -0
  333. package/src/services/remote-desktop/mediamtx-process.ts +152 -0
  334. package/src/services/remote-desktop/remote-desktop-capture-wayland.ts +312 -0
  335. package/src/services/remote-desktop/remote-desktop-capture.ts +60 -4
  336. package/src/services/remote-desktop/remote-desktop-portal.ts +529 -0
  337. package/src/services/remote-desktop/remote-desktop-requirements.ts +56 -20
  338. package/src/services/remote-desktop/remote-desktop-session.ts +77 -3
  339. package/src/services/remote-desktop/remote-desktop-whep-registry.ts +36 -0
  340. package/src/services/scheduler-runner.ts +2 -3
  341. package/src/services/session-trace/browser-trace-ingest.ts +131 -0
  342. package/src/services/session-trace/session-trace-cleanup.ts +65 -0
  343. package/src/services/session-trace/session-trace-db.ts +89 -0
  344. package/src/services/session-trace/session-trace-store.ts +132 -0
  345. package/src/services/session-trace/trace-coalescer.ts +86 -0
  346. package/src/services/session-trace/trace-recorder.ts +304 -0
  347. package/src/services/session-trace/trace-writer.ts +83 -0
  348. package/src/shared/android-avd.ts +53 -0
  349. package/src/shared/android-protocol.ts +184 -0
  350. package/src/shared/file-index-limits.ts +17 -0
  351. package/src/shared/session-trace.ts +61 -0
  352. package/src/types/chat.ts +17 -0
  353. package/src/types/config.ts +27 -0
  354. package/src/types/project.ts +9 -0
  355. package/src/web/app.tsx +5 -0
  356. package/src/web/components/android/android-apk-upload.ts +75 -0
  357. package/src/web/components/android/android-avd-create-dialog.tsx +305 -0
  358. package/src/web/components/android/android-avd-destroy-dialog.tsx +151 -0
  359. package/src/web/components/android/android-clipboard-panel.tsx +94 -0
  360. package/src/web/components/android/android-controls.tsx +128 -0
  361. package/src/web/components/android/android-coords.ts +99 -0
  362. package/src/web/components/android/android-device-list.tsx +329 -0
  363. package/src/web/components/android/android-install-panel.tsx +280 -0
  364. package/src/web/components/android/android-log-filter.ts +75 -0
  365. package/src/web/components/android/android-logcat-panel.tsx +214 -0
  366. package/src/web/components/android/android-screenshot-download.ts +56 -0
  367. package/src/web/components/android/android-tab.tsx +66 -0
  368. package/src/web/components/android/android-tools-drawer.tsx +76 -0
  369. package/src/web/components/android/android-viewer.tsx +200 -0
  370. package/src/web/components/android/android-ws-url.ts +21 -0
  371. package/src/web/components/android/open-android.ts +21 -0
  372. package/src/web/components/android/use-android-available.ts +29 -0
  373. package/src/web/components/android/use-android-keyboard.ts +111 -0
  374. package/src/web/components/android/use-android-session.ts +277 -0
  375. package/src/web/components/android/use-android-touch.ts +123 -0
  376. package/src/web/components/chat/chat-tab.tsx +28 -2
  377. package/src/web/components/chat/message-input.tsx +3 -5
  378. package/src/web/components/editor/compare-picker.tsx +12 -2
  379. package/src/web/components/explorer/file-tree.tsx +6 -7
  380. package/src/web/components/explorer/use-tree-row-dnd.ts +0 -2
  381. package/src/web/components/floating-window/window-content-registry.ts +8 -8
  382. package/src/web/components/layout/command-palette.tsx +31 -9
  383. package/src/web/components/layout/mobile-drawer.tsx +8 -1
  384. package/src/web/components/layout/nav-section-rail.tsx +8 -1
  385. package/src/web/components/layout/reparenting-tab.tsx +2 -2
  386. package/src/web/components/layout/tab-content.tsx +5 -0
  387. package/src/web/components/layout/tab-pool.tsx +31 -20
  388. package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +23 -1
  389. package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +64 -6
  390. package/src/web/components/remote-desktop/use-webrtc-canvas-video.ts +255 -0
  391. package/src/web/components/root-error-boundary.tsx +5 -0
  392. package/src/web/components/settings/remote-desktop-settings-section.tsx +176 -0
  393. package/src/web/components/settings/settings-categories.ts +3 -0
  394. package/src/web/components/settings/settings-section-content.tsx +25 -18
  395. package/src/web/hooks/use-chat-prewarm.ts +53 -0
  396. package/src/web/hooks/use-chat.ts +18 -4
  397. package/src/web/hooks/use-file-index-invalidation.ts +7 -5
  398. package/src/web/hooks/use-global-events.ts +12 -1
  399. package/src/web/hooks/use-remote-file-search.ts +39 -0
  400. package/src/web/hooks/use-ui-preload.ts +38 -0
  401. package/src/web/index.html +43 -0
  402. package/src/web/lib/chunk-recovery.ts +5 -1
  403. package/src/web/lib/device-id.ts +39 -0
  404. package/src/web/lib/feature-badges.ts +2 -0
  405. package/src/web/lib/lazy-with-preload.tsx +43 -0
  406. package/src/web/lib/preload-ui.ts +60 -0
  407. package/src/web/lib/score-file-search.ts +27 -14
  408. package/src/web/lib/tab-type-icons.ts +2 -1
  409. package/src/web/lib/trace-boot.ts +8 -0
  410. package/src/web/lib/trace-client.ts +516 -0
  411. package/src/web/main.tsx +12 -0
  412. package/src/web/stores/file-store.ts +124 -18
  413. package/src/web/stores/panel-utils.ts +3 -0
  414. package/src/web/stores/tab-store.ts +2 -1
  415. package/src/web/stores/window-panel-persistence.ts +3 -0
  416. package/vite.config.ts +3 -0
  417. package/dist/web/assets/accounts-settings-section-DEIm-W-D.js +0 -1
  418. package/dist/web/assets/accounts-settings-section-DEIm-W-D.js.br +0 -0
  419. package/dist/web/assets/accounts-settings-section-DEIm-W-D.js.gz +0 -0
  420. package/dist/web/assets/agent-session-sheet-CBMsnl_p.js.br +0 -0
  421. package/dist/web/assets/agent-session-sheet-CBMsnl_p.js.gz +0 -0
  422. package/dist/web/assets/agent-session-window-content-D9C9FA7E.js.br +0 -0
  423. package/dist/web/assets/agent-session-window-content-D9C9FA7E.js.gz +0 -0
  424. package/dist/web/assets/ai-resource-editor-DhUVgDEG.js.br +0 -0
  425. package/dist/web/assets/ai-resource-editor-DhUVgDEG.js.gz +0 -0
  426. package/dist/web/assets/ai-settings-section-CETpSpYd.js.br +0 -0
  427. package/dist/web/assets/ai-settings-section-CETpSpYd.js.gz +0 -0
  428. package/dist/web/assets/appearance-settings-section-BJUiLUb7.js.br +0 -0
  429. package/dist/web/assets/appearance-settings-section-BJUiLUb7.js.gz +0 -0
  430. package/dist/web/assets/apps-panel-1VElRgV3.js.br +0 -0
  431. package/dist/web/assets/apps-panel-1VElRgV3.js.gz +0 -0
  432. package/dist/web/assets/audio-preview-DYkyHu5X.js.br +0 -0
  433. package/dist/web/assets/audio-preview-DYkyHu5X.js.gz +0 -0
  434. package/dist/web/assets/branch-review-tab-DhTMSpSU.js +0 -1
  435. package/dist/web/assets/branch-review-tab-DhTMSpSU.js.br +0 -0
  436. package/dist/web/assets/branch-review-tab-DhTMSpSU.js.gz +0 -0
  437. package/dist/web/assets/chat-tab-Cg3BKugo.js +0 -15
  438. package/dist/web/assets/chat-tab-Cg3BKugo.js.br +0 -0
  439. package/dist/web/assets/chat-tab-Cg3BKugo.js.gz +0 -0
  440. package/dist/web/assets/chat-tab-tbUDK__Y.js +0 -1
  441. package/dist/web/assets/chat-tab-tbUDK__Y.js.br +0 -0
  442. package/dist/web/assets/chat-tab-tbUDK__Y.js.gz +0 -0
  443. package/dist/web/assets/code-editor-6ZiQehbr.js +0 -7
  444. package/dist/web/assets/code-editor-6ZiQehbr.js.br +0 -0
  445. package/dist/web/assets/code-editor-6ZiQehbr.js.gz +0 -0
  446. package/dist/web/assets/codex-reset-credit-button-Fr45FUxi.js.br +0 -0
  447. package/dist/web/assets/codex-reset-credit-button-Fr45FUxi.js.gz +0 -0
  448. package/dist/web/assets/conflict-editor-B-wdjSXI.js.br +0 -0
  449. package/dist/web/assets/conflict-editor-B-wdjSXI.js.gz +0 -0
  450. package/dist/web/assets/csv-preview-B6RodObB.js.br +0 -0
  451. package/dist/web/assets/csv-preview-B6RodObB.js.gz +0 -0
  452. package/dist/web/assets/database-viewer-CdPBUQPY.js.br +0 -0
  453. package/dist/web/assets/database-viewer-CdPBUQPY.js.gz +0 -0
  454. package/dist/web/assets/design-settings-section-BpCpaBwL.js.br +0 -0
  455. package/dist/web/assets/design-settings-section-BpCpaBwL.js.gz +0 -0
  456. package/dist/web/assets/design-skill-suggestion-DkT2E2IV.js.br +0 -0
  457. package/dist/web/assets/design-skill-suggestion-DkT2E2IV.js.gz +0 -0
  458. package/dist/web/assets/design-tab-BZb9eemI.js.br +0 -0
  459. package/dist/web/assets/design-tab-BZb9eemI.js.gz +0 -0
  460. package/dist/web/assets/designs-sidebar-panel-CF4tp6j-.js.br +0 -0
  461. package/dist/web/assets/designs-sidebar-panel-CF4tp6j-.js.gz +0 -0
  462. package/dist/web/assets/diff-viewer-BqEqwSw6.js.br +0 -0
  463. package/dist/web/assets/diff-viewer-BqEqwSw6.js.gz +0 -0
  464. package/dist/web/assets/edit-diff-preview-DD4HayXY.js.br +0 -0
  465. package/dist/web/assets/edit-diff-preview-DD4HayXY.js.gz +0 -0
  466. package/dist/web/assets/editor-language-service-CkA5sEdV.js.br +0 -0
  467. package/dist/web/assets/editor-language-service-CkA5sEdV.js.gz +0 -0
  468. package/dist/web/assets/explorer-body-Ds7oKuz7.js +0 -2
  469. package/dist/web/assets/explorer-body-Ds7oKuz7.js.br +0 -0
  470. package/dist/web/assets/explorer-body-Ds7oKuz7.js.gz +0 -0
  471. package/dist/web/assets/explorer-window-content-CRJ2eMZ4.js.br +0 -0
  472. package/dist/web/assets/explorer-window-content-CRJ2eMZ4.js.gz +0 -0
  473. package/dist/web/assets/extension-manager-section-DwQTdCII.js.br +0 -0
  474. package/dist/web/assets/extension-manager-section-DwQTdCII.js.gz +0 -0
  475. package/dist/web/assets/extension-webview-CMq-VTLu.js.br +0 -0
  476. package/dist/web/assets/extension-webview-CMq-VTLu.js.gz +0 -0
  477. package/dist/web/assets/file-store-DY1_0nzY.js +0 -1
  478. package/dist/web/assets/file-store-DY1_0nzY.js.br +0 -0
  479. package/dist/web/assets/file-store-DY1_0nzY.js.gz +0 -0
  480. package/dist/web/assets/files-settings-section-B2lcyh-6.js.br +0 -0
  481. package/dist/web/assets/files-settings-section-B2lcyh-6.js.gz +0 -0
  482. package/dist/web/assets/general-settings-section-Doepm2sH.js.br +0 -0
  483. package/dist/web/assets/general-settings-section-Doepm2sH.js.gz +0 -0
  484. package/dist/web/assets/git-log-panel-CJakNMDc.js.br +0 -0
  485. package/dist/web/assets/git-log-panel-CJakNMDc.js.gz +0 -0
  486. package/dist/web/assets/glide-data-grid-C_SeOhSq.js.br +0 -0
  487. package/dist/web/assets/glide-data-grid-C_SeOhSq.js.gz +0 -0
  488. package/dist/web/assets/group-chat-tab--by1xCQW.js +0 -1
  489. package/dist/web/assets/group-chat-tab--by1xCQW.js.br +0 -0
  490. package/dist/web/assets/group-chat-tab--by1xCQW.js.gz +0 -0
  491. package/dist/web/assets/index-DhWjx5iR.js +0 -52
  492. package/dist/web/assets/index-DhWjx5iR.js.br +0 -0
  493. package/dist/web/assets/index-DhWjx5iR.js.gz +0 -0
  494. package/dist/web/assets/index-oIvYSKTT.css +0 -1
  495. package/dist/web/assets/index-oIvYSKTT.css.br +0 -0
  496. package/dist/web/assets/index-oIvYSKTT.css.gz +0 -0
  497. package/dist/web/assets/keybindings-store-30LYZU0l.js +0 -1
  498. package/dist/web/assets/keyboard-shortcuts-section-BgZe3QDr.js.br +0 -0
  499. package/dist/web/assets/keyboard-shortcuts-section-BgZe3QDr.js.gz +0 -0
  500. package/dist/web/assets/language-servers-section-CCMzgOaE.js.br +0 -0
  501. package/dist/web/assets/language-servers-section-CCMzgOaE.js.gz +0 -0
  502. package/dist/web/assets/lsp-client-B10suuaZ.js.br +0 -0
  503. package/dist/web/assets/lsp-client-B10suuaZ.js.gz +0 -0
  504. package/dist/web/assets/markdown-renderer-AHHFS3jc.js.br +0 -0
  505. package/dist/web/assets/markdown-renderer-AHHFS3jc.js.gz +0 -0
  506. package/dist/web/assets/markdown-renderer-DxnXtBoj.js +0 -1
  507. package/dist/web/assets/mobile-explorer-sheet-CqCsLWSr.js.br +0 -0
  508. package/dist/web/assets/mobile-explorer-sheet-CqCsLWSr.js.gz +0 -0
  509. package/dist/web/assets/new-design-dialog-B9tgnQXq.js +0 -1
  510. package/dist/web/assets/new-design-dialog-B9tgnQXq.js.br +0 -0
  511. package/dist/web/assets/new-design-dialog-B9tgnQXq.js.gz +0 -0
  512. package/dist/web/assets/notification-store-HUVzO_bp.js +0 -1
  513. package/dist/web/assets/notifications-settings-section-CXgzH_bK.js.br +0 -0
  514. package/dist/web/assets/notifications-settings-section-CXgzH_bK.js.gz +0 -0
  515. package/dist/web/assets/overview-panel-BYB8mgRE.js.br +0 -0
  516. package/dist/web/assets/overview-panel-BYB8mgRE.js.gz +0 -0
  517. package/dist/web/assets/panel-store-CWHPmHwj.js +0 -1
  518. package/dist/web/assets/panel-store-CWHPmHwj.js.br +0 -0
  519. package/dist/web/assets/panel-store-CWHPmHwj.js.gz +0 -0
  520. package/dist/web/assets/performance-panel-Dpuq3g0W.js.br +0 -0
  521. package/dist/web/assets/performance-panel-Dpuq3g0W.js.gz +0 -0
  522. package/dist/web/assets/postgres-viewer-DW0Gkmow.js.br +0 -0
  523. package/dist/web/assets/postgres-viewer-DW0Gkmow.js.gz +0 -0
  524. package/dist/web/assets/ppmbot-settings-section-DFtlGoW6.js.br +0 -0
  525. package/dist/web/assets/ppmbot-settings-section-DFtlGoW6.js.gz +0 -0
  526. package/dist/web/assets/pptx-export-CNyG32Xr.js.br +0 -0
  527. package/dist/web/assets/pptx-export-CNyG32Xr.js.gz +0 -0
  528. package/dist/web/assets/problems-panel-V5zqpuXq.js.br +0 -0
  529. package/dist/web/assets/problems-panel-V5zqpuXq.js.gz +0 -0
  530. package/dist/web/assets/process-table-DAj46HIl.js +0 -1
  531. package/dist/web/assets/process-table-DAj46HIl.js.br +0 -0
  532. package/dist/web/assets/process-table-DAj46HIl.js.gz +0 -0
  533. package/dist/web/assets/proxy-settings-section-B7AVlTfY.js.br +0 -0
  534. package/dist/web/assets/proxy-settings-section-B7AVlTfY.js.gz +0 -0
  535. package/dist/web/assets/query-audit-section-gHmRfWKr.js.br +0 -0
  536. package/dist/web/assets/query-audit-section-gHmRfWKr.js.gz +0 -0
  537. package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js +0 -1
  538. package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js.br +0 -0
  539. package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js.gz +0 -0
  540. package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js +0 -2
  541. package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js.br +0 -0
  542. package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js.gz +0 -0
  543. package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js +0 -1
  544. package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js.br +0 -0
  545. package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js.gz +0 -0
  546. package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js +0 -1
  547. package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js.br +0 -0
  548. package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js.gz +0 -0
  549. package/dist/web/assets/remote-desktop-window-content-BnznIby3.js +0 -1
  550. package/dist/web/assets/remote-desktop-window-content-BnznIby3.js.br +0 -0
  551. package/dist/web/assets/remote-desktop-window-content-BnznIby3.js.gz +0 -0
  552. package/dist/web/assets/schedules-settings-section-sYDAsBMO.js.br +0 -0
  553. package/dist/web/assets/schedules-settings-section-sYDAsBMO.js.gz +0 -0
  554. package/dist/web/assets/send-to-chat-CCdOrKc7.js.br +0 -0
  555. package/dist/web/assets/send-to-chat-CCdOrKc7.js.gz +0 -0
  556. package/dist/web/assets/services-panel-CKa2aP1d.js.br +0 -0
  557. package/dist/web/assets/services-panel-CKa2aP1d.js.gz +0 -0
  558. package/dist/web/assets/settings-body-CEIF8lkl.js +0 -2
  559. package/dist/web/assets/settings-body-CEIF8lkl.js.br +0 -0
  560. package/dist/web/assets/settings-body-CEIF8lkl.js.gz +0 -0
  561. package/dist/web/assets/settings-store-DfuiLq_9.js.br +0 -0
  562. package/dist/web/assets/settings-store-DfuiLq_9.js.gz +0 -0
  563. package/dist/web/assets/settings-tab-Du5AUPni.js +0 -1
  564. package/dist/web/assets/settings-window-content-BTflfLez.js +0 -1
  565. package/dist/web/assets/slash-command-picker-CLevA_Gf.js.br +0 -0
  566. package/dist/web/assets/slash-command-picker-CLevA_Gf.js.gz +0 -0
  567. package/dist/web/assets/sql-query-editor-Db8b0jEr.js.br +0 -0
  568. package/dist/web/assets/sql-query-editor-Db8b0jEr.js.gz +0 -0
  569. package/dist/web/assets/sqlite-viewer-VzYLMqkD.js.br +0 -0
  570. package/dist/web/assets/sqlite-viewer-VzYLMqkD.js.gz +0 -0
  571. package/dist/web/assets/system-monitor-body-BR60W_mG.js.br +0 -0
  572. package/dist/web/assets/system-monitor-body-BR60W_mG.js.gz +0 -0
  573. package/dist/web/assets/system-monitor-tab-BYpantE2.js +0 -1
  574. package/dist/web/assets/tab-host-window-content-BL61SB5m.js.br +0 -0
  575. package/dist/web/assets/tab-host-window-content-BL61SB5m.js.gz +0 -0
  576. package/dist/web/assets/terminal-tab-B4y6at4h.js.br +0 -0
  577. package/dist/web/assets/terminal-tab-B4y6at4h.js.gz +0 -0
  578. package/dist/web/assets/tool-cards-K0r_yxI0.js.br +0 -0
  579. package/dist/web/assets/tool-cards-K0r_yxI0.js.gz +0 -0
  580. package/dist/web/assets/use-inline-blame-BK23icsE.js.br +0 -0
  581. package/dist/web/assets/use-inline-blame-BK23icsE.js.gz +0 -0
  582. package/dist/web/assets/use-lsp-CRdCPCKW.js.br +0 -0
  583. package/dist/web/assets/use-lsp-CRdCPCKW.js.gz +0 -0
  584. package/dist/web/assets/use-process-kill-BWYX03KF.js.br +0 -0
  585. package/dist/web/assets/use-process-kill-BWYX03KF.js.gz +0 -0
  586. package/dist/web/assets/video-preview-DugVkMB7.js +0 -1
  587. package/dist/web/assets/video-preview-DugVkMB7.js.br +0 -0
  588. package/dist/web/assets/video-preview-DugVkMB7.js.gz +0 -0
  589. package/dist/web/assets/voice-settings-section-Ceihggqf.js.br +0 -0
  590. package/dist/web/assets/voice-settings-section-Ceihggqf.js.gz +0 -0
  591. /package/dist/web/assets/{__vite-browser-external-B_XMEguz.js → __vite-browser-external-C5mXParC.js} +0 -0
  592. /package/dist/web/assets/{agent-session-sheet-store-DO682WSg.js → agent-session-sheet-store-_OeezCXB.js} +0 -0
  593. /package/dist/web/assets/{api-settings-CpO8SPk9.js → api-settings-Cc_CpfmC.js} +0 -0
  594. /package/dist/web/assets/{api-settings-CpO8SPk9.js.br → api-settings-Cc_CpfmC.js.br} +0 -0
  595. /package/dist/web/assets/{api-settings-CpO8SPk9.js.gz → api-settings-Cc_CpfmC.js.gz} +0 -0
  596. /package/dist/web/assets/{api-themes-CJipDH_l.js → api-themes-BtMBSjuM.js} +0 -0
  597. /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js → can-open-in-ppm-DeE2-kd5.js} +0 -0
  598. /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js.br → can-open-in-ppm-DeE2-kd5.js.br} +0 -0
  599. /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js.gz → can-open-in-ppm-DeE2-kd5.js.gz} +0 -0
  600. /package/dist/web/assets/{csv-parser-DcRWxcNV.js → csv-parser-CoxPdyLw.js} +0 -0
  601. /package/dist/web/assets/{csv-parser-DcRWxcNV.js.br → csv-parser-CoxPdyLw.js.br} +0 -0
  602. /package/dist/web/assets/{csv-parser-DcRWxcNV.js.gz → csv-parser-CoxPdyLw.js.gz} +0 -0
  603. /package/dist/web/assets/{design-export-client-CHffN3DM.js → design-export-client-BfdZB7xK.js} +0 -0
  604. /package/dist/web/assets/{design-export-client-CHffN3DM.js.br → design-export-client-BfdZB7xK.js.br} +0 -0
  605. /package/dist/web/assets/{design-export-client-CHffN3DM.js.gz → design-export-client-BfdZB7xK.js.gz} +0 -0
  606. /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js → design-responsive-dialog-BiYy3ibS.js} +0 -0
  607. /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js.br → design-responsive-dialog-BiYy3ibS.js.br} +0 -0
  608. /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js.gz → design-responsive-dialog-BiYy3ibS.js.gz} +0 -0
  609. /package/dist/web/assets/{design-system-status-label-B_0I_3a8.js → design-system-status-label-ekiLyjKn.js} +0 -0
  610. /package/dist/web/assets/{docx-preview-B3eJyY2y.js → docx-preview-Dt6RQpfA.js} +0 -0
  611. /package/dist/web/assets/{docx-preview-B3eJyY2y.js.br → docx-preview-Dt6RQpfA.js.br} +0 -0
  612. /package/dist/web/assets/{docx-preview-B3eJyY2y.js.gz → docx-preview-Dt6RQpfA.js.gz} +0 -0
  613. /package/dist/web/assets/{editor-font-BNwo7zo5.js → editor-font-CBszn6vt.js} +0 -0
  614. /package/dist/web/assets/{format-bytes-CRZfxO2J.js → format-bytes-FQmpZ25A.js} +0 -0
  615. /package/dist/web/assets/{image-gallery-DC3gRAqk.js → image-gallery-B16hO6Ab.js} +0 -0
  616. /package/dist/web/assets/{image-preview-geometry-DN3DZQp0.js → image-preview-geometry-D4Ihz4UV.js} +0 -0
  617. /package/dist/web/assets/{lib-B9k5tn9s.js → lib-6APiJkU3.js} +0 -0
  618. /package/dist/web/assets/{lib-B9k5tn9s.js.br → lib-6APiJkU3.js.br} +0 -0
  619. /package/dist/web/assets/{lib-B9k5tn9s.js.gz → lib-6APiJkU3.js.gz} +0 -0
  620. /package/dist/web/assets/{libesm-5f7T4AHA.js → libesm-5wREk7JN.js} +0 -0
  621. /package/dist/web/assets/{libesm-5f7T4AHA.js.br → libesm-5wREk7JN.js.br} +0 -0
  622. /package/dist/web/assets/{libesm-5f7T4AHA.js.gz → libesm-5wREk7JN.js.gz} +0 -0
  623. /package/dist/web/assets/{media-url-CCGOIxzS.js → media-url-CrT-qulZ.js} +0 -0
  624. /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js → metric-chart-canvas-D7f-LQ8x.js} +0 -0
  625. /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js.br → metric-chart-canvas-D7f-LQ8x.js.br} +0 -0
  626. /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js.gz → metric-chart-canvas-D7f-LQ8x.js.gz} +0 -0
  627. /package/dist/web/assets/{monaco-dotenv-language-Bwq3gQsi.js → monaco-dotenv-language-DbSss7YR.js} +0 -0
  628. /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js → onboarding-entry-CGFdGLLP.js} +0 -0
  629. /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js.br → onboarding-entry-CGFdGLLP.js.br} +0 -0
  630. /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js.gz → onboarding-entry-CGFdGLLP.js.gz} +0 -0
  631. /package/dist/web/assets/{pdf-preview-X8bdpfE9.js → pdf-preview-B8A4T-ES.js} +0 -0
  632. /package/dist/web/assets/{pdf-preview-X8bdpfE9.js.br → pdf-preview-B8A4T-ES.js.br} +0 -0
  633. /package/dist/web/assets/{pdf-preview-X8bdpfE9.js.gz → pdf-preview-B8A4T-ES.js.gz} +0 -0
  634. /package/dist/web/assets/{separator-DMu7VFQa.js → separator-dHj3Km--.js} +0 -0
  635. /package/dist/web/assets/{sortable-header-CipIP7aH.js → sortable-header-BOa8o7NJ.js} +0 -0
  636. /package/dist/web/assets/{sortable-header-CipIP7aH.js.br → sortable-header-BOa8o7NJ.js.br} +0 -0
  637. /package/dist/web/assets/{sortable-header-CipIP7aH.js.gz → sortable-header-BOa8o7NJ.js.gz} +0 -0
  638. /package/dist/web/assets/{use-blob-url-DjuRQWnR.js → use-blob-url-BC69n15x.js} +0 -0
  639. /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js → vendor-xterm-CfasyE0m.js} +0 -0
  640. /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js.br → vendor-xterm-CfasyE0m.js.br} +0 -0
  641. /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js.gz → vendor-xterm-CfasyE0m.js.gz} +0 -0
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Which emulators are running right now, and how to reach each one's gRPC endpoint.
3
+ *
4
+ * The emulator advertises itself in a per-process `.ini` under the *current user's* runtime
5
+ * directory. Plan §5 requires this to be read defensively: bounded in size, with PID liveness
6
+ * and process identity verified, and only a loopback endpoint accepted — a stale `.ini` from a
7
+ * crashed emulator otherwise names a port some unrelated process may now hold.
8
+ */
9
+ import { readdirSync, readFileSync, statSync } from "node:fs";
10
+ import { homedir, platform } from "node:os";
11
+ import { join } from "node:path";
12
+
13
+ /** A discovery .ini is a few hundred bytes; anything larger is not one, and we refuse to read it. */
14
+ const MAX_DISCOVERY_BYTES = 64 * 1024;
15
+
16
+ export interface RunningEmulator {
17
+ /** Absolute path of the discovery file this came from. */
18
+ file: string;
19
+ pid: number;
20
+ /**
21
+ * The AVD **id** (`avd.id`) — what `-avd` takes, what an AVD's `config.ini` calls `AvdId`, and
22
+ * what `listAvds()` reports as `name`. Deliberately not `avd.name`, which is the display name.
23
+ */
24
+ avdName: string;
25
+ avdDir: string | null;
26
+ emulatorVersion: string | null;
27
+ grpcPort: number;
28
+ /** Bearer token for the gRPC channel. Never leaves the backend. */
29
+ grpcToken: string | null;
30
+ /** Directory of JSON Web Key Sets, when the emulator offers JWT auth. */
31
+ grpcJwks: string | null;
32
+ adbPort: number | null;
33
+ adbSerial: string | null;
34
+ /** The emulator's own argv, used to verify this pid is still the process the file describes. */
35
+ cmdline: string | null;
36
+ }
37
+
38
+ /** Where the emulator writes discovery files, current user only. */
39
+ export function discoveryDirs(): string[] {
40
+ const dirs: string[] = [];
41
+ const runtime = process.env.XDG_RUNTIME_DIR;
42
+ if (runtime) dirs.push(join(runtime, "avd", "running"));
43
+ dirs.push(join(homedir(), ".android", "avd", "running"));
44
+ if (platform() === "win32") {
45
+ const local = process.env.LOCALAPPDATA;
46
+ if (local) dirs.push(join(local, "Temp", "avd", "running"));
47
+ } else {
48
+ const tmp = process.env.TMPDIR ?? "/tmp";
49
+ dirs.push(join(tmp, `android-${process.env.USER ?? ""}`, "avd", "running"));
50
+ }
51
+ return dirs;
52
+ }
53
+
54
+ function parseIni(text: string): Record<string, string> {
55
+ const out: Record<string, string> = {};
56
+ for (const line of text.split("\n")) {
57
+ const t = line.trim();
58
+ if (!t || t.startsWith("#") || t.startsWith("[")) continue;
59
+ const eq = t.indexOf("=");
60
+ if (eq <= 0) continue;
61
+ out[t.slice(0, eq).trim()] = t.slice(eq + 1).trim();
62
+ }
63
+ return out;
64
+ }
65
+
66
+ /** Is this pid alive? Signal 0 tests existence without delivering anything. */
67
+ function pidAlive(pid: number): boolean {
68
+ try { process.kill(pid, 0); return true; } catch { return false; }
69
+ }
70
+
71
+ /**
72
+ * Does the live process still look like the emulator the discovery file describes?
73
+ *
74
+ * PIDs are reused. Without this, a stale `.ini` whose pid now belongs to something else would
75
+ * be treated as a running emulator — and a later "stop" would signal an innocent process.
76
+ */
77
+ export function verifyProcessIdentity(pid: number, avdName: string | undefined): boolean {
78
+ const avd = avdName;
79
+ if (!avd) return false;
80
+ if (platform() !== "linux") {
81
+ // Only /proc gives a cheap, dependency-free argv. Elsewhere the pid check plus a live gRPC
82
+ // handshake is what establishes identity, so accept a live pid here and let the connect
83
+ // prove it.
84
+ return pidAlive(pid);
85
+ }
86
+ try {
87
+ const argv = readFileSync(`/proc/${pid}/cmdline`, "utf8").split("\0").filter(Boolean);
88
+ return argv.some((a) => a === avd) || argv.some((a) => a.includes("qemu-system"));
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
94
+ function parsePort(v: string | undefined): number | null {
95
+ const n = Number(v);
96
+ return Number.isInteger(n) && n > 0 && n <= 65535 ? n : null;
97
+ }
98
+
99
+ /** Every emulator this user is running that advertises a usable loopback gRPC endpoint. */
100
+ export function findRunningEmulators(): RunningEmulator[] {
101
+ const found: RunningEmulator[] = [];
102
+ const seenPids = new Set<number>();
103
+
104
+ for (const dir of discoveryDirs()) {
105
+ let entries: string[];
106
+ try { entries = readdirSync(dir); } catch { continue; }
107
+
108
+ for (const name of entries) {
109
+ const m = /^pid_(\d+)\.ini$/.exec(name);
110
+ if (!m) continue;
111
+ const pid = Number(m[1]);
112
+ if (seenPids.has(pid)) continue;
113
+
114
+ const file = join(dir, name);
115
+ let fields: Record<string, string>;
116
+ try {
117
+ if (statSync(file).size > MAX_DISCOVERY_BYTES) continue;
118
+ fields = parseIni(readFileSync(file, "utf8"));
119
+ } catch {
120
+ continue; // racing with emulator shutdown is normal
121
+ }
122
+
123
+ const grpcPort = parsePort(fields["grpc.port"]);
124
+ if (!grpcPort) continue; // no control channel, nothing we can drive
125
+ if (!pidAlive(pid)) continue; // stale file from a crashed emulator
126
+ // pid was reused by something else
127
+ if (!verifyProcessIdentity(pid, fields["avd.id"] ?? fields["avd.name"])) continue;
128
+
129
+ seenPids.add(pid);
130
+ const adbPort = parsePort(fields["port.adb"]);
131
+ const serialPort = parsePort(fields["port.serial"]);
132
+ found.push({
133
+ file,
134
+ pid,
135
+ // `avd.id`, **never** `avd.name`. The discovery file carries both, and for any AVD made
136
+ // in Android Studio they differ: the id is `Pixel_9` while `avd.name` is `Pixel 9`, the
137
+ // same string with the underscores turned back into spaces. Read the display name here
138
+ // and a running emulator stops matching its own AVD row — the device list then shows the
139
+ // AVD as stopped *and* a second `external:` row beside it with no geometry, and Start is
140
+ // offered for a device that is already up. Every AVD used while this was built had a
141
+ // one-word name, where the two fields agree, which is why it was never seen.
142
+ avdName: fields["avd.id"] ?? fields["avd.name"] ?? "(unknown)",
143
+ avdDir: fields["avd.dir"] ?? null,
144
+ emulatorVersion: fields["emulator.version"] ?? null,
145
+ grpcPort,
146
+ grpcToken: fields["grpc.token"] ?? null,
147
+ grpcJwks: fields["grpc.jwks"] ?? null,
148
+ adbPort,
149
+ // adb names an emulator by its *console* port, not its adb port.
150
+ adbSerial: serialPort ? `emulator-${serialPort}` : null,
151
+ cmdline: fields["cmdline"] ?? null,
152
+ });
153
+ }
154
+ }
155
+ return found;
156
+ }
157
+
158
+ export function findRunningEmulatorByAvd(avdName: string): RunningEmulator | null {
159
+ return findRunningEmulators().find((e) => e.avdName === avdName) ?? null;
160
+ }
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Starting and stopping emulators PPM owns.
3
+ *
4
+ * Four things here are load-bearing and each one is in the plan for a reason:
5
+ *
6
+ * - **One start per AVD at a time.** A refresh, a double-tap on Start, or two browser tabs must
7
+ * not spawn two emulators against one AVD — that corrupts the userdata image. A per-AVD mutex
8
+ * plus start idempotency (an in-flight start is *returned*, not duplicated) is what prevents it.
9
+ * - **Never `-grpc <port>`.** `emulator -help` says `-grpc-use-jwt ... (default, disable with
10
+ * -grpc flag)`, so pinning a port silently drops the control channel to unauthenticated.
11
+ * The port is discovered from the emulator's own advertisement instead.
12
+ * - **`ANDROID_AVD_HOME` goes in the child's env only.** Setting it on this process would hide
13
+ * every AVD outside it from our own listing — it replaces the default rather than adding to it.
14
+ * - **A lock file is reported, never removed.** An AVD Android Studio is running stays untouched.
15
+ */
16
+ import { spawn } from "node:child_process";
17
+ import { existsSync } from "node:fs";
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { connectToEmulator, getEmulatorStatus, requestShutdown } from "./android-grpc.ts";
21
+ import { findRunningEmulatorByAvd, findRunningEmulators, type RunningEmulator } from "./emulator-discovery.ts";
22
+ import { claimOwnership, listDevices, releaseOwnership } from "./device-registry.ts";
23
+ import { createOperation, failOperation, finishOperation, updateOperation, type Operation } from "./android-operations.ts";
24
+ import { avdHomeEnv } from "./sdk-discovery.ts";
25
+
26
+ /** How long to wait for the guest to report boot complete before calling it failed. */
27
+ const DEFAULT_BOOT_DEADLINE_MS = 5 * 60_000;
28
+ /** How often to ask. Cheap: a getStatus is sub-millisecond once the channel is up. */
29
+ const BOOT_POLL_MS = 1_000;
30
+ /** Emulator stderr/stdout kept for diagnostics. Bounded: a boot loop can log without end. */
31
+ const LOG_RING_LINES = 200;
32
+
33
+ export interface StartOptions {
34
+ avdName: string;
35
+ avdHome: string;
36
+ emulatorPath: string;
37
+ /** Extra flags the caller has already validated. Passed as argv, never through a shell. */
38
+ extraArgs?: string[];
39
+ bootDeadlineMs?: number;
40
+ /** Run without a visible window. `qt-hide-window` still creates one (and needs a display). */
41
+ windowMode?: "no-window" | "qt-hide-window" | "window";
42
+ gpuMode?: string;
43
+ /**
44
+ * Quick boot resumes the saved snapshot and saves one on exit; cold boot ignores any snapshot
45
+ * and boots the guest from scratch.
46
+ *
47
+ * Neither touches user data — that is what **wipe** is for, and conflating the two is how a
48
+ * "boot fresh" button ends up deleting somebody's app state. A cold boot is minutes; a quick
49
+ * boot is seconds, which is why it is the default.
50
+ */
51
+ bootMode?: "quick" | "cold";
52
+ /**
53
+ * How many emulators this host may run at once, starts still booting included. Counted here
54
+ * because only here is the count in the same synchronous step as the reservation below: a
55
+ * caller that counts, awaits, then starts lets two requests for two different AVDs both see
56
+ * the same free slot.
57
+ */
58
+ maxConcurrent?: number;
59
+ }
60
+
61
+ /** A start refused because the host is already at `maxConcurrent`. */
62
+ export class EmulatorLimitError extends Error {
63
+ constructor(readonly busy: number, readonly limit: number) {
64
+ super(`already running or starting ${busy} emulator(s); the limit for this host is ${limit}`);
65
+ }
66
+ }
67
+
68
+ export interface StartedDevice {
69
+ avdName: string;
70
+ pid: number;
71
+ grpcPort: number;
72
+ adbSerial: string | null;
73
+ generation: number;
74
+ }
75
+
76
+ interface InFlight {
77
+ operation: Operation<StartedDevice>;
78
+ promise: Promise<StartedDevice>;
79
+ }
80
+
81
+ /** One entry per AVD name while a start is running — this *is* the mutex. */
82
+ const starting = new Map<string, InFlight>();
83
+ /** Bounded log of what each emulator printed, for the error surface. */
84
+ const logs = new Map<string, string[]>();
85
+
86
+ export function emulatorLog(avdName: string): string[] {
87
+ return logs.get(avdName) ?? [];
88
+ }
89
+
90
+ function appendLog(avdName: string, chunk: string): void {
91
+ const ring = logs.get(avdName) ?? [];
92
+ for (const line of chunk.split("\n")) {
93
+ if (!line.trim()) continue;
94
+ ring.push(line);
95
+ if (ring.length > LOG_RING_LINES) ring.shift();
96
+ }
97
+ logs.set(avdName, ring);
98
+ }
99
+
100
+ /** The env the *child* gets. Shared with the SDK tools, which need the same treatment. */
101
+ const childEnv = avdHomeEnv;
102
+
103
+ /** Exported for tests: the flag set is a decision, and `-grpc`'s absence is load-bearing. */
104
+ export function buildArgs(opts: StartOptions): string[] {
105
+ const args = ["-avd", opts.avdName];
106
+ switch (opts.windowMode ?? "no-window") {
107
+ case "no-window": args.push("-no-window"); break;
108
+ case "qt-hide-window": args.push("-qt-hide-window"); break;
109
+ case "window": break;
110
+ }
111
+ args.push("-no-boot-anim");
112
+ // `-no-snapshot-load` only refuses to *resume* one; the guest's disk is untouched either way.
113
+ if ((opts.bootMode ?? "quick") === "cold") args.push("-no-snapshot-load");
114
+ if (opts.gpuMode) args.push("-gpu", opts.gpuMode);
115
+ // Deliberately absent: `-grpc <port>`. See the file header.
116
+ for (const extra of opts.extraArgs ?? []) args.push(extra);
117
+ return args;
118
+ }
119
+
120
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
121
+
122
+ /** Poll discovery until this AVD advertises a gRPC endpoint, or the deadline passes. */
123
+ async function waitForAdvertisement(avdName: string, deadline: number): Promise<RunningEmulator> {
124
+ while (Date.now() < deadline) {
125
+ const found = findRunningEmulatorByAvd(avdName);
126
+ if (found) return found;
127
+ await sleep(250);
128
+ }
129
+ throw new Error(`emulator for ${avdName} never advertised a gRPC endpoint`);
130
+ }
131
+
132
+ /** Poll the guest until it reports boot complete. */
133
+ async function waitForBoot(
134
+ emulator: RunningEmulator,
135
+ deadline: number,
136
+ onProgress: (detail: string) => void,
137
+ ): Promise<void> {
138
+ const channel = connectToEmulator(emulator);
139
+ const startedAt = Date.now();
140
+ try {
141
+ while (Date.now() < deadline) {
142
+ try {
143
+ const status = await getEmulatorStatus(channel);
144
+ if (status.booted) return;
145
+ onProgress(`booting (${Math.round((Date.now() - startedAt) / 1000)}s)`);
146
+ } catch {
147
+ onProgress(`waiting for control channel (${Math.round((Date.now() - startedAt) / 1000)}s)`);
148
+ }
149
+ await sleep(BOOT_POLL_MS);
150
+ }
151
+ throw new Error("guest did not report boot complete before the deadline");
152
+ } finally {
153
+ channel.close();
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Start an emulator, or return the start already running for this AVD.
159
+ *
160
+ * Returns immediately with an operation the caller polls; a cold boot is minutes and no HTTP
161
+ * request should be held that long.
162
+ */
163
+ export function startEmulator(opts: StartOptions): Operation<StartedDevice> {
164
+ const inFlight = starting.get(opts.avdName);
165
+ if (inFlight) return inFlight.operation; // idempotent: same operation, no second process
166
+
167
+ const already = findRunningEmulatorByAvd(opts.avdName);
168
+ if (already) {
169
+ const op = createOperation<StartedDevice>("android.start", "already running");
170
+ finishOperation(op.id, {
171
+ avdName: opts.avdName,
172
+ pid: already.pid,
173
+ grpcPort: already.grpcPort,
174
+ adbSerial: already.adbSerial,
175
+ generation: 0,
176
+ });
177
+ return op;
178
+ }
179
+
180
+ if (opts.maxConcurrent !== undefined) {
181
+ // A start in flight counts as much as a running emulator: it is minutes to boot, and until
182
+ // it advertises itself discovery cannot see it.
183
+ const busy = new Set([...findRunningEmulators().map((e) => e.avdName), ...starting.keys()]);
184
+ if (busy.size >= opts.maxConcurrent) throw new EmulatorLimitError(busy.size, opts.maxConcurrent);
185
+ }
186
+
187
+ const operation = createOperation<StartedDevice>("android.start", "spawning emulator");
188
+ const promise = run(opts, operation).finally(() => starting.delete(opts.avdName));
189
+ starting.set(opts.avdName, { operation, promise });
190
+ // The operation carries the outcome; an unobserved rejection here must not crash the server.
191
+ promise.catch(() => {});
192
+ return operation;
193
+ }
194
+
195
+ async function run(opts: StartOptions, operation: Operation<StartedDevice>): Promise<StartedDevice> {
196
+ const deadline = Date.now() + (opts.bootDeadlineMs ?? DEFAULT_BOOT_DEADLINE_MS);
197
+ updateOperation(operation.id, { state: "running", detail: "spawning emulator" });
198
+ logs.delete(opts.avdName);
199
+
200
+ if (!existsSync(opts.emulatorPath)) {
201
+ const message = `emulator binary not found at ${opts.emulatorPath}`;
202
+ failOperation(operation.id, message);
203
+ throw new Error(message);
204
+ }
205
+
206
+ // argv, never a shell string: an AVD name or SDK path with a space or a quote in it would
207
+ // otherwise be re-split by the shell.
208
+ const child = spawn(opts.emulatorPath, buildArgs(opts), {
209
+ env: childEnv(opts.avdHome),
210
+ stdio: ["ignore", "pipe", "pipe"],
211
+ detached: false,
212
+ });
213
+
214
+ child.stdout?.on("data", (d: Buffer) => appendLog(opts.avdName, d.toString()));
215
+ child.stderr?.on("data", (d: Buffer) => appendLog(opts.avdName, d.toString()));
216
+
217
+ let spawnError: Error | null = null;
218
+ child.on("error", (e) => { spawnError = e; });
219
+
220
+ try {
221
+ updateOperation(operation.id, { detail: "waiting for the emulator to advertise itself" });
222
+ const emulator = await waitForAdvertisement(opts.avdName, deadline);
223
+
224
+ updateOperation(operation.id, { detail: "booting" });
225
+ await waitForBoot(emulator, deadline, (detail) => updateOperation(operation.id, { detail }));
226
+
227
+ const generation = claimOwnership(opts.avdName, emulator.pid);
228
+ const started: StartedDevice = {
229
+ avdName: opts.avdName,
230
+ pid: emulator.pid,
231
+ grpcPort: emulator.grpcPort,
232
+ adbSerial: emulator.adbSerial,
233
+ generation,
234
+ };
235
+ finishOperation(operation.id, started);
236
+ return started;
237
+ } catch (e) {
238
+ const tail = emulatorLog(opts.avdName).slice(-6).join("\n");
239
+ const base = spawnError ? `${(spawnError as Error).message}` : (e as Error).message;
240
+ const message = tail ? `${base}\n${tail}` : base;
241
+ failOperation(operation.id, message);
242
+ throw new Error(message);
243
+ }
244
+ }
245
+
246
+ export type StopOutcome = "stopped" | "not-running" | "not-owned";
247
+
248
+ /**
249
+ * Stop an emulator PPM started.
250
+ *
251
+ * Graceful only: `setVmState SHUTDOWN` over gRPC, which measured at 1-3 seconds. Nothing here
252
+ * signals a pid, and certainly not by process *name* — on this very host `pgrep qemu-system`
253
+ * matches Docker Desktop.
254
+ */
255
+ export async function stopEmulator(
256
+ avdName: string,
257
+ opts: { avdHome: string; requireOwnership?: boolean },
258
+ ): Promise<StopOutcome> {
259
+ const emulator = findRunningEmulatorByAvd(avdName);
260
+ if (!emulator) {
261
+ releaseOwnership(avdName);
262
+ return "not-running";
263
+ }
264
+ if (opts.requireOwnership !== false) {
265
+ const entry = listDevices(opts.avdHome).find((d) => d.name === avdName);
266
+ if (entry?.runtime && !entry.runtime.ownedByPpm) return "not-owned";
267
+ }
268
+
269
+ const channel = connectToEmulator(emulator);
270
+ try {
271
+ await requestShutdown(channel);
272
+ } finally {
273
+ channel.close();
274
+ }
275
+
276
+ // Wait for the process to actually go, so the caller can report truthfully.
277
+ const deadline = Date.now() + 30_000;
278
+ while (Date.now() < deadline) {
279
+ try { process.kill(emulator.pid, 0); } catch { break; }
280
+ await sleep(250);
281
+ }
282
+ releaseOwnership(avdName);
283
+ return "stopped";
284
+ }
285
+
286
+ /** Test seam. */
287
+ export function _resetLauncher(): void {
288
+ starting.clear();
289
+ logs.clear();
290
+ }
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/gen-android-proto.ts — do not edit.
2
+ //
3
+ // Source: emulator_controller.proto (Apache 2.0, The Android Open Source Project)
4
+ // Taken from: $ANDROID_SDK_ROOT/emulator/lib/emulator_controller.proto
5
+ // Emulator: 36.5.10.0 (build 15081367)
6
+ // SHA-256: e872af01d8ff0a46d2d19c644709e4d524be609e9cff69f75b06ab0bb67653dd
7
+ //
8
+ // Embedded rather than loaded from disk: a compiled binary cannot read the .proto file.
9
+ export const EMULATOR_CONTROLLER_PROTO_SHA256 = "e872af01d8ff0a46d2d19c644709e4d524be609e9cff69f75b06ab0bb67653dd";
10
+ export const emulatorControllerDescriptor = {"options":{"java_multiple_files":true,"java_package":"com.android.emulator.control","objc_class_prefix":"AEC"},"nested":{"android":{"nested":{"emulation":{"nested":{"control":{"nested":{"EmulatorController":{"methods":{"streamSensor":{"requestType":"SensorValue","responseType":"SensorValue","responseStream":true},"getSensor":{"requestType":"SensorValue","responseType":"SensorValue"},"setSensor":{"requestType":"SensorValue","responseType":"google.protobuf.Empty"},"setPhysicalModel":{"requestType":"PhysicalModelValue","responseType":"google.protobuf.Empty"},"getPhysicalModel":{"requestType":"PhysicalModelValue","responseType":"PhysicalModelValue"},"streamPhysicalModel":{"requestType":"PhysicalModelValue","responseType":"PhysicalModelValue","responseStream":true},"setClipboard":{"requestType":"ClipData","responseType":"google.protobuf.Empty"},"getClipboard":{"requestType":"google.protobuf.Empty","responseType":"ClipData"},"streamClipboard":{"requestType":"google.protobuf.Empty","responseType":"ClipData","responseStream":true},"setBattery":{"requestType":"BatteryState","responseType":"google.protobuf.Empty"},"getBattery":{"requestType":"google.protobuf.Empty","responseType":"BatteryState"},"setGps":{"requestType":"GpsState","responseType":"google.protobuf.Empty"},"getGps":{"requestType":"google.protobuf.Empty","responseType":"GpsState"},"sendFingerprint":{"requestType":"Fingerprint","responseType":"google.protobuf.Empty"},"sendKey":{"requestType":"KeyboardEvent","responseType":"google.protobuf.Empty"},"sendTouch":{"requestType":"TouchEvent","responseType":"google.protobuf.Empty"},"sendMouse":{"requestType":"MouseEvent","responseType":"google.protobuf.Empty"},"injectWheel":{"requestType":"WheelEvent","requestStream":true,"responseType":"google.protobuf.Empty"},"streamInputEvent":{"requestType":"InputEvent","requestStream":true,"responseType":"google.protobuf.Empty"},"sendPhone":{"requestType":"PhoneCall","responseType":"PhoneResponse"},"sendSms":{"requestType":"SmsMessage","responseType":"PhoneResponse"},"setPhoneNumber":{"requestType":"PhoneNumber","responseType":"PhoneResponse"},"getStatus":{"requestType":"google.protobuf.Empty","responseType":"EmulatorStatus"},"getScreenshot":{"requestType":"ImageFormat","responseType":"Image"},"streamScreenshot":{"requestType":"ImageFormat","responseType":"Image","responseStream":true},"streamAudio":{"requestType":"AudioFormat","responseType":"AudioPacket","responseStream":true},"injectAudio":{"requestType":"AudioPacket","requestStream":true,"responseType":"google.protobuf.Empty"},"getMicrophoneState":{"requestType":"google.protobuf.Empty","responseType":"MicrophoneState"},"setMicrophoneState":{"requestType":"MicrophoneState","responseType":"google.protobuf.Empty"},"getLogcat":{"requestType":"LogMessage","responseType":"LogMessage","options":{"deprecated":true},"parsedOptions":[{"deprecated":true}]},"streamLogcat":{"requestType":"LogMessage","responseType":"LogMessage","responseStream":true},"setVmState":{"requestType":"VmRunState","responseType":"google.protobuf.Empty"},"getVmState":{"requestType":"google.protobuf.Empty","responseType":"VmRunState"},"setDisplayConfigurations":{"requestType":"DisplayConfigurations","responseType":"DisplayConfigurations"},"getDisplayConfigurations":{"requestType":"google.protobuf.Empty","responseType":"DisplayConfigurations"},"streamNotification":{"requestType":"google.protobuf.Empty","responseType":"Notification","responseStream":true},"rotateVirtualSceneCamera":{"requestType":"RotationRadian","responseType":"google.protobuf.Empty"},"setVirtualSceneCameraVelocity":{"requestType":"Velocity","responseType":"google.protobuf.Empty"},"setPosture":{"requestType":"Posture","responseType":"google.protobuf.Empty"},"getBrightness":{"requestType":"BrightnessValue","responseType":"BrightnessValue"},"setBrightness":{"requestType":"BrightnessValue","responseType":"google.protobuf.Empty"},"getDisplayMode":{"requestType":"google.protobuf.Empty","responseType":"DisplayMode"},"setDisplayMode":{"requestType":"DisplayMode","responseType":"google.protobuf.Empty"},"setXrOptions":{"requestType":"XrOptions","responseType":"google.protobuf.Empty"},"getXrOptions":{"requestType":"google.protobuf.Empty","responseType":"XrOptions"}}},"VmRunState":{"fields":{"state":{"type":"RunState","id":1}},"nested":{"RunState":{"values":{"UNKNOWN":0,"RUNNING":1,"RESTORE_VM":2,"PAUSED":3,"SAVE_VM":4,"SHUTDOWN":5,"TERMINATE":7,"RESET":9,"INTERNAL_ERROR":10,"RESTART":11,"START":12,"STOP":13}}}},"ParameterValue":{"fields":{"data":{"rule":"repeated","type":"float","id":1,"options":{"packed":true}}}},"PhysicalModelValue":{"fields":{"target":{"type":"PhysicalType","id":1},"status":{"type":"State","id":2},"value":{"type":"ParameterValue","id":3}},"nested":{"State":{"values":{"OK":0,"NO_SERVICE":-3,"DISABLED":-2,"UNKNOWN":-1}},"PhysicalType":{"values":{"POSITION":0,"ROTATION":1,"MAGNETIC_FIELD":2,"TEMPERATURE":3,"PROXIMITY":4,"LIGHT":5,"PRESSURE":6,"HUMIDITY":7,"VELOCITY":8,"AMBIENT_MOTION":9,"HINGE_ANGLE0":10,"HINGE_ANGLE1":11,"HINGE_ANGLE2":12,"ROLLABLE0":13,"ROLLABLE1":14,"ROLLABLE2":15,"POSTURE":16,"HEART_RATE":17,"RGBC_LIGHT":18,"WRIST_TILT":19}}}},"SensorValue":{"fields":{"target":{"type":"SensorType","id":1},"status":{"type":"State","id":2},"value":{"type":"ParameterValue","id":3}},"nested":{"State":{"values":{"OK":0,"NO_SERVICE":-3,"DISABLED":-2,"UNKNOWN":-1}},"SensorType":{"values":{"ACCELERATION":0,"GYROSCOPE":1,"MAGNETIC_FIELD":2,"ORIENTATION":3,"TEMPERATURE":4,"PROXIMITY":5,"LIGHT":6,"PRESSURE":7,"HUMIDITY":8,"MAGNETIC_FIELD_UNCALIBRATED":9,"GYROSCOPE_UNCALIBRATED":10,"HEART_RATE":14,"RGBC_LIGHT":15,"ACCELERATION_UNCALIBRATED":17,"HEADING":18}}}},"BrightnessValue":{"fields":{"target":{"type":"LightType","id":1},"value":{"type":"uint32","id":2}},"nested":{"LightType":{"values":{"LCD":0,"KEYBOARD":1,"BUTTON":2}}}},"DisplayModeValue":{"values":{"PHONE":0,"FOLDABLE":1,"TABLET":2,"DESKTOP":3}},"DisplayMode":{"fields":{"value":{"type":"DisplayModeValue","id":1}}},"XrOptions":{"fields":{"environment":{"type":"Environment","id":1},"passthroughCoefficient":{"type":"float","id":2}},"nested":{"Environment":{"values":{"LIVING_ROOM_DAY":0,"LIVING_ROOM_NIGHT":1}}}},"LogMessage":{"fields":{"contents":{"type":"string","id":1},"start":{"type":"int64","id":2,"options":{"deprecated":true}},"next":{"type":"int64","id":3,"options":{"deprecated":true}},"sort":{"type":"LogType","id":4},"entries":{"rule":"repeated","type":"LogcatEntry","id":5}},"nested":{"LogType":{"values":{"Text":0,"Parsed":1}}}},"LogcatEntry":{"fields":{"timestamp":{"type":"uint64","id":1},"pid":{"type":"uint32","id":2},"tid":{"type":"uint32","id":3},"level":{"type":"LogLevel","id":4},"tag":{"type":"string","id":5},"msg":{"type":"string","id":6}},"nested":{"LogLevel":{"values":{"UNKNOWN":0,"DEFAULT":1,"VERBOSE":2,"DEBUG":3,"INFO":4,"WARN":5,"ERR":6,"FATAL":7,"SILENT":8}}}},"VmConfiguration":{"fields":{"hypervisorType":{"type":"VmHypervisorType","id":1},"numberOfCpuCores":{"type":"int32","id":2},"ramSizeBytes":{"type":"int64","id":3}},"nested":{"VmHypervisorType":{"valuesOptions":{"HAXM":{"deprecated":true}},"values":{"UNKNOWN":0,"NONE":1,"KVM":2,"HAXM":3,"HVF":4,"WHPX":5,"AEHD":6}}}},"ClipData":{"fields":{"text":{"type":"string","id":1}}},"Touch":{"fields":{"x":{"type":"int32","id":1},"y":{"type":"int32","id":2},"identifier":{"type":"int32","id":3},"pressure":{"type":"int32","id":4},"touchMajor":{"type":"int32","id":5},"touchMinor":{"type":"int32","id":6},"expiration":{"type":"EventExpiration","id":7},"orientation":{"type":"int32","id":8}},"nested":{"EventExpiration":{"values":{"EVENT_EXPIRATION_UNSPECIFIED":0,"NEVER_EXPIRE":1}}}},"Pen":{"fields":{"location":{"type":"Touch","id":1},"buttonPressed":{"type":"bool","id":2},"rubberPointer":{"type":"bool","id":3}}},"TouchEvent":{"fields":{"touches":{"rule":"repeated","type":"Touch","id":1},"display":{"type":"int32","id":2}}},"TouchpadEvent":{"fields":{"touches":{"rule":"repeated","type":"Touch","id":1},"touchpad":{"type":"int32","id":2}}},"PenEvent":{"fields":{"events":{"rule":"repeated","type":"Pen","id":1},"display":{"type":"int32","id":2}}},"MouseEvent":{"fields":{"x":{"type":"int32","id":1},"y":{"type":"int32","id":2},"buttons":{"type":"int32","id":3},"display":{"type":"int32","id":4}}},"WheelEvent":{"fields":{"dx":{"type":"int32","id":1},"dy":{"type":"int32","id":2},"display":{"type":"int32","id":3}}},"KeyboardEvent":{"fields":{"codeType":{"type":"KeyCodeType","id":1},"eventType":{"type":"KeyEventType","id":2},"keyCode":{"type":"int32","id":3},"key":{"type":"string","id":4},"text":{"type":"string","id":5}},"nested":{"KeyCodeType":{"values":{"Usb":0,"Evdev":1,"XKB":2,"Win":3,"Mac":4}},"KeyEventType":{"values":{"keydown":0,"keyup":1,"keypress":2}}}},"XrCommand":{"fields":{"action":{"type":"Action","id":1}},"nested":{"Action":{"values":{"RECENTER":0}}}},"InputEvent":{"oneofs":{"type":{"oneof":["keyEvent","touchEvent","mouseEvent","androidEvent","penEvent","wheelEvent","xrHandEvent","xrEyeEvent","xrCommand","xrHeadRotationEvent","xrHeadMovementEvent","xrHeadAngularVelocityEvent","xrHeadVelocityEvent","touchpadEvent"]}},"fields":{"keyEvent":{"type":"KeyboardEvent","id":1},"touchEvent":{"type":"TouchEvent","id":2},"mouseEvent":{"type":"MouseEvent","id":3},"androidEvent":{"type":"AndroidEvent","id":4},"penEvent":{"type":"PenEvent","id":5},"wheelEvent":{"type":"WheelEvent","id":6},"xrHandEvent":{"type":"MouseEvent","id":7},"xrEyeEvent":{"type":"MouseEvent","id":8},"xrCommand":{"type":"XrCommand","id":9},"xrHeadRotationEvent":{"type":"RotationRadian","id":10},"xrHeadMovementEvent":{"type":"Translation","id":11},"xrHeadAngularVelocityEvent":{"type":"AngularVelocity","id":12},"xrHeadVelocityEvent":{"type":"Velocity","id":13},"touchpadEvent":{"type":"TouchpadEvent","id":14}}},"AndroidEvent":{"fields":{"type":{"type":"int32","id":1},"code":{"type":"int32","id":2},"value":{"type":"int32","id":3},"display":{"type":"int32","id":4}}},"Fingerprint":{"fields":{"isTouching":{"type":"bool","id":1},"touchId":{"type":"int32","id":2}}},"GpsState":{"fields":{"passiveUpdate":{"type":"bool","id":1},"latitude":{"type":"double","id":2},"longitude":{"type":"double","id":3},"speed":{"type":"double","id":4},"bearing":{"type":"double","id":5},"altitude":{"type":"double","id":6},"satellites":{"type":"int32","id":7}}},"BatteryState":{"fields":{"hasBattery":{"type":"bool","id":1},"isPresent":{"type":"bool","id":2},"charger":{"type":"BatteryCharger","id":3},"chargeLevel":{"type":"int32","id":4},"health":{"type":"BatteryHealth","id":5},"status":{"type":"BatteryStatus","id":6}},"nested":{"BatteryStatus":{"values":{"UNKNOWN":0,"CHARGING":1,"DISCHARGING":2,"NOT_CHARGING":3,"FULL":4}},"BatteryCharger":{"values":{"NONE":0,"AC":1,"USB":2,"WIRELESS":3}},"BatteryHealth":{"values":{"GOOD":0,"FAILED":1,"DEAD":2,"OVERVOLTAGE":3,"OVERHEATED":4}}}},"ImageTransport":{"fields":{"channel":{"type":"TransportChannel","id":1},"handle":{"type":"string","id":2}},"nested":{"TransportChannel":{"values":{"TRANSPORT_CHANNEL_UNSPECIFIED":0,"MMAP":1}}}},"FoldedDisplay":{"fields":{"width":{"type":"uint32","id":1},"height":{"type":"uint32","id":2},"xOffset":{"type":"uint32","id":3},"yOffset":{"type":"uint32","id":4}}},"ImageFormat":{"fields":{"format":{"type":"ImgFormat","id":1},"rotation":{"type":"Rotation","id":2},"width":{"type":"uint32","id":3},"height":{"type":"uint32","id":4},"display":{"type":"uint32","id":5},"transport":{"type":"ImageTransport","id":6},"foldedDisplay":{"type":"FoldedDisplay","id":7},"displayMode":{"type":"DisplayModeValue","id":8}},"nested":{"ImgFormat":{"values":{"PNG":0,"RGBA8888":1,"RGB888":2}}}},"Image":{"fields":{"format":{"type":"ImageFormat","id":1},"width":{"type":"uint32","id":2,"options":{"deprecated":true}},"height":{"type":"uint32","id":3,"options":{"deprecated":true}},"image":{"type":"bytes","id":4},"seq":{"type":"uint32","id":5},"timestampUs":{"type":"uint64","id":6}}},"Rotation":{"fields":{"rotation":{"type":"SkinRotation","id":1},"xAxis":{"type":"double","id":2},"yAxis":{"type":"double","id":3},"zAxis":{"type":"double","id":4}},"nested":{"SkinRotation":{"values":{"PORTRAIT":0,"LANDSCAPE":1,"REVERSE_PORTRAIT":2,"REVERSE_LANDSCAPE":3}}}},"PhoneCall":{"fields":{"operation":{"type":"Operation","id":1},"number":{"type":"string","id":2}},"nested":{"Operation":{"values":{"InitCall":0,"AcceptCall":1,"RejectCallExplicit":2,"RejectCallBusy":3,"DisconnectCall":4,"PlaceCallOnHold":5,"TakeCallOffHold":6}}}},"PhoneResponse":{"fields":{"response":{"type":"Response","id":1}},"nested":{"Response":{"values":{"OK":0,"BadOperation":1,"BadNumber":2,"InvalidAction":3,"ActionFailed":4,"RadioOff":5}}}},"Entry":{"fields":{"key":{"type":"string","id":1},"value":{"type":"string","id":2}}},"EntryList":{"fields":{"entry":{"rule":"repeated","type":"Entry","id":1}}},"EmulatorStatus":{"fields":{"version":{"type":"string","id":1},"uptime":{"type":"uint64","id":2},"booted":{"type":"bool","id":3},"vmConfig":{"type":"VmConfiguration","id":4},"hardwareConfig":{"type":"EntryList","id":5},"heartbeat":{"type":"uint64","id":6},"guestConfig":{"keyType":"string","type":"string","id":7}}},"AudioFormat":{"fields":{"samplingRate":{"type":"uint64","id":1},"channels":{"type":"Channels","id":2},"format":{"type":"SampleFormat","id":3},"mode":{"type":"DeliveryMode","id":4}},"nested":{"SampleFormat":{"values":{"AUD_FMT_U8":0,"AUD_FMT_S16":1}},"Channels":{"values":{"Mono":0,"Stereo":1}},"DeliveryMode":{"values":{"MODE_UNSPECIFIED":0,"MODE_REAL_TIME":1}}}},"AudioPacket":{"fields":{"format":{"type":"AudioFormat","id":1},"timestamp":{"type":"uint64","id":2},"audio":{"type":"bytes","id":3}}},"MicrophoneState":{"fields":{"realAudioEnabled":{"type":"bool","id":1}}},"SmsMessage":{"fields":{"srcAddress":{"type":"string","id":1},"text":{"type":"string","id":2}}},"DisplayConfiguration":{"fields":{"width":{"type":"uint32","id":1},"height":{"type":"uint32","id":2},"dpi":{"type":"uint32","id":3},"flags":{"type":"uint32","id":4},"display":{"type":"uint32","id":5}},"nested":{"DisplayFlags":{"values":{"DISPLAYFLAGS_UNSPECIFIED":0,"VIRTUAL_DISPLAY_FLAG_PUBLIC":1,"VIRTUAL_DISPLAY_FLAG_PRESENTATION":2,"VIRTUAL_DISPLAY_FLAG_SECURE":4,"VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY":8,"VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR":16}}}},"DisplayConfigurations":{"fields":{"displays":{"rule":"repeated","type":"DisplayConfiguration","id":1},"userConfigurable":{"type":"uint32","id":2},"maxDisplays":{"type":"uint32","id":3}}},"Notification":{"oneofs":{"type":{"oneof":["cameraNotification","displayConfigurationsChangedNotification","posture","booted","brightness","textViewFocus","xrOptions","microphoneState"]}},"fields":{"cameraNotification":{"type":"CameraNotification","id":2},"displayConfigurationsChangedNotification":{"type":"DisplayConfigurationsChangedNotification","id":3},"posture":{"type":"Posture","id":4},"booted":{"type":"BootCompletedNotification","id":5},"brightness":{"type":"BrightnessValue","id":6},"textViewFocus":{"type":"TextViewFocus","id":7},"xrOptions":{"type":"XrOptions","id":8},"microphoneState":{"type":"MicrophoneState","id":9}}},"BootCompletedNotification":{"fields":{"time":{"type":"int32","id":1}}},"CameraNotification":{"fields":{"active":{"type":"bool","id":1},"display":{"type":"int32","id":2}}},"TextViewFocus":{"fields":{"textViewHasFocus":{"type":"bool","id":1},"display":{"type":"int32","id":2}}},"DisplayConfigurationsChangedNotification":{"fields":{"displayConfigurations":{"type":"DisplayConfigurations","id":1}}},"RotationRadian":{"fields":{"x":{"type":"float","id":1},"y":{"type":"float","id":2},"z":{"type":"float","id":3}}},"Translation":{"fields":{"deltaX":{"type":"float","id":1},"deltaY":{"type":"float","id":2},"deltaZ":{"type":"float","id":3}}},"AngularVelocity":{"fields":{"omegaX":{"type":"float","id":1},"omegaY":{"type":"float","id":2},"omegaZ":{"type":"float","id":3}}},"Velocity":{"fields":{"x":{"type":"float","id":1},"y":{"type":"float","id":2},"z":{"type":"float","id":3}}},"Posture":{"fields":{"value":{"type":"PostureValue","id":3}},"nested":{"PostureValue":{"values":{"POSTURE_UNKNOWN":0,"POSTURE_CLOSED":1,"POSTURE_HALF_OPENED":2,"POSTURE_OPENED":3,"POSTURE_FLIPPED":4,"POSTURE_TENT":5,"POSTURE_MAX":6}}}},"PhoneNumber":{"fields":{"number":{"type":"string","id":1}}}}}}}}},"google":{"nested":{"protobuf":{"nested":{"Empty":{"fields":{}}}}}}}} as const;