@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,376 @@
1
+ # Plan: Android Emulator trong PPM
2
+
3
+ Ngày: 2026-09-20. Trạng thái: **đề xuất triển khai, chưa viết tính năng**.
4
+ Đối chiếu repository tại `641da958`; nghiên cứu tài liệu và mã nguồn upstream ngày 2026-09-20.
5
+
6
+ ## 1. Kết quả cần đạt
7
+
8
+ Người dùng mở **Android** trong PPM, chọn máy ảo, bấm Start/Open và thao tác trực tiếp: chạm, vuốt, giữ, gõ chữ, Home/Back/Recent, xoay màn hình. Mỗi máy có tab riêng; desktop có thể pop-out/PiP theo cơ chế sẵn có, điện thoại dùng giao diện cảm ứng. Emulator chạy trên máy host cài PPM; trình duyệt chỉ hiển thị và gửi thao tác.
9
+
10
+ Phạm vi mặc định: Android Emulator chính thức/AVD trên cùng host PPM; Linux trước để xác minh, Windows và macOS là các nền tảng phải kiểm chứng trước khi công bố hỗ trợ. Hai máy ảo độc lập là bài kiểm tra thiết kế; mặc định giới hạn một máy do PPM khởi động đồng thời để tránh chiếm tài nguyên host. Có thể tăng giới hạn sau kiểm tra RAM/CPU.
11
+
12
+ Không yêu cầu Android Studio đang mở. SDK, system image và AVD có thể dùng chung với Studio. Không cam kết toàn bộ tính năng của Studio: debugger, profiler, Gradle integration, camera/AR/XR và device farm nằm ngoài bản đầu. Điện thoại USB/Wi-Fi là giai đoạn mở rộng, chưa phải yêu cầu đã chốt.
13
+
14
+ ## 2. Android Studio thực sự làm gì
15
+
16
+ | Bằng chứng upstream | Bài học áp dụng cho PPM |
17
+ |---|---|
18
+ | `EmulatorController.kt` kết nối localhost gRPC, gắn credentials, quản lý trạng thái và gọi các dịch vụ emulator | Backend PPM giữ kết nối native và thông tin xác thực; browser dùng API PPM. [S1] |
19
+ | `EmulatorView.kt` yêu cầu `streamScreenshot` ở định dạng `RGB888`, kích thước theo vùng hiển thị; hủy feed cũ khi thay đổi | Lấy màn hình trực tiếp từ emulator, scale theo viewport; không chụp cửa sổ desktop. [S2] |
20
+ | View chuyển chuột/phím/touch thành sự kiện emulator | Viết bộ chuyển input Android riêng; không dùng bộ inject input vào OS của Remote Desktop. [S2] |
21
+ | `emulator_controller.proto` có screenshot, input, clipboard, VM state, rotation/display metadata và timestamp | Có cơ sở xây tab tương tác; phải pin schema và probe năng lực từng phiên bản. [S3] |
22
+ | Device Manager quản lý AVD, cấu hình phần cứng và system image | Tách **danh sách máy/config** khỏi **phiên đang chạy/viewer**. [S4] |
23
+ | Tài liệu CLI minh họa Studio dùng `-qt-hide-window`, `-grpc-use-token`, `-idle-grpc-timeout` | Flags phụ thuộc phiên bản; kiểm tra `-help` trên binary thật, không copy cứng hoặc nhầm “ẩn cửa sổ” với “headless”. [S5] |
24
+
25
+ Đính chính đề xuất ban đầu: **chưa có căn cứ nói Android Studio dùng scrcpy cho embedded emulator**. Nguồn đã đọc cho thấy gRPC + screenshot feed. Scrcpy là một phương án của PPM, không phải mô tả kiến trúc Studio.
26
+
27
+ Phần khác biệt cần tự thiết kế: Studio và emulator ở cùng máy; PPM có browser qua LAN/tunnel. Một frame RGB 720×1280 cần 2,764,800 byte; 30 fps xấp xỉ 83 MB/s trước overhead. Không chuyển raw RGB qua Internet. Con số là phép tính dung lượng, không phải benchmark.
28
+
29
+ Google cũng có demo browser dùng gateway nối gRPC `rtc2` và WebRTC. Đây là hướng tham khảo riêng cho web, không đồng nghĩa embedded Studio dùng WebRTC. Proto `rtc_service_v2.proto` trên SDK máy này ghi rõ API experimental. [S6]
30
+
31
+ ## 3. Bằng chứng tại máy và repository
32
+
33
+ Kiểm tra read-only, chưa boot/stop AVD và chưa thử phiên streaming:
34
+
35
+ - Emulator: `/home/thawngho/Android/Sdk/emulator/emulator`, phiên bản **36.5.10.0**, build **15081367**.
36
+ - `-list-avds`: **Pixel_9**, **Pixel_Tablet**.
37
+ - `-accel-check`: **KVM installed and usable**; chưa xác minh GPU rendering hoặc tốc độ boot.
38
+ - ADB trên PATH: `/usr/bin/adb`, **1.0.41**, package **37.0.0-android-tools**. Khi triển khai cần chọn một ADB nhất quán với SDK; không thay server ADB đang chạy chỉ vì phát hiện khác phiên bản.
39
+ - SDK có `emulator_controller.proto`, `rtc_service.proto`, `rtc_service_v2.proto`, snapshot/UI protos. Có file không chứng minh RPC hoạt động trên binary: phase 0 phải gọi thử.
40
+ - PPM có Hono/Bun WS, ffmpeg, WebCodecs viewer, tab pool và pop-out. Remote Desktop session hiện thu hồi **mọi** session khác khi mở phiên mới; không thể dùng nguyên manager này cho Android.
41
+ - TabPool giữ tab ẩn mounted. Phải ngừng feed/release input theo visibility thực tế, không chỉ cleanup khi unmount.
42
+ - Decoder Remote Desktop đang tạo timestamp theo 30 fps; chưa phải pipeline đồng bộ audio/video.
43
+ - `.claude/workflows/*`, `.ck.json` và biến `CK_PLAN_DATE_FORMAT` không có trong checkout này. Plan dùng `YYMMDD` theo tên tài liệu hiện có; áp dụng `CLAUDE.md`, roadmap, code/design standards đã có.
44
+
45
+ ## 4. Quyết định kiến trúc / ADR đề xuất
46
+
47
+ ### ADR-A: Backend native gRPC cho emulator
48
+
49
+ **Ưu tiên:** Bun service gọi emulator gRPC; ADB dùng discovery/boot readiness, cài APK và logcat. SDK command-line tools quản lý AVD khi tới giai đoạn quản lý máy.
50
+
51
+ > **Đính chính sau Phase 3 (2026-09-21, đo thật):** logcat **không** đi qua `adb logcat` như câu
52
+ > trên viết, mà qua gRPC `streamLogcat` — dùng lại đúng channel đã xác thực, không thêm tiến
53
+ > trình con mỗi máy, và có sẵn cả khi adb serial còn `null` lúc máy đang boot. Theo chính comment
54
+ > trong proto, `streamLogcat` chạy `logcat` trong guest qua `AdbShellStream`, nên dữ liệu là một.
55
+ > Cái mất là không đẩy được filter xuống thiết bị. **Cài APK thì vẫn đi adb** đúng như trên, vì
56
+ > `EmulatorController` không có RPC install nào. Hai phép đo đi kèm, cả hai đều trái với thứ đọc
57
+ > proto ra: `LogMessage.sort = Parsed` **không được cài đặt** và hỏng bằng cách gửi stream rỗng
58
+ > (334 message trống trong 8 s, không lỗi), còn unary `getLogcat` trả `12 UNIMPLEMENTED`. Xem
59
+ > `android-emulator-phase3-report-260921.md` §2.
60
+
61
+ Lý do: phù hợp emulator-first và học đúng ranh giới từ Studio; không cần cài server vào Android guest cho đường chính. Rủi ro: schema/auth/discovery thay đổi; thư viện gRPC Node không mặc nhiên tương thích Bun/binary compiled. Thử `@grpc/grpc-js` với protobuf client được generate/pin trước; chỉ thêm dependency sau spike. Không tự viết lại HTTP/2/gRPC, không đổi backend sang Go hay thêm Python service mặc định. [S9]
62
+
63
+ Chỉ chọn subset RPC cần dùng nhưng giữ nguồn/schema, revision và license. Không tải proto tùy ý từ mạng lúc chạy.
64
+
65
+ **Cấm `protoLoader.loadSync()`.** Nó đọc file `.proto` từ đĩa lúc chạy, và trong binary
66
+ `bun build --compile` đường dẫn trỏ vào `/$bunfs/root/` nên ném `ENOENT` — đo được ở Phase 0, đúng
67
+ bài học "compiled PPM không với tới node_modules của chính nó" trong CLAUDE.md. Đường duy nhất là
68
+ `protoLoader.fromJSON()` với descriptor JSON sinh lúc build và `import` vào module để bundler nhúng.
69
+ Đã chứng minh: binary chạy từ thư mục ngoài checkout trả `getStatus` trong 17.5 ms và pass toàn bộ
70
+ bài cancellation/deadline/cleanup y hệt bản chạy từ source. Tạo compatibility record gồm emulator version, auth mode, RPC capabilities và lỗi có hướng xử lý.
71
+
72
+ ### ADR-B: Media qua WebSocket cùng origin là đường cơ sở
73
+
74
+ | Phương án | Ưu điểm | Chi phí / kết luận |
75
+ |---|---|---|
76
+ | gRPC RGB → ffmpeg H.264 → WSS → WebCodecs | Input/lifecycle giống Studio; đi cùng đường truy cập PPM | Encode thêm trên host, copy frame, xử lý resize; **phương án ưu tiên cần benchmark** |
77
+ | Native emulator WebRTC + signaling qua PPM | Browser media stack, có khả năng giảm encode trung gian | API experimental; ICE/TURN, NAT và chính sách thu hồi phiên cần kiểm chứng; để mở rộng sau |
78
+ | Scrcpy server → H.264 qua ADB → WSS | Luồng nén từ guest, dùng được cho máy thật | Client/server phải khớp phiên bản, deploy artifact vào guest; **contingency nếu gRPC media không đạt** [S7] |
79
+ | gRPC PNG → WSS → canvas | Dễ xác minh correctness, không phụ thuộc VideoDecoder | Băng thông/CPU lớn; chế độ tương thích giới hạn kích thước và fps, không dùng làm chuẩn hiệu năng |
80
+ | **gRPC MMAP side channel → ffmpeg → WSS** | Pixel không đi qua grpc-js chút nào; gRPC chỉ mang `seq`/`timestampUs` | `ImageTransport.MMAP` (`emulator_controller.proto` field 6): client sở hữu handle shm/mmap. Đo được 318/318 frame có pixel thật, **0 byte** qua gRPC. Proto tự cảnh báo *"the mmap can result in tearing"*. **Để dành**, chưa cần ở v1 |
81
+
82
+ **Quyết định (Phase 0, 2026-09-21): giữ option 1 làm đường chính.** Đo trên host Linux, emulator
83
+ 36.5.10, Bun 1.3.11, `@grpc/grpc-js` 1.14.0, với chuyển động liên tục thật: RGB888 720×1600 đạt
84
+ **39.9 fps / 131.9 MiB/s**, full-res 1080×2400 đạt **40.0 fps / 297.4 MiB/s**, **không rớt frame nào**
85
+ (seq liên tục). Pipeline đầy đủ ra **360/360 frame** decode được ở **3.90 Mbit/s**. `h264_vaapi` tốn
86
+ **0.33 core** so với 64–80% của libx264. Ngưỡng 83 MB/s mà plan lo không phải là ngưỡng. Không
87
+ chuyển sang scrcpy. Chi tiết: `docs/architecture/android-emulator-phase0-report-260921.md`.
88
+
89
+ Ba chi tiết schema phải tôn trọng khi hiện thực hoá — cả ba đều đã được **đo lại ở Phase 2**, và
90
+ hai trong số đó hoá ra đoạn văn cũ ở đây ghi sai:
91
+
92
+ 1. `ImageFormat.width/height` là **hộp bao giữ tỉ lệ**, không phải kích thước ra lệnh (proto:
93
+ *"will never exceed the given width, but can be less"*). Phải xin hộp **vuông** để trần áp lên
94
+ cạnh dài, và đọc kích thước thật từ `format.width/height` của chính frame — đó là trường
95
+ output, và cũng là thứ khiến việc xoay màn hình chạy đúng mà không phải đoán.
96
+ 2. ~~Thứ tự pixel là bottom-up nên phải có `vflip`~~ — **sai**. Câu đó chép từ comment trong
97
+ proto. So từng hàng với `adb exec-out screencap` trên emulator 36.5.10: khớp ở mức chênh lệch
98
+ **1.21**/pixel khi căn thẳng và **37.15** khi lật. Buffer là **top-down**; thêm `vflip` làm mọi
99
+ màn hình lộn ngược mà không báo lỗi.
100
+ 3. Sau khi một `streamScreenshot` bị cancel, mọi stream mở sau đó trả **đúng 1 frame** rồi im, kể
101
+ cả trên channel mới. Nên đổi mức chất lượng **không được** mở lại stream: mở đúng một stream ở
102
+ trần rung cao nhất cho cả phiên, đổi rung bằng `scale` trong ffmpeg.
103
+
104
+ Và một chi tiết input: `Touch.x/y` luôn là **pixel panel gốc chưa xoay**, không đổi theo hướng màn
105
+ hình (đo bằng `getevent`), nên toạ độ trên frame đã xoay phải được xoay ngược lại trước khi gửi.
106
+
107
+ Chỉ productize một đường chính; không xây đồng thời ba backend. Nếu raw→H.264 không đạt ngân sách, ghi ADR cập nhật rồi chuyển sang scrcpy cho video/control thay vì kết hợp input của backend này với geometry backend khác chưa được kiểm chứng.
108
+
109
+ WebSocket được Cloudflare hỗ trợ; cần heartbeat và reconnect vì kết nối có thể bị ngắt. WebRTC media đi qua tuyến ICE riêng; việc trang PPM mở được qua tunnel không chứng minh media WebRTC tới được. Không mặc định yêu cầu người dùng dựng TURN. [S6, S10]
110
+
111
+ ### ADR-C: Module nội bộ độc lập, lazy-load
112
+
113
+ Đặt backend trong `src/services/android/`, UI trong `src/web/components/android/`. Dùng route/tab riêng; chỉ trích xuất tiện ích codec thực sự dùng chung. Runtime registry theo device, không tạo framework plugin mới.
114
+
115
+ Đây là bước thực dụng theo hiện trạng: extension RPC/webview hiện chưa có media/control capability đã được chứng minh. Giữ API service có ranh giới rõ để có thể chuyển thành plugin khi nền tảng hỗ trợ. Không nới quyền spawn toàn cục của extension chỉ để gọi emulator.
116
+
117
+ ### ADR-D: Vòng đời emulator tách khỏi viewer
118
+
119
+ Đóng tab/refresh/mất mạng không stop emulator. Stop là hành động riêng, chỉ áp dụng máy PPM sở hữu; máy attach từ Studio mặc định chỉ Disconnect. Không kill ADB server, không kill theo tên process.
120
+
121
+ ## 5. Luồng và hợp đồng nội bộ
122
+
123
+ ```mermaid
124
+ flowchart LR
125
+ B[Android tab trong browser] <-->|HTTPS: máy và tác vụ| H[PPM Hono API]
126
+ B <-->|WSS: input, trạng thái, video nén| W[Android session manager]
127
+ H --> D[Device registry và lifecycle]
128
+ D --> T[SDK tools và ADB]
129
+ W -->|input và trạng thái| G[gRPC adapter localhost]
130
+ G <--> E[Android Emulator]
131
+ G -->|RGB frames nội bộ host| F[ffmpeg encoder]
132
+ F -->|H.264 access units| W
133
+ T --> E
134
+ ```
135
+
136
+ Đồ thị là phương án ADR-B ưu tiên; thay media adapter nếu phase 0 chọn khác.
137
+
138
+ **Identity:** `avdId` dựa trên canonical AVD config path + SDK context; ID opaque cấp bởi server. `deviceId` chỉ runtime instance, đi cùng `generation`, ADB serial, PID/start identity và gRPC endpoint. Không dùng ADB serial làm ID tab bền vững. Restart máy làm runtime identity thay đổi nhưng vẫn mở lại đúng AVD.
139
+
140
+ **State máy:** `stopped → starting → booting → ready → stopping → stopped`; lỗi boot thành `error`, ADB offline hiện riêng. **State viewer:** `disconnected → connecting → viewing/controlling → paused/reconnecting/error`. Khả năng video sẵn sàng có thể trước Android boot-complete; install APK chỉ khi guest ready.
141
+
142
+ **Discovery:** SDK path do người dùng chọn → env Android SDK phù hợp → vị trí chuẩn OS/PATH. Tôn trọng AVD home overrides — nhưng **`ANDROID_AVD_HOME` thay thế chứ không cộng dồn**: set nó thì AVD của người dùng biến mất khỏi `-list-avds`, nên PPM không được set biến này toàn cục (đo ở Phase 0). Và **không bao giờ truyền `-grpc <port>`**: `emulator -help` ghi `-grpc-use-jwt ... (default, disable with -grpc flag)`, nên ghim port cố định chính là tự hạ kênh điều khiển xuống không xác thực — luôn discovery. Thực tế gRPC đã bật sẵn không cần cờ nào (`Started GRPC server at 127.0.0.1:8554, security: Local, auth: +token`), và emulator tự cảnh báo *"Basic token auth should only be used by android-studio"*, nên PPM đi đường JWT. Đọc discovery files của emulator user hiện tại với giới hạn kích thước; xác minh PID/process identity, AVD và endpoint loopback trước sử dụng. Không giả định mọi OS/version dùng một đường dẫn `avd/running`. Credentials chỉ nằm backend. Hỗ trợ token/JWT theo phiên bản đã test, báo unsupported nếu chưa có; không hạ xuống unauthenticated khi thất bại. [S8]
143
+
144
+ **Lifecycle:** mutex theo AVD + start idempotency; refresh/chạm Start hai lần không spawn hai process. Dùng argv, deadline boot có cấu hình, log ring buffer, cancellation. Timeout cho lựa chọn Retry/Stop rõ ràng; chỉ xử lý process được task đó tạo. Kiểm tra AVD đang được Studio dùng, không xóa lock file để cưỡng ép chạy.
145
+
146
+ **PPM restart:** không tự boot máy theo restored tab. Runtime registry được dựng lại từ discovery + ownership record tối thiểu; kiểm tra PID start identity để tránh PID reuse. Encoder/viewer session kết thúc, emulator do PPM tạo được giữ chạy và nhận lại nếu runtime/process ownership còn hợp lệ. Phase 0 phải thử thực tế hành vi process group/service shutdown trên từng OS; khi chưa xác minh thì không quảng cáo giữ máy xuyên restart.
147
+
148
+ **Session:** một controller lease trên mỗi runtime device; client thứ hai bị báo đang sử dụng, có hành động Take control rõ ràng. V1 chưa cần nhiều viewer thụ động. Hai device có hai session độc lập; tuyệt đối không ngắt Remote Desktop hay máy khác. Lease đề xuất heartbeat 5 giây, expire 15 giây; server hết lease phải giải phóng input. Reconnect lấy nonce mới và không replay thao tác cũ. Server cấp capability reconnect ngắn hạn, chỉ giữ trong memory của browser, bind session/device/token generation; reconnect hợp lệ thay socket cũ nguyên tử, không đợi lease hết hạn. Take control tăng generation, hủy cả pending auth/reconnect của controller cũ. Refresh mất capability thì chờ lease hoặc Take control chủ động; mục tiêu reconnect 5 giây chỉ áp dụng kết nối còn capability hợp lệ.
149
+
150
+ **API dự kiến (tên có thể điều chỉnh theo convention repository):**
151
+
152
+ | Endpoint | Contract chính |
153
+ |---|---|
154
+ | `GET /api/android/capabilities` | SDK/tool versions, host accel, streaming/backend readiness, lý do thiếu |
155
+ | `GET /api/android/devices` | AVD + runtime instance, state, ownership và capabilities; không token/đường dẫn nhạy cảm |
156
+ | `POST /api/android/avds/:avdId/start` | Validated launch profile, idempotency key → operation ID |
157
+ | `GET /api/android/operations/:id` | Pending/progress/result/error; client reconnect không khởi động lại operation |
158
+ | `POST /api/android/devices/:deviceId/stop` | Check generation và ownership, graceful stop → operation ID |
159
+ | `POST /api/android/devices/:deviceId/sessions` | Viewport/codec capabilities → session ID + nonce ngắn hạn |
160
+ | `WS /ws/android` | Auth đầu tiên, device/session binding; JSON control + binary video |
161
+ | `DELETE /api/android/sessions/:id` | Đóng viewer/idempotent, không stop máy |
162
+ | Phase 3: install/screenshot/logcat | API typed riêng, không mở generic shell/RPC proxy |
163
+ | Phase 4: AVD create/delete/wipe | Thao tác riêng, xác nhận target và hậu quả |
164
+
165
+ HTTP dùng `ok/err` hiện có. Các thao tác lâu trả operation ID, không giữ HTTP request chờ boot nhiều phút. Discovery khi Android UI hoạt động có interval/backoff giới hạn; feature chưa dùng không spawn/poll liên tục.
166
+
167
+ **WS envelope phiên bản 1:** auth, ready, geometry, input, input-reset, quality, visibility, heartbeat, error; metadata gồm session generation và geometry generation. Binary video có version, generation, sequence, timestamp/PTS, config/keyframe flag, kích thước payload. Final layout ghi trong `src/shared/android-protocol.ts` và test với fixture trước khi viết UI. Không gửi base64 video trong JSON.
168
+
169
+ **Media:** một encoder mỗi active device; RGB chỉ trong host. Giới hạn frame dimensions, message size và pending buffers. Không block Bun loop bằng encode sync. Trước encode chỉ giữ latest frame; ffmpeg rawvideo stdin không có frame header nên một khi bắt đầu write phải hoàn tất frame đó, kể cả partial write/backpressure. Chỉ drop nguyên frame chưa bắt đầu; validate stride, pixel layout và kích thước. Sau encode không drop delta tùy ý rồi tiếp tục decode: bỏ đến keyframe hợp lệ hoặc restart/request keyframe. Resize/rotation bắt đầu generation mới, gửi codec config + keyframe, bỏ late frames từ generation cũ. Duy trì timestamp monotonic từ pipeline; chưa thêm audio ở v1.
170
+
171
+ ## 6. UX và input
172
+
173
+ **Device Manager:** danh sách AVD: tên, loại phone/tablet, API/ABI, trạng thái, Start/Open/Disconnect/Stop theo ownership. Empty state phân biệt chưa có SDK, thiếu emulator/system image, chưa có AVD, acceleration không dùng được. Không spinner vô thời hạn.
174
+
175
+ **Viewer:** toolbar Home, Back, Recent, Rotate, Volume, Power, Fit/100%, Disconnect; hiển thị trạng thái kết nối và lựa chọn chất lượng. Stop nằm trong menu riêng. Action chưa được backend hỗ trợ có lý do rõ ràng. Phase 3 thêm Screenshot, Install APK và Logcat ở panel phụ.
176
+
177
+ **Mobile:** viewport giữ đúng aspect ratio; nút điều khiển chính ở dưới, target ≥44×44; menu/dialog dùng bottom sheet. Có nút Keyboard và vùng nhập text dùng IME. Pinch trên màn hình Android gửi multi-touch khi bật chế độ tương tác; zoom viewer có chế độ riêng để hai hành vi không xung đột.
178
+
179
+ **Input correctness:**
180
+
181
+ - Pointer capture, ID ổn định cho nhiều ngón; down/move/up/cancel; long press và drag dựa trên thời gian thực, không lặp `adb shell input` mỗi frame.
182
+ - Ánh xạ CSS bounds/letterboxing → frame hiển thị → native display coordinates. Xét DPR, rotation, resize, display metadata. Reject input theo geometry cũ; cancel gesture khi geometry đổi.
183
+ - Pointer cancel, blur, tab hidden, mất controller, disconnect đều release keys/touches. Timeout server là lớp dự phòng cho browser mất mạng không gửi được release.
184
+ - Phân biệt physical key với text/IME (`beforeinput`, composition). **Phase 0 đo được: `sendKey.text` chỉ mang ASCII in được [32-127).** `"café"` tới nơi thành `"caf"`, còn tiếng Việt, emoji và CJK mất sạch — không lỗi, chỉ cắt cụt âm thầm. `setClipboard` giữ nguyên `"Tiếng Việt 😀"` (xác minh cả round-trip lẫn nhìn trong guest). Nên **mọi ký tự ngoài ASCII phải đi đường clipboard**, không phải `text`; đó là ràng buộc thiết kế của IME mobile ở phase 2, không phải chi tiết tối ưu.
185
+ - Clipboard là thao tác copy/paste chủ động giữa browser và guest, không bật đồng bộ clipboard OS host mặc định. Giữ nguyên giới hạn quyền clipboard của browser.
186
+ - Không chiếm shortcut PPM khi canvas không focus. PiP dùng đúng ownerDocument/window, không gắn listener cứng vào document chính.
187
+
188
+ `VideoDecoder` phụ thuộc secure context và codec thực tế. Probe `isConfigSupported`; HTTPS/localhost dùng H.264 khi có. Browser không hỗ trợ hoặc LAN HTTP có chế độ PNG tốc độ thấp, ghi nhãn chất lượng rõ ràng; nếu không đạt mức dùng được thì báo hướng mở HTTPS/trình duyệt hỗ trợ, không để màn hình đen. Backend được chọn phải chứng minh được screenshot fallback: gRPC dùng PNG, nếu chọn scrcpy thì thử ADB screenshot có giới hạn tần suất/độ phân giải; không giữ thêm toàn bộ gRPC stack chỉ để fallback. [S11]
189
+
190
+ ## 7. Bảo vệ phiên và dữ liệu
191
+
192
+ Đây là yêu cầu chức năng của kênh điều khiển host/device, không phải bổ sung hệ thống phân quyền nhiều người dùng.
193
+
194
+ - Bắt buộc PPM auth enabled; validate Origin đầy đủ ở upgrade và tạo phiên, có allowlist dev proxy cụ thể. Không copy kiểm tra chỉ hostname của Remote Desktop như bảo đảm same-origin chung. **Phase 0 xác nhận câu trên đúng:** `assertSessionAllowed` trong `src/server/routes/remote-desktop.ts:28-46` so sánh **hostname, bỏ qua port**, có chủ ý và có comment — dev proxy của Vite ghi đè `Host` mà không thêm `X-Forwarded-Host`, nên so cả `host:port` sẽ chặn mọi phiên dev. Android dùng lại đúng khuôn đó, nhưng phải nhớ nó **không** phải bảo đảm same-origin đầy đủ: một trang khác **port** trên cùng hostname vẫn qua được.
195
+ - Nonce single-use TTL đề xuất 30 giây, bind auth context, device/generation, session và quyền control. Chưa auth không tạo encoder/gRPC session; auth timeout đề xuất 5 giây. PPM hiện dùng bearer token chung, không giả định đã có user/session identity phía server: logout browser phải gửi close/release, server có lease expiry dự phòng; token đổi/auth tắt thu hồi toàn bộ Android sessions.
196
+ - RPC chỉ gọi endpoint loopback server đã discovery; browser không nhập URL gRPC hay command tùy ý. Không public ADB/gRPC/TURN credentials qua API/logs.
197
+ - Bound control message size, input rate, video/encoder allocation và concurrent operations. Không nuốt key-up/cancel vì rate limiting; quá tải thì reset input.
198
+ - Cài APK nhận upload ID hoặc file qua existing path guards; xác thực đích, quota, deadline, cleanup temp qua `getPpmDir()`. Không cho upload chọn đường ghi tự do. Không tự uninstall app khi install lỗi chữ ký.
199
+ - Log chỉ metadata/errors, phiên bản, latency/bytes/drop counts; không lưu màn hình, clipboard hay text gõ mặc định.
200
+ - AVD/SDK người dùng hiện có giữ vị trí native Android; dữ liệu quản lý/cache riêng PPM qua `getPpmDir()`. Tests dùng SDK/AVD home giả và `PPM_HOME` tạm.
201
+
202
+ ## 8. Bản đồ thay đổi code
203
+
204
+ Tất cả đường dẫn Android dưới đây là **dự kiến tạo**, chưa tồn tại.
205
+
206
+ | Phần | Điểm tích hợp |
207
+ |---|---|
208
+ | Backend Android | `src/services/android/`: sdk-discovery, device-registry, emulator-launcher, grpc-client/auth, session-manager, input, video-pipeline, operations |
209
+ | Schema/protocol | `src/shared/android-protocol.ts`, generated/pinned protobuf dưới module Android; build-time generate, runtime không cần protoc |
210
+ | HTTP/WS | `src/server/routes/android.ts`, `src/server/ws/android.ts`; đăng ký Hono/upgrade/dispatch trong `src/server/index.ts` |
211
+ | UI | `src/web/components/android/`: manager, tab, viewport, toolbar, input hooks, setup; lazy-loaded |
212
+ | Tab registry | `src/web/stores/tab-store.ts`, `panel-utils.ts`, `components/layout/tab-pool.tsx`, `tab-content.tsx` |
213
+ | Pop-out/icon/navigation | `window-panel-persistence.ts`, `lib/tab-type-icons.ts`, nav rail/mobile drawer/command palette; dùng `tab-host` sẵn có |
214
+ | Settings | `settings-categories.ts`, `settings-section-content.tsx`, settings routes, `src/types/config.ts`, config service |
215
+ | Codec reuse | Remote Desktop H.264 decoder/SPS/NAL helpers: trích xuất phần thuần dùng chung nếu cần, giữ regression tests đường cũ |
216
+ | Packaging | `package.json`, `.npmignore`, build/release pipeline, third-party notices; kiểm tra npm và compiled binary |
217
+
218
+ SDK path/default launch limits là host config trong KV hiện có; fit/quality là preference từng browser. Chưa cần migration DB mới hoặc ấn định migration number. Chỉ lưu ownership metadata tối thiểu nếu restart reconciliation thực sự cần; không lưu secret hoặc process handle trong workspace JSON.
219
+
220
+ ## 9. Các giai đoạn và điều kiện hoàn thành
221
+
222
+ ### Phase 0 — Chứng minh protocol, runtime và media
223
+
224
+ - Tạo spike riêng, scratch PPM_HOME và test AVD do task tạo; không sửa Pixel_9/Pixel_Tablet của người dùng để test destructive flows.
225
+ - Pin emulator/proto/dependency versions; đọc help thực tế, kiểm chứng discovery/token hoặc JWT, `getStatus`, screenshot, touch/key/text, rotation. So sánh tọa độ bằng test app có điểm chạm hiển thị.
226
+ - Chạy gRPC dưới Bun source **và compiled PPM**, working directory ngoài checkout; chứng minh cancellation/deadline/resource cleanup.
227
+ - Đo gRPC RGB→ffmpeg→H.264→browser; PNG làm correctness baseline. Có fixture stdin slow-consumer/partial writes để xác minh frame boundary. Nếu không đạt, benchmark scrcpy candidate và screenshot fallback tương ứng; native WebRTC chỉ spike phụ khi có lý do, không làm dependency để hoàn thành v1.
228
+ - Đo trên LAN và PPM tunnel: fps khi có chuyển động, bitrate, click-to-visible p50/p95, CPU/RSS của PPM + encoder riêng và emulator riêng, ảnh hưởng chat/terminal, rotation, hide/resume.
229
+ - Output: report versions/commands/numbers, quyết định media, giới hạn browser/OS, schema/auth compatibility. **Gate:** boot/stream/control/cleanup thật và ngân sách sơ bộ đạt; chưa đạt thì sửa ADR trước phase 1.
230
+
231
+ ### Phase 1 — SDK discovery và vòng đời máy
232
+
233
+ - Capabilities/setup diagnostics; list AVD/runtime, Start/Open/Stop có ownership, trạng thái và operation progress.
234
+ - Registry identity, per-AVD mutex, timeouts, stderr bounded, port/discovery races và restart reconcile.
235
+ - Gate: start đúng một máy, không double spawn; attach máy ngoài không nhận quyền stop; lỗi SDK/KVM/boot actionable; không tác động ADB/AVD khác.
236
+
237
+ ### Phase 2 — Tab hiển thị và điều khiển hoàn chỉnh
238
+
239
+ - Dedicated route/WS auth + lease, media adapter đã chọn, viewport và Android input.
240
+ - Toolbar cơ bản, Unicode/IME, multi-touch, rotation, quality, pause/resume, disconnect/reconnect.
241
+ - Tích hợp tab, pop-out/PiP và mobile; fallback browser; không bật emulator khi restore workspace.
242
+ - Gate: nghiệm thu tình huống 1–9 và 11 bên dưới trên served build. Đây là bản đầu có thể dùng để thao tác máy ảo hằng ngày; tình huống 10 thuộc phase 3, tình huống 12 thuộc phase 4.
243
+
244
+ > **Đính chính sau khi người dùng thử thật (đo 2026-09-21).**
245
+ > Ba lỗi, cả ba **không sinh ra một dòng lỗi nào** ở bất kỳ tầng nào:
246
+ > 1. **Ảnh cuộn/méo từ khung thứ hai trở đi.** `FileSink.write()` của Bun nhận trọn chunk và trả
247
+ > về một con số **không phải** "đã ghi bao nhiêu byte của chunk này". Vòng `off += n` vì thế
248
+ > gửi lại phần đuôi nhiều lần: đo bằng `cat`, một khung 4.924.800 byte tới nơi thành
249
+ > **28.043.840 byte (5,7×)**. Luồng rawvideo vào ffmpeg lệch vĩnh viễn — khung **đầu** vẫn
250
+ > đúng, mọi khung sau bị vẽ cuộn. Ghi **một lần** rồi `flush()`. Test phải đo **byte tới nơi**,
251
+ > không đếm khung: mọi bộ đếm trong pipeline đều báo đúng trong khi ffmpeg nhận gấp 5,7 lần.
252
+ > 2. **Màn hình đứng yên thì không có video.** `streamScreenshot` là *change-driven*: đo được
253
+ > **2 khung trong 15 giây** trên một máy nằm ở launcher. Chỉ nạp ffmpeg khi có khung mới nghĩa
254
+ > là luồng H.264 im hẳn, và người vào xem lúc đó kẹt ở "Waiting for the first frame…" cho tới
255
+ > khi có gì đó động đậy trong guest. Phải **nạp lại khung cuối theo nhịp fps** của rung. E2E cũ
256
+ > không thấy vì nó chạy kèm một vòng swipe liên tục.
257
+ > Nhưng nhịp đầy đủ không miễn phí: đo trên máy đứng im, một viewer giữ ffmpeg ở **55% một
258
+ > core** — mỗi khung rgb24 đều bị scale và hwupload lại dù không một pixel nào đổi. Lùi về 10
259
+ > fps sau 1 giây không đổi thì còn **11,7 khung/s vào ffmpeg, 23% một core**, trong khi client
260
+ > vẫn nhận **24,9 access unit/s**: demuxer rawvideo khai 25 fps nên CFR mặc định của ffmpeg
261
+ > nhân bản khung để bù lại, mà khung nhân bản gần như không tốn gì — phần đắt nằm ở mỗi khung
262
+ > *đầu vào*. Hệ quả cần biết: **tốc độ trên dây luôn là 25 fps**, không phải `fps` của rung
263
+ > (24/30/30), và `-g = fps/2` vì thế là GOP 0,6 s chứ không phải 0,5 s. Chưa sửa — muốn đúng
264
+ > thì phải đặt `-framerate` cho input, và đó là thay đổi ngoài phạm vi ba lỗi này.
265
+ > 3. **`avd.id` mới là danh tính, không phải `avd.name`.** File discovery có cả hai, và với mọi AVD
266
+ > tạo bằng Android Studio chúng khác nhau: `avd.id=Pixel_9` cạnh `avd.name=Pixel 9`. Khớp theo
267
+ > tên hiển thị thì emulator đang chạy không khớp được dòng AVD của chính nó — danh sách hiện
268
+ > máy là "stopped" *và* mọc thêm một dòng `external:` không có geometry. Không thấy suốt 4 phase
269
+ > vì mọi AVD dùng để test đều tên một từ, nơi hai trường trùng nhau.
270
+
271
+ ### Phase 3 — Công cụ làm việc với app
272
+
273
+ - Install APK bằng picker/upload và chọn file project; progress/cancel, lỗi ABI/minSdk/chữ ký, split APK chỉ nếu có workflow rõ ràng.
274
+ - Screenshot tải về; clipboard chủ động; Logcat theo device với filter, pause/clear-view và ring buffer, không ghi vô hạn vào DB.
275
+ - Gate: install đúng target khi có hai máy; hủy upload không để temp; logs hidden ngừng subscription; không log nội dung input/clipboard.
276
+
277
+ ### Phase 4 — Device Manager đầy đủ hơn
278
+
279
+ - Tạo AVD từ system image đã cài, chọn phone/tablet profile, ABI theo host, RAM/storage hợp lý. Các API typed bọc SDK tools, không nối chuỗi shell.
280
+ - **Bắt buộc ghi `hw.keyboard=yes` vào `config.ini`.** `avdmanager` mặc định `no` (Studio thì `yes`), và khi tắt thì touch gRPC vẫn chạy hoàn hảo trong khi `sendKey` trả `OK` và **không một ký tự nào tới guest** — không lỗi, không log. Đã loại trừ allowlist và `-no-window` bằng thực nghiệm ở Phase 0.
281
+ - Cold boot, quick-boot policy; quản lý snapshot là task riêng, serialize với start/stop. Wipe/Delete có xác nhận tên máy và hậu quả, chỉ khi stopped.
282
+ - Có thể cài system image qua UI sau khi hiển thị dung lượng, license và tiến trình; không tự chấp nhận SDK license hay tải nhiều GB khi mở tab. SDK tools có `sdkmanager`/`avdmanager`; tài liệu mới cũng giới thiệu Android CLI, nên probe tool có sẵn và pin đường được test. [S4, S5, S12, S13]
283
+ - Gate: tạo→boot→stop→mở lại giữ dữ liệu; wipe/delete chỉ trúng AVD đã chọn; không sửa AVD Studio đang chạy. Không cần build lại toàn bộ SDK Manager của Studio.
284
+
285
+ > **Đính chính sau Phase 4 (đo 2026-09-21, xem `android-emulator-phase4-report-260921.md`).**
286
+ > Ba điều plan không nói, và cả ba đều hỏng **im lặng**:
287
+ > 1. `ANDROID_AVD_HOME` phải trỏ vào một thư mục **có thật**. Trỏ vào thư mục không tồn tại thì
288
+ > `avdmanager` không báo lỗi — nó quay về `~/.android/avd`, tức thư mục AVD **thật của người
289
+ > dùng**, và ghi AVD vào đó. Giống hệt trường hợp không set biến này cho tiến trình con.
290
+ > `createAvd` phải `mkdir -p` avdHome trước, và vẫn kiểm tra `config.ini` có hiện ra đúng chỗ.
291
+ > 2. **Wipe không được xoá `userdata.img`.** `emulator -help-disk-images` xếp nó vào nhóm ảnh
292
+ > *khởi tạo* cùng `system.img`, và định nghĩa `-wipe-data` là *copy nội dung của userdata.img
293
+ > vào userdata-qemu.img* — xoá nó là xoá bản gốc mà wipe cần để khôi phục.
294
+ > 3. `hardware-qemu.ini.lock` chứa pid **kết thúc bằng byte NUL** (`519772\0`). `trim()` không bỏ
295
+ > NUL, nên `Number()` ra `NaN` và mọi emulator đang chạy đều bị đọc là "không khoá" — dòng cảnh
296
+ > báo "đang mở trong Android Studio" chưa từng hiện kể từ Phase 1. Lấy cụm số đầu file.
297
+
298
+ ### Phase 5 — Đóng gói, ổn định và phát hành
299
+
300
+ - Test source/npm/compiled ở Linux, Windows, macOS; đường dẫn có khoảng trắng/Unicode, PATH của service khác terminal, không có Android Studio, thiếu ffmpeg/tool.
301
+ - Test thực trên mobile Safari/Chrome và desktop Chromium/Firefox theo capabilities, cả mạng cục bộ/tunnel.
302
+ - Documentation setup/troubleshoot/compatibility, license notices; feature flag opt-in, lazy load; tắt flag phải cleanup session/encoder nhưng không wipe/stop emulator ngoài ý muốn.
303
+ - Gate: artifacts được serve đúng build, regression Remote Desktop/chat/terminal pass; rollback chỉ tắt tính năng, không thay schema hoặc AVD data.
304
+
305
+ Thứ tự: **0 → 1 → 2 → 3 → 4 → 5**. Việc kiểm tra packaging/mobile/security diễn ra từ phase 0–2, không để cuối mới phát hiện. Có thể release preview sau phase 2 nếu ghi rõ chưa có AVD CRUD/công cụ phase 3–4. Chưa gắn số version hay lịch ngày trước khi có benchmark và test trên OS đích.
306
+
307
+ ## 10. Ngân sách hiệu năng và cách đo
308
+
309
+ Đây là **mục tiêu nghiệm thu đề xuất**, chưa phải số đo đã đạt:
310
+
311
+ | Chỉ số | Mục tiêu ban đầu |
312
+ |---|---|
313
+ | Chất lượng chuẩn | 720p-equivalent, 30 fps khi màn hình chuyển động; bitrate mục tiêu 2–6 Mbps |
314
+ | LAN input-to-visible | p95 ≤150 ms trên host/reference client đủ tài nguyên |
315
+ | Tunnel input-to-visible | p95 ≤300 ms với RTT ≤100 ms, downstream ≥10 Mbps; báo điều kiện mạng khi đo |
316
+ | Thời gian first frame | ≤3 giây từ khi emulator đã sẵn sàng, không gồm cold boot |
317
+ | Encoder backlog | ≤2 raw frames; encode/decode/network queues đều có hard cap |
318
+ | PPM + encoder overhead | Mục tiêu ≤1 CPU core bình quân, ≤250 MiB RSS tăng thêm/device ở profile chuẩn; không tính emulator |
319
+ | Idle/ẩn | Dừng feed/encoder sau grace ≤5 giây khi không còn viewer; emulator vẫn chạy |
320
+ | Reconnect | ≤5 giây sau mạng phục hồi trong test, nonce mới/keyframe mới, không input cũ |
321
+ | Soak | 60 phút có rotate/reconnect; không tăng RAM đều, không rò encoder/gRPC/touch |
322
+
323
+ Đo click-to-visible bằng test app đổi màu khi nhận touch, quay/timestamp trên cùng browser clock; không trừ trực tiếp clock host và client chưa đồng bộ. Ghi cấu hình host/GPU/guest/browser và thông số mạng. Nếu ngân sách không đạt thì hạ profile hoặc đổi media theo ADR; không gọi số mục tiêu là benchmark.
324
+
325
+ ## 11. Ma trận kiểm thử và Definition of Done
326
+
327
+ Unit/contract: parser SDK/discovery và stale PID, identity, argv/path validation, protocol packet bounds, codec generation, geometry tại 0/90/180/270°, DPR/letterbox, pointer/key cancellation, IME composition, lease expiry/nonce replay.
328
+
329
+ Integration: fake SDK processes + gRPC fixture có auth, timeout và disconnect; HTTP/WS thực qua route registration; lỗi giữa lúc auth/start/rotate, start hai lần, logout, đổi token, stop nhầm generation, thiếu quyền host. Hai thiết bị chạy đồng thời không tranh session; feature không ảnh hưởng Remote Desktop.
330
+
331
+ E2E bắt buộc với emulator thật và **bundle đã build/serve trên instance riêng**:
332
+
333
+ 1. SDK có sẵn → list AVD → Start → boot progress → Open có hình.
334
+ 2. Tap/long press/swipe/drag; hai ngón pinch; Home/Back/Recent/Power/Volume hoạt động.
335
+ 3. Gõ `Tiếng Việt`, emoji **qua đường clipboard** (Phase 0 chứng minh `sendKey.text` không mang được); ASCII qua `key`; Enter/Backspace; bàn phím mobile không gõ đôi/mất composition.
336
+ 4. Rotate liên tục trong khi kéo, resize/fit/100%; chạm vẫn đúng vị trí, không stuck touch.
337
+ 5. Chuyển tab ẩn/hiện, pop-out/PiP/return; không double stream hoặc mất ownership.
338
+ 6. Mất mạng 30 giây rồi reconnect; input được release, không replay click; máy vẫn chạy.
339
+ 7. Client thứ hai nhận thông báo đang dùng; Take control thu hồi client cũ và input cũ.
340
+ 8. Hai AVD khác nhau và Remote Desktop không đá nhau; vượt limit có lỗi rõ ràng.
341
+ 9. Refresh/restore workspace không boot hoặc tự giành control; emulator đã chạy có thể reconnect.
342
+ 10. Install APK đúng máy; screenshot đúng khung Android; Logcat có cap/cleanup.
343
+ 11. Stop máy PPM sở hữu; máy Studio chỉ Disconnect; stale PID/AVD lock không gây kill sai.
344
+ 12. Wipe/Delete task-test AVD có xác nhận và đúng target; Cold boot/Quick boot không mất dữ liệu ngoài hành động wipe.
345
+
346
+ Release checklist: cold browser origin tránh cache cũ; kiểm tra hash/timestamp served bundle; full asset pipeline gồm Monaco/precompress; isolated `PPM_HOME` và port đã kiểm tra không trùng. Không stop `ppm.service` từ session này để build. Nếu suite tổng treo theo baseline đã biết, báo rõ và chạy từng file liên quan, không tuyên bố full suite pass.
347
+
348
+ ## 12. Những việc cần chốt bằng thử nghiệm
349
+
350
+ - Bun gRPC + compiled binary có hoạt động ổn với auth/stream cancellation không?
351
+ - RGB→H.264 có đạt ngân sách trên Linux/Windows/macOS, hay nên chọn scrcpy media?
352
+ - Phiên bản emulator tối thiểu, flags headless/hidden, discovery layout và auth modes nào được hỗ trợ chính thức?
353
+ - Unicode/text injection thực tế của gRPC trên các guest image; cơ chế nào cần cho mobile IME?
354
+ - Process lifecycle qua PPM restart/service shutdown ở từng OS giữ emulator như thiết kế được không?
355
+ - Chọn máy Windows/macOS và thiết bị browser thật để chạy ma trận; máy hiện tại chỉ chứng minh prerequisites Linux.
356
+
357
+ Các câu hỏi này không chặn việc lập plan. Chúng là deliverable của spike/validation; không âm thầm coi giả định là chức năng đã có.
358
+
359
+ ## Nguồn tham khảo
360
+
361
+ - **S1 — Studio controller (pinned revision):** https://android.googlesource.com/platform/tools/adt/idea/+/2aa920453118ffa8cd6b2996ca95e4e7187d01c2/streaming/src/com/android/tools/idea/streaming/emulator/EmulatorController.kt
362
+ - **S2 — Studio view (cùng revision; đọc raw Gitiles):** https://android.googlesource.com/platform/tools/adt/idea/+/2aa920453118ffa8cd6b2996ca95e4e7187d01c2/streaming/src/com/android/tools/idea/streaming/emulator/EmulatorView.kt
363
+ - **S3 — Emulator controller schema:** https://android.googlesource.com/platform/tools/base/+/refs/heads/mirror-goog-studio-main/emulator/proto/emulator_controller.proto ; đối chiếu file SDK cục bộ 36.5.10 ở `emulator/lib/emulator_controller.proto`.
364
+ - **S4 — Device Manager / AVD:** https://developer.android.com/studio/run/managing-avds
365
+ - **S5 — Emulator CLI:** https://developer.android.com/studio/run/emulator-commandline
366
+ - **S6 — Google browser/WebRTC demo:** https://github.com/google/android-emulator-container-scripts/blob/master/gateway/DEMO.md ; đối chiếu `emulator/lib/rtc_service_v2.proto` cục bộ, có cảnh báo experimental.
367
+ - **S7 — Scrcpy architecture/protocol:** https://github.com/Genymobile/scrcpy/blob/master/doc/develop.md
368
+ - **S8 — Emulator gRPC/authentication:** https://android.googlesource.com/platform/external/qemu/+/686efa16baf59d776cadc3f975d12570fe44bbb9/android/android-grpc/docs/
369
+ - **S9 — gRPC Node API (không phải chứng nhận Bun compatibility):** https://grpc.io/docs/languages/node/basics/
370
+ - **S10 — Cloudflare WebSocket support:** https://developers.cloudflare.com/network/websockets/
371
+ - **S11 — Browser VideoDecoder:** https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder
372
+ - **S12 — sdkmanager:** https://developer.android.com/tools/sdkmanager
373
+ - **S13 — avdmanager:** https://developer.android.com/tools/avdmanager
374
+ - **S14 — Host acceleration:** https://developer.android.com/studio/run/emulator-acceleration
375
+
376
+ Nguồn branch/master là tài liệu động, chỉ dùng để nghiên cứu. Khi triển khai phải pin revision/hash dependency và giữ notices tương ứng. Kế hoạch không sao chép nguyên implementation Studio và không bundle SDK/system images vào PPM.
@@ -4,8 +4,9 @@ Two rules adopted on 2026-09-11, borrowed from DeepSeek Harness: **Everything is
4
4
  run is traceable.** PPM is a platform that embeds things around an AI agent — the IDE is one of
5
5
  those things, not the product.
6
6
 
7
- **Status: design only. Nothing in this document is built.** Current priority is finishing the
8
- features already in flight; this exists so the work starts from a decision instead of a guess.
7
+ **Status (2026-09-25): Rule 1's trace is built** — `src/services/session-trace/` and
8
+ `src/web/lib/trace-client.ts`; where the build departs from the design is listed under *As built*.
9
+ **Rule 2 is still design only**; it exists so that work starts from a decision instead of a guess.
9
10
 
10
11
  Rewriting the backend in Go was considered and rejected on the same day — see `docs/lessons-learned.md`.
11
12
 
@@ -160,11 +161,12 @@ real question too, and it keeps one `seq` space per key.
160
161
  "All of the browser's logs" is read as: `console.error` and `console.warn` are sent; `console.log`
161
162
  and `info` go into a **50-entry ring buffer** that rides along as breadcrumbs on the next error. That
162
163
  is what a failure needs — the lines just before it — without paying for logging while nothing is
163
- wrong.
164
+ wrong. (Reversed when built: every level is sent — see *As built*.)
164
165
 
165
166
  Ingest is one route — `POST /api/trace` — taking a small batch. It sits behind `authMiddleware` like
166
- the rest of `/api/*` (`index.ts:177`), so an error raised while logged out is lost; accepted. Three
167
- things it needs, none optional:
167
+ the rest of `/api/*` (`index.ts:177`), so an error raised while logged out is lost; accepted. (As
168
+ built, the client holds such rows until a sign-in — see *As built*.) Three things it needs, none
169
+ optional:
168
170
 
169
171
  - **A cap and a schema check.** Batch ≤ 50, payload ≤ 16 KB each; treat the body as hostile and drop
170
172
  what does not fit.
@@ -178,8 +180,9 @@ Client side, `root-error-boundary.tsx:87` and `chunk-recovery.ts` already know s
178
180
  `main.tsx`** so it lives in the boot shell — in a lazy chunk it could not report the one failure that
179
181
  matters most, a missing chunk. The case where the entry never runs at all (`__ppmEntryRan` false)
180
182
  gets a bundle-free beacon in `index.html`'s inline watchdog, reading the Bearer token from
181
- `localStorage["ppm-auth-token"]`. Buffer locally and flush with `sendBeacon`/`keepalive` on
182
- `pagehide`, because the common case for a fatal client error is that the network is also what broke.
183
+ `localStorage["ppm-auth-token"]`. Buffer locally and flush with `keepalive` on `pagehide`, because
184
+ the common case for a fatal client error is that the network is also what broke. (Not `sendBeacon`:
185
+ it cannot carry the `Authorization` header.)
183
186
 
184
187
  ### Retention
185
188
 
@@ -194,6 +197,44 @@ sessions that predate the log or were created outside PPM. That is the point whe
194
197
  tax gets repaid: cross-provider history stops depending on `getFullMessages` being implemented
195
198
  (only Claude implements it today, so the search index is better for one provider than the others).
196
199
 
200
+ ### As built (2026-09-25)
201
+
202
+ What differs from the design above, and why:
203
+
204
+ - **Every console level is sent**, at the user's request: batched (errors within 1 s, the rest
205
+ within 5 s), capped at 300 entries a minute per tab, then one `console_dropped{count}`. Each
206
+ error-level entry still carries the 50 lines before it as breadcrumbs.
207
+ - **Logged out is held, not lost.** A 401 leaves the queue in place and nothing is sent again until
208
+ the stored token changes — a storage read every 5 s, no request — so a fresh device's login screen
209
+ is not the one page that cannot be debugged. Rows still only reach the server authenticated. The
210
+ watchdog beacon cannot do this: when the entry never ran there is no code left to retry with.
211
+ - **`trace_aliases`** maps an id a provider migrated to (`session_migrated`) back to the trace the
212
+ run started under, so a follow-up, an abort or a browser row filed under the new id joins it.
213
+ - **`context_added`** records the shared provider context PPM prefixes to a message (or hands to a
214
+ provider that places it), in full — at most 12 000 characters, and only when it changed. Found in
215
+ verification: a mock asked approval for `rm -rf` because the word "remove" was in
216
+ `~/.claude/CLAUDE.md`, text the trace had not recorded. Design instructions are not recorded; they
217
+ are rebuilt from the stored slug.
218
+ - **A bare system signal is counted on the block it arrives in.** The Claude SDK sends a data-less
219
+ `system/thinking_tokens` between every two thinking deltas; treated as events, they split each
220
+ thinking block into a row per delta — 84 of one real turn's 92 rows. Inside a text or thinking
221
+ block such a signal now becomes `signals: {thinking_tokens: N}` on the block's row; outside one it
222
+ is still a row of its own.
223
+ - **`run_closed` only for an unanswered turn.** Every caller but the WebSocket stops reading at
224
+ `done`, so that is how a run normally ends and it gets no row. `consumer_closed` and `no_done` are
225
+ written only when a turn, or a follow-up queued behind it, never got its `done`.
226
+ - **The API proxy** (`proxy-agent-turn.ts`) does not go through `ChatService`, so its stream is
227
+ wrapped in `traceStream` with origin `proxy`.
228
+ - **Reading without sqlite:** `GET /api/trace/sessions/:id` returns a session's merged timeline —
229
+ its rows plus every browser row whose `ref_id` is one of its ids.
230
+ - **Measured:** 50 mock turns against a clean HEAD and the traced build, alternating: `/api/health`
231
+ p50 0.85–0.94 ms and p99 4.4–5.0 ms on both, no event-loop stall on either. A synthetic heavy
232
+ stream (76 010 events → 6 040 rows) cost 49.7 ms in all, 0.57 µs per event; the worst single call
233
+ was the end-of-turn write at 3.75 ms.
234
+ - **Not in the trace yet:** events of nested subagents (never streamed — see `CLAUDE.md`) and
235
+ background `bash_output`. The older `session_logs` / `logSessionEvent` still exists and could be
236
+ retired in favour of this log.
237
+
197
238
  ---
198
239
 
199
240
  ## Rule 2 — Everything is a plugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.23.11",
3
+ "version": "0.23.12",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -19,7 +19,7 @@
19
19
  "tunnel": "cloudflared tunnel --url http://localhost:5173",
20
20
  "dev:tunnel": "concurrently \"bun run dev:server\" \"bun run dev:web\" \"bun run tunnel\"",
21
21
  "build:web": "bun run vite build --config vite.config.ts",
22
- "build": "bun run build:web && bun scripts/copy-monaco.ts && bun scripts/precompress-web.ts && bun build src/index.ts src/services/extension-host-worker.ts --compile --outfile dist/ppm",
22
+ "build": "bun run build:web && bun scripts/copy-monaco.ts && bun scripts/precompress-web.ts && bun build src/index.ts src/services/extension-host-worker.ts src/services/file-index/file-index-worker.ts --compile --outfile dist/ppm",
23
23
  "start": "bun run src/index.ts start",
24
24
  "typecheck": "bunx tsc --noEmit",
25
25
  "test:docker": "docker compose -f docker-compose.test.yml up --build --renew-anon-volumes --abort-on-container-exit --exit-code-from test",
@@ -57,6 +57,8 @@
57
57
  "@anthropic-ai/claude-agent-sdk": "0.3.280",
58
58
  "@codemirror/lang-sql": "^6.10.0",
59
59
  "@glideapps/glide-data-grid": "^6.0.3",
60
+ "@grpc/grpc-js": "1.14.0",
61
+ "@grpc/proto-loader": "0.7.15",
60
62
  "@inquirer/prompts": "^8.3.0",
61
63
  "@monaco-editor/react": "^4.7.0",
62
64
  "@radix-ui/react-switch": "^1.2.6",
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Turns the emulator's `emulator_controller.proto` into a JSON descriptor the bundler can embed.
3
+ *
4
+ * `@grpc/proto-loader`'s `loadSync()` reads the .proto off disk at call time, and in a compiled
5
+ * PPM that path resolves under `file:///$bunfs/root/` where no such file exists — measured, it
6
+ * throws ENOENT at `loadProtosWithOptionsSync`. Same family as the `bundledServerEntry` trap in
7
+ * CLAUDE.md. So the descriptor is generated here and `import`ed as a module instead.
8
+ *
9
+ * Re-run after changing the .proto: bun scripts/gen-android-proto.ts
10
+ */
11
+ import protobuf from "protobufjs";
12
+ import { createHash } from "node:crypto";
13
+ import { readFileSync, writeFileSync } from "node:fs";
14
+ import { resolve } from "node:path";
15
+
16
+ const DIR = resolve(import.meta.dir, "..", "src", "services", "android", "proto");
17
+ const SRC = resolve(DIR, "emulator_controller.proto");
18
+ const OUT = resolve(DIR, "emulator-controller-descriptor.ts");
19
+
20
+ const root = await protobuf.load(SRC);
21
+ const sha = createHash("sha256").update(readFileSync(SRC)).digest("hex");
22
+
23
+ writeFileSync(OUT, `// GENERATED by scripts/gen-android-proto.ts — do not edit.
24
+ //
25
+ // Source: emulator_controller.proto (Apache 2.0, The Android Open Source Project)
26
+ // Taken from: $ANDROID_SDK_ROOT/emulator/lib/emulator_controller.proto
27
+ // Emulator: 36.5.10.0 (build 15081367)
28
+ // SHA-256: ${sha}
29
+ //
30
+ // Embedded rather than loaded from disk: a compiled binary cannot read the .proto file.
31
+ export const EMULATOR_CONTROLLER_PROTO_SHA256 = ${JSON.stringify(sha)};
32
+ export const emulatorControllerDescriptor = ${JSON.stringify(root.toJSON({ keepComments: false }))} as const;
33
+ `);
34
+
35
+ console.log(`wrote ${OUT}`);
36
+ console.log(` sha256 ${sha}`);
37
+ console.log(` ${(readFileSync(OUT).length / 1024).toFixed(0)} KiB`);
@@ -115,7 +115,9 @@ TARGETS=(
115
115
  for entry in "${TARGETS[@]}"; do
116
116
  target="${entry%%:*}"; artifact="${entry##*:}"
117
117
  echo " -> $artifact ($target)"
118
- bun build src/index.ts --compile --target="$target" --outfile="dist/$artifact" \
118
+ # The same entry points as the `build` script: a Worker is in the binary only if it is one.
119
+ bun build src/index.ts src/services/extension-host-worker.ts src/services/file-index/file-index-worker.ts \
120
+ --compile --target="$target" --outfile="dist/$artifact" \
119
121
  || fail "compile failed for $target."
120
122
  done
121
123
 
@@ -167,7 +167,7 @@ export function registerChatCommands(program: Command): void {
167
167
  process.exit(1);
168
168
  }
169
169
 
170
- const events = chatService.sendMessage(session.providerId, session.id, message);
170
+ const events = chatService.sendMessage(session.providerId, session.id, message, { origin: "cli" });
171
171
  await streamEvents(events);
172
172
  } catch (err) {
173
173
  console.error(`${C.red}Error:${C.reset}`, (err as Error).message);
@@ -210,7 +210,7 @@ export function registerChatCommands(program: Command): void {
210
210
  process.stdout.write(`${C.bold}${C.magenta}Claude:${C.reset} `);
211
211
 
212
212
  try {
213
- const events = chatService.sendMessage(session.providerId, session.id, trimmed);
213
+ const events = chatService.sendMessage(session.providerId, session.id, trimmed, { origin: "cli" });
214
214
  await streamEvents(events, async (_requestId, tool, input) => {
215
215
  const approved = await promptApproval(tool, input);
216
216
  return approved;
@@ -27,6 +27,34 @@ export type EffortValue = (typeof VALID_EFFORT_VALUES)[number];
27
27
  */
28
28
  export const THINKING_ADAPTIVE = -1;
29
29
 
30
+ /**
31
+ * The tools the SDK runs without asking — it skips `canUseTool` for everything listed.
32
+ *
33
+ * In non-bypass modes only the read-only tools are listed, so write/execute tools go through
34
+ * the permission evaluation chain → the PreToolUse hook. The design policy lists nothing:
35
+ * the read-only list would let Read and Grep reach any path on disk and every MCP tool run
36
+ * unasked, which is exactly what a design session's agent (fed page content it did not
37
+ * write) must not do.
38
+ */
39
+ export const READ_ONLY_TOOLS: readonly string[] = ["Read", "Glob", "Grep", "WebSearch", "WebFetch", "ToolSearch"];
40
+
41
+ export function allowedToolsFor(p: {
42
+ isBypass: boolean;
43
+ agentTeams?: boolean;
44
+ designPolicy?: boolean;
45
+ designCheckTool?: string | null;
46
+ }): string[] {
47
+ if (p.designPolicy) return p.designCheckTool ? [p.designCheckTool] : [];
48
+ const writeTools = ["Write", "Edit", "Bash", "Agent", "Skill", "TodoWrite", "AskUserQuestion"];
49
+ const teamTools = p.agentTeams
50
+ ? ["TeamCreate", "TeamDelete", "SendMessage", "TaskCreate", "TaskUpdate", "TaskList", "TaskGet"]
51
+ : [];
52
+ const mcpTools = ["mcp__*"];
53
+ return p.isBypass
54
+ ? [...READ_ONLY_TOOLS, ...writeTools, ...teamTools, ...mcpTools]
55
+ : [...READ_ONLY_TOOLS, ...mcpTools];
56
+ }
57
+
30
58
  export interface ModelQueryOverrides {
31
59
  model?: string;
32
60
  oneMContext?: boolean;