@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
@@ -1,17 +1,20 @@
1
1
  import type { StripMode } from "../services/transcript-images.ts";
2
2
  import {
3
3
  query,
4
+ type Query,
4
5
  listSessions as sdkListSessions,
5
6
  getSessionInfo as sdkGetSessionInfo,
6
7
  getSessionMessages,
7
8
  } from "@anthropic-ai/claude-agent-sdk";
8
- import { buildModelQueryOptions, buildSystemPromptOption, designMcpServers, preToolUseDecision } from "./claude-agent-sdk-query-options.ts";
9
+ import { allowedToolsFor, buildModelQueryOptions, buildSystemPromptOption, designMcpServers, preToolUseDecision, READ_ONLY_TOOLS } from "./claude-agent-sdk-query-options.ts";
10
+ import { WarmSpares, spawnFingerprint } from "./claude-warm-spare.ts";
9
11
  import { CLAUDE_DESIGN_CHECK_TOOL } from "../services/design/mcp/design-mcp-tool.ts";
10
12
  import { designToolDecision } from "../services/design/design-tool-policy.ts";
11
13
  import { CLAUDE_MODELS } from "../types/claude-models.ts";
12
14
  import { isImageLimitRejection } from "./image-limit-detection.ts";
13
15
  import type {
14
16
  AIProvider,
17
+ PrewarmInput,
15
18
  Session,
16
19
  SessionConfig,
17
20
  SessionInfo,
@@ -38,7 +41,7 @@ import { isCompiledBinary } from "../services/autostart-generator.ts";
38
41
  import { resolveClaudeCliPath } from "../services/claude-cli-resolver.ts";
39
42
  import { resolve, dirname } from "node:path";
40
43
  import { existsSync, readdirSync, unlinkSync, readFileSync, statSync } from "node:fs";
41
- import { homedir } from "node:os";
44
+ import { homedir, totalmem } from "node:os";
42
45
 
43
46
  const CLAUDE_PROJECTS_DIR = resolve(homedir(), ".claude/projects");
44
47
 
@@ -238,6 +241,10 @@ export class ClaudeAgentSdkProvider implements AIProvider {
238
241
  * and this is the only place that knows what made it do so.
239
242
  */
240
243
  private teardownReasons = new Map<string, string>();
244
+ /** CLIs started for chats that do not exist yet — see `prewarm`. */
245
+ private readonly warmSpares = new WarmSpares<Query>();
246
+ /** Hosts with less RAM keep no warm CLI: each one holds ~500 MB while it waits. */
247
+ private minWarmSpareHostMemory = 8 * 1024 ** 3;
241
248
 
242
249
  /** Auth-related env keys for diagnostic logging */
243
250
  private readonly AUTH_ENV_KEYS = ["ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
@@ -510,7 +517,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
510
517
  }
511
518
 
512
519
  async createSession(config: SessionConfig): Promise<Session> {
513
- const id = crypto.randomUUID();
520
+ const id = (config.adoptWarmSpare && config.projectPath && this.warmSpares.claim(config.projectPath)) || crypto.randomUUID();
514
521
  const meta: Session = {
515
522
  id,
516
523
  providerId: this.id,
@@ -811,6 +818,131 @@ export class ClaudeAgentSdkProvider implements AIProvider {
811
818
  return process.env.CLAUDE_CODE_OAUTH_TOKEN ? SUBSCRIPTION_PROMPT_CACHE_TTL_MS : API_KEY_PROMPT_CACHE_TTL_MS;
812
819
  }
813
820
 
821
+ /**
822
+ * What a turn spawns the CLI with. `sendMessage` and `prewarm` both build it here, so a
823
+ * warm spare is only ever taken over by a turn that would have started that same process
824
+ * (`spawnFingerprint` compares the two).
825
+ */
826
+ private buildQueryOptions(p: {
827
+ sessionId?: string;
828
+ resume?: string;
829
+ forkSession?: boolean;
830
+ cwd: string;
831
+ systemPrompt: ReturnType<typeof buildSystemPromptOption>;
832
+ env: Record<string, string | undefined>;
833
+ allowedTools: string[];
834
+ mcpServers: Record<string, unknown>;
835
+ permissionMode: string;
836
+ opts?: Pick<import("./provider.interface.ts").SendMessageOpts, "model" | "oneMContext" | "effort" | "thinkingBudget" | "maxTurns">;
837
+ providerConfig: Partial<import("../types/config.ts").AIProviderConfig>;
838
+ stderr: (chunk: string) => void;
839
+ }): Record<string, any> {
840
+ // 1M context (GA): the CLI enables a 1M window when the model name carries a
841
+ // [1m] suffix. The suffix is stripped before the API call. Requires an entitled
842
+ // account (Max/Team/Enterprise) and a supported model; otherwise the API errors.
843
+ // Per-call overrides win over provider config (lightweight calls can opt out of 1M;
844
+ // the chat input picker sets per-session model/effort/thinking). Effort enum is
845
+ // guarded inside the helper — "extra" would crash the CLI subprocess.
846
+ const mqo = buildModelQueryOptions(
847
+ {
848
+ model: p.opts?.model,
849
+ oneMContext: p.opts?.oneMContext,
850
+ effort: p.opts?.effort,
851
+ thinkingBudget: p.opts?.thinkingBudget,
852
+ },
853
+ p.providerConfig,
854
+ );
855
+
856
+ // Compiled binaries have no node_modules → resolve a Claude CLI explicitly
857
+ // (system claude or the one shipped in cli/). Source installs → undefined
858
+ // (SDK self-resolves from node_modules, unchanged).
859
+ const cliExecutablePath = resolveCliExecutablePath(
860
+ (p.providerConfig as { cli_command?: string }).cli_command,
861
+ );
862
+
863
+ return {
864
+ // Run the CLI under node only for a .js entry (or the win32 source-mode
865
+ // default). A native claude(.exe) must be spawned directly.
866
+ ...(needsNodeInterpreter(process.platform, cliExecutablePath) && { executable: "node" }),
867
+ ...(cliExecutablePath && { pathToClaudeCodeExecutable: cliExecutablePath }),
868
+ sessionId: p.sessionId,
869
+ resume: p.resume,
870
+ ...(p.forkSession && { forkSession: true }),
871
+ cwd: p.cwd,
872
+ systemPrompt: p.systemPrompt,
873
+ settingSources: ["user", "project"],
874
+ env: p.env,
875
+ settings: { permissions: { allow: [], deny: [] } },
876
+ allowedTools: p.allowedTools,
877
+ ...(Object.keys(p.mcpServers).length > 0 && { mcpServers: p.mcpServers }),
878
+ permissionMode: p.permissionMode,
879
+ allowDangerouslySkipPermissions: p.permissionMode === "bypassPermissions",
880
+ ...(mqo.model && { model: mqo.model }),
881
+ ...(mqo.effort && { effort: mqo.effort }),
882
+ maxTurns: p.opts?.maxTurns ?? p.providerConfig.max_turns ?? 1000,
883
+ ...(p.providerConfig.max_budget_usd && { maxBudgetUsd: p.providerConfig.max_budget_usd }),
884
+ ...(mqo.thinking && { thinking: mqo.thinking }),
885
+ // Beta headers are honored only for API-key auth; OAuth/subscription sessions
886
+ // reject them ("Custom betas are only available for API key users") and crash the
887
+ // subprocess. Entitled OAuth accounts still get 1M context via the [1m] model suffix.
888
+ ...(mqo.use1m && !!p.env.ANTHROPIC_API_KEY && { betas: ["context-1m-2025-08-07"] }),
889
+ includePartialMessages: true,
890
+ stderr: p.stderr,
891
+ };
892
+ }
893
+
894
+ /**
895
+ * Start the CLI the next chat created in `projectPath` will run on, so that chat's first
896
+ * message does not wait ~1.4 s for it to boot (`claude-warm-spare.ts` has the numbers).
897
+ * Given the settings the message will carry, the options are built exactly as
898
+ * `sendMessage` builds them; anything this cannot foresee only makes that turn start cold.
899
+ */
900
+ async prewarm(input: PrewarmInput): Promise<void> {
901
+ const { projectPath, accountId, opts } = input;
902
+ if (!existsSync(projectPath) || totalmem() < this.minWarmSpareHostMemory) return;
903
+ const providerConfig = this.getProviderConfig();
904
+ const permissionMode = opts?.permissionMode || providerConfig.permission_mode || "bypassPermissions";
905
+ const isBypass = permissionMode === "bypassPermissions";
906
+
907
+ let account: AccountWithTokens | null = null;
908
+ if (accountSelector.isEnabled()) {
909
+ // The session will be bound to the account its tab claimed, and its turn runs on that
910
+ // one. Without a claim the turn's own pick cannot be foreseen, so nothing is started.
911
+ if (!accountId || !accountSelector.canServe(accountId)) return;
912
+ account = await accountService.ensureFreshToken(accountId);
913
+ if (!account) return;
914
+ // What `sendMessage` does too: a background refresh may have rotated the token.
915
+ account = accountService.getWithTokens(accountId) ?? account;
916
+ }
917
+
918
+ const options = this.buildQueryOptions({
919
+ cwd: projectPath,
920
+ systemPrompt: buildSystemPromptOption(providerConfig.system_prompt),
921
+ env: this.buildQueryEnv(projectPath, account),
922
+ allowedTools: allowedToolsFor({ isBypass, agentTeams: providerConfig.agent_teams }),
923
+ mcpServers: this.resolveMcpServers(projectPath),
924
+ permissionMode,
925
+ opts,
926
+ providerConfig,
927
+ stderr: () => {},
928
+ });
929
+ this.warmSpares.offer(projectPath, spawnFingerprint(options), (sessionId, callbacks) => {
930
+ const { generator, controller } = createMessageChannel();
931
+ const q = query({
932
+ prompt: generator,
933
+ options: {
934
+ ...options,
935
+ sessionId,
936
+ stderr: callbacks.stderr,
937
+ ...(!isBypass && { hooks: { PreToolUse: [{ matcher: ".*", hooks: [callbacks.preToolUse] }] } }),
938
+ canUseTool: callbacks.canUseTool,
939
+ } as any,
940
+ });
941
+ console.log(`[sdk] session=${sessionId} warm CLI started for ${projectPath}`);
942
+ return { query: q, controller };
943
+ });
944
+ }
945
+
814
946
  async *sendMessage(
815
947
  _sessionId: string,
816
948
  message: string,
@@ -899,26 +1031,9 @@ export class ClaudeAgentSdkProvider implements AIProvider {
899
1031
  // No project root means nothing can be proven inside it, so every file tool asks.
900
1032
  const designRoot = designPolicy && meta.projectPath && existsSync(meta.projectPath) ? meta.projectPath : undefined;
901
1033
 
902
- // Build allowedTools based on permission mode.
903
- // SDK auto-approves everything in allowedTools (skips canUseTool callback).
904
- // In non-bypass modes, only pre-approve read-only tools so write/execute tools
905
- // go through the permission evaluation chain → canUseTool callback.
906
- // The design policy pre-approves nothing: the read-only list would let Read and Grep
907
- // reach any path on disk and every MCP tool run unasked, which is exactly what a
908
- // design session's agent (fed page content it did not write) must not do.
909
- const readOnlyTools = ["Read", "Glob", "Grep", "WebSearch", "WebFetch", "ToolSearch"];
910
- const writeTools = ["Write", "Edit", "Bash", "Agent", "Skill", "TodoWrite", "AskUserQuestion"];
911
- const teamTools = providerConfig.agent_teams
912
- ? ["TeamCreate", "TeamDelete", "SendMessage", "TaskCreate", "TaskUpdate", "TaskList", "TaskGet"]
913
- : [];
914
- const mcpTools = ["mcp__*"];
915
1034
  // `design_check` only reads the canvas, so a design session never asks before it runs.
916
1035
  const designCheckTool = opts?.designSession && opts.designMcp ? CLAUDE_DESIGN_CHECK_TOOL : null;
917
- const allowedTools = designPolicy
918
- ? (designCheckTool ? [designCheckTool] : [])
919
- : isBypass
920
- ? [...readOnlyTools, ...writeTools, ...teamTools, ...mcpTools]
921
- : [...readOnlyTools, ...mcpTools];
1036
+ const allowedTools = allowedToolsFor({ isBypass, agentTeams: providerConfig.agent_teams, designPolicy, designCheckTool });
922
1037
 
923
1038
  /**
924
1039
  * Approval events to yield from the generator.
@@ -991,7 +1106,7 @@ export class ClaudeAgentSdkProvider implements AIProvider {
991
1106
  if (designToolDecision(toolName, hookInput?.tool_input, designRoot) === "allow") {
992
1107
  return preToolUseDecision("allow");
993
1108
  }
994
- } else if (readOnlyTools.includes(toolName)) {
1109
+ } else if (READ_ONLY_TOOLS.includes(toolName)) {
995
1110
  // Read-only tools: always allow
996
1111
  return {};
997
1112
  }
@@ -1148,61 +1263,21 @@ export class ClaudeAgentSdkProvider implements AIProvider {
1148
1263
  console.log(`[sdk] session=${sessionId} mcpServers: ${Object.keys(mcpServers).join(", ")}`);
1149
1264
  }
1150
1265
 
1151
- // 1M context (GA): the CLI enables a 1M window when the model name carries a
1152
- // [1m] suffix. The suffix is stripped before the API call. Requires an entitled
1153
- // account (Max/Team/Enterprise) and a supported model; otherwise the API errors.
1154
- // Per-call overrides win over provider config (lightweight calls can opt out of 1M;
1155
- // the chat input picker sets per-session model/effort/thinking). Effort enum is
1156
- // guarded inside the helper — "extra" would crash the CLI subprocess.
1157
- const mqo = buildModelQueryOptions(
1158
- {
1159
- model: opts?.model,
1160
- oneMContext: opts?.oneMContext,
1161
- effort: opts?.effort,
1162
- thinkingBudget: opts?.thinkingBudget,
1163
- },
1164
- providerConfig,
1165
- );
1166
- const resolvedModel = mqo.model;
1167
- const use1m = mqo.use1m;
1168
-
1169
- // Compiled binaries have no node_modules → resolve a Claude CLI explicitly
1170
- // (system claude or the one shipped in cli/). Source installs → undefined
1171
- // (SDK self-resolves from node_modules, unchanged).
1172
- const cliExecutablePath = resolveCliExecutablePath(
1173
- (providerConfig as { cli_command?: string }).cli_command,
1174
- );
1175
-
1176
- const queryOptions: Record<string, any> = {
1177
- // Run the CLI under node only for a .js entry (or the win32 source-mode
1178
- // default). A native claude(.exe) must be spawned directly.
1179
- ...(needsNodeInterpreter(process.platform, cliExecutablePath) && { executable: "node" }),
1180
- ...(cliExecutablePath && { pathToClaudeCodeExecutable: cliExecutablePath }),
1266
+ const queryOptions = this.buildQueryOptions({
1181
1267
  // First message: create session with this ID. Subsequent: resume by same ID.
1182
1268
  sessionId: isFirstMessage && !shouldFork ? sessionId : undefined,
1183
1269
  resume: (isFirstMessage && !shouldFork) ? undefined : (shouldFork ? forkSourceId : sessionId),
1184
- ...(shouldFork && { forkSession: true }),
1270
+ forkSession: shouldFork,
1185
1271
  cwd: effectiveCwd,
1186
1272
  systemPrompt: systemPromptOpt,
1187
- settingSources: ["user", "project"],
1188
1273
  env: queryEnv,
1189
- settings: { permissions: { allow: [], deny: [] } },
1190
1274
  allowedTools,
1191
- ...(hasMcp && { mcpServers }),
1275
+ mcpServers,
1192
1276
  permissionMode,
1193
- allowDangerouslySkipPermissions: isBypass,
1194
- ...(resolvedModel && { model: resolvedModel }),
1195
- ...(mqo.effort && { effort: mqo.effort }),
1196
- maxTurns: opts?.maxTurns ?? providerConfig.max_turns ?? 1000,
1197
- ...(providerConfig.max_budget_usd && { maxBudgetUsd: providerConfig.max_budget_usd }),
1198
- ...(mqo.thinking && { thinking: mqo.thinking }),
1199
- // Beta headers are honored only for API-key auth; OAuth/subscription sessions
1200
- // reject them ("Custom betas are only available for API key users") and crash the
1201
- // subprocess. Entitled OAuth accounts still get 1M context via the [1m] model suffix.
1202
- ...(use1m && !!queryEnv.ANTHROPIC_API_KEY && { betas: ["context-1m-2025-08-07"] }),
1203
- includePartialMessages: true,
1277
+ opts,
1278
+ providerConfig,
1204
1279
  stderr: stderrCallback,
1205
- };
1280
+ });
1206
1281
 
1207
1282
  // Crash retry: if subprocess exits with non-zero code before producing events,
1208
1283
  // clean up and retry once with a fresh query before surfacing the error.
@@ -1252,21 +1327,28 @@ export class ClaudeAgentSdkProvider implements AIProvider {
1252
1327
  };
1253
1328
  };
1254
1329
 
1255
- const { generator: streamGen, controller: initialCtrl } = createMessageChannel();
1330
+ // A new session's first attempt takes over the CLI `prewarm` started for it, if that
1331
+ // is exactly the process it would have spawned; otherwise it spawns one as always.
1332
+ const spare = crashRetryCount === 0 && isFirstMessage && !shouldFork
1333
+ ? this.warmSpares.adopt(sessionId, spawnFingerprint(queryOptions), { canUseTool, preToolUse: preToolUseHook, stderr: stderrCallback })
1334
+ : undefined;
1335
+ const channel = spare ? undefined : createMessageChannel();
1336
+ const initialCtrl = spare?.controller ?? channel!.controller;
1256
1337
  // On crash retry, use buildRetryMsg to get the latest user message (not the stale firstMsg)
1257
1338
  const initRetry = crashRetryCount > 0 ? buildRetryMsg() : null;
1258
1339
  initialCtrl.push(initRetry?.msg ?? firstMsg);
1259
1340
  const initContent = initRetry?.lastUserContent ?? modelInput;
1260
1341
  const initImages = initRetry?.lastUserImages ?? opts?.images;
1261
1342
 
1262
- const initialQuery = query({
1263
- prompt: streamGen,
1343
+ const initialQuery = spare?.query ?? query({
1344
+ prompt: channel!.generator,
1264
1345
  options: {
1265
1346
  ...queryOptions,
1266
1347
  ...(permissionHooks && { hooks: permissionHooks }),
1267
1348
  canUseTool,
1268
1349
  } as any,
1269
1350
  });
1351
+ if (spare) console.log(`[sdk] session=${sessionId} took over the warm CLI started ${spare.ageMs} ms ago`);
1270
1352
  this.streamingSessions.set(sessionId, { meta, query: initialQuery, controller: initialCtrl, lastUserContent: initContent, lastUserImages: initImages });
1271
1353
  this.activeQueries.set(sessionId, initialQuery);
1272
1354
  let eventSource: AsyncIterable<any> = initialQuery;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * A Claude CLI started before the chat that will use it exists.
3
+ *
4
+ * A new chat's first message used to wait for the CLI to boot before anything reached the
5
+ * API. Measured against a local stub API, so the figure is the CLI's own: 1.33–1.53 s from
6
+ * the message to the request, against 37–43 ms for a CLI started a few seconds earlier and
7
+ * waiting on stdin. The price is ~500 MB of RAM (the CLI plus the MCP servers it starts)
8
+ * and ~2.5% of a core while it waits — hence spares exist only while a new-chat composer is
9
+ * open, expire when nobody touches it, and are capped.
10
+ *
11
+ * A spare is spawned under a session id chosen now. `claim` hands that id to the next chat
12
+ * created in the project, and that chat's first turn takes the process over through `adopt`
13
+ * — but only when every option it would spawn a CLI with is the one the spare was spawned
14
+ * with. Any difference (another model, a rotated token, an edited MCP list) closes the spare
15
+ * and the turn starts cold, so a stale spare can cost the speed-up but never the behaviour.
16
+ * A spare closed unused has written nothing (the CLI creates the transcript on the first
17
+ * message), which is what lets its id go on to a cold start.
18
+ */
19
+ import { createHash } from "node:crypto";
20
+
21
+ /** The per-turn callbacks a CLI is spawned with. A spare's forward to the turn that adopts it. */
22
+ export interface SpareHandlers {
23
+ canUseTool: (...args: any[]) => Promise<any>;
24
+ preToolUse: (...args: any[]) => Promise<any>;
25
+ stderr: (chunk: string) => void;
26
+ }
27
+
28
+ export interface SpareProcess<Q> {
29
+ query: Q;
30
+ controller: { push(msg: unknown): void; done(): void };
31
+ }
32
+
33
+ interface Spare<Q> extends SpareProcess<Q> {
34
+ key: string;
35
+ sessionId: string;
36
+ fingerprint: string;
37
+ startedAt: number;
38
+ claimed: boolean;
39
+ handlers?: SpareHandlers;
40
+ /** What the CLI wrote to stderr before a turn took it, handed to that turn's handler. */
41
+ stderr: string;
42
+ timer?: ReturnType<typeof setTimeout>;
43
+ }
44
+
45
+ export interface WarmSpareLimits {
46
+ /** How long a spare nobody claims stays, from the last `offer` for its key. */
47
+ idleMs: number;
48
+ /** How long a claimed spare waits for its session's first message. */
49
+ claimedMs: number;
50
+ /** Spares alive at once, across every project. */
51
+ max: number;
52
+ }
53
+
54
+ const DEFAULT_LIMITS: WarmSpareLimits = { idleMs: 5 * 60_000, claimedMs: 60_000, max: 2 };
55
+
56
+ export class WarmSpares<Q extends { close(): void; initializationResult?(): Promise<unknown> }> {
57
+ private readonly spares = new Map<string, Spare<Q>>();
58
+
59
+ constructor(private readonly limits: WarmSpareLimits = DEFAULT_LIMITS) {}
60
+
61
+ /**
62
+ * Keep a spare ready for `key`. One already waiting there with the same fingerprint is kept
63
+ * and its expiry pushed back; one with any other is replaced. Returns the waiting spare's
64
+ * session id.
65
+ */
66
+ offer(key: string, fingerprint: string, start: (sessionId: string, callbacks: SpareHandlers) => SpareProcess<Q>): string {
67
+ const waiting = this.waiting(key);
68
+ if (waiting?.fingerprint === fingerprint) {
69
+ this.expireIn(waiting, this.limits.idleMs);
70
+ return waiting.sessionId;
71
+ }
72
+ if (waiting) this.close(waiting);
73
+ // Oldest first, and a claimed spare last: its first message is at most seconds away.
74
+ for (const victim of [...this.spares.values()].sort((a, b) => Number(a.claimed) - Number(b.claimed))) {
75
+ if (this.spares.size < this.limits.max) break;
76
+ this.close(victim);
77
+ }
78
+
79
+ const spare: Spare<Q> = {
80
+ key, fingerprint, sessionId: crypto.randomUUID(), startedAt: Date.now(), claimed: false, stderr: "",
81
+ } as Spare<Q>;
82
+ const callbacks: SpareHandlers = {
83
+ // Nothing can ask before a turn has pushed a message; refusing is the safe answer anyway.
84
+ canUseTool: (...args) => spare.handlers
85
+ ? spare.handlers.canUseTool(...args)
86
+ : Promise.resolve({ behavior: "deny", message: "No turn has taken this process over yet" }),
87
+ preToolUse: (...args) => spare.handlers ? spare.handlers.preToolUse(...args) : Promise.resolve({}),
88
+ stderr: (chunk) => {
89
+ if (spare.handlers) spare.handlers.stderr(chunk);
90
+ else spare.stderr = (spare.stderr + chunk).slice(-2048);
91
+ },
92
+ };
93
+ Object.assign(spare, start(spare.sessionId, callbacks));
94
+ this.spares.set(spare.sessionId, spare);
95
+ this.expireIn(spare, this.limits.idleMs);
96
+ // A CLI that dies during startup (a broken MCP entry, a missing binary) says so here;
97
+ // dropping it keeps a turn from adopting a process that is already gone.
98
+ spare.query.initializationResult?.().catch(() => {
99
+ if (this.spares.get(spare.sessionId) === spare) this.close(spare);
100
+ });
101
+ return spare.sessionId;
102
+ }
103
+
104
+ /** Hand the spare waiting for `key` to the session being created there. */
105
+ claim(key: string): string | undefined {
106
+ const spare = this.waiting(key);
107
+ if (!spare) return undefined;
108
+ spare.claimed = true;
109
+ this.expireIn(spare, this.limits.claimedMs);
110
+ return spare.sessionId;
111
+ }
112
+
113
+ /**
114
+ * Take over the spare started for `sessionId`, if the turn would have spawned exactly it.
115
+ * One that differs is closed rather than kept: its session is starting cold, and no other
116
+ * session can have its id.
117
+ */
118
+ adopt(sessionId: string, fingerprint: string, handlers: SpareHandlers): (SpareProcess<Q> & { ageMs: number }) | undefined {
119
+ const spare = this.spares.get(sessionId);
120
+ if (!spare) return undefined;
121
+ this.forget(spare);
122
+ if (spare.fingerprint !== fingerprint) {
123
+ console.log(`[sdk] session=${sessionId} warm CLI does not match this turn's options — starting cold`);
124
+ this.stop(spare);
125
+ return undefined;
126
+ }
127
+ spare.handlers = handlers;
128
+ if (spare.stderr) handlers.stderr(spare.stderr);
129
+ return { query: spare.query, controller: spare.controller, ageMs: Date.now() - spare.startedAt };
130
+ }
131
+
132
+ closeAll(): void {
133
+ for (const spare of [...this.spares.values()]) this.close(spare);
134
+ }
135
+
136
+ private waiting(key: string): Spare<Q> | undefined {
137
+ for (const spare of this.spares.values()) if (spare.key === key && !spare.claimed) return spare;
138
+ return undefined;
139
+ }
140
+
141
+ private expireIn(spare: Spare<Q>, ms: number): void {
142
+ clearTimeout(spare.timer);
143
+ spare.timer = setTimeout(() => this.close(spare), ms);
144
+ spare.timer.unref?.();
145
+ }
146
+
147
+ private close(spare: Spare<Q>): void {
148
+ this.forget(spare);
149
+ this.stop(spare);
150
+ }
151
+
152
+ private forget(spare: Spare<Q>): void {
153
+ clearTimeout(spare.timer);
154
+ this.spares.delete(spare.sessionId);
155
+ }
156
+
157
+ private stop(spare: Spare<Q>): void {
158
+ spare.controller.done();
159
+ spare.query.close();
160
+ }
161
+ }
162
+
163
+ /**
164
+ * A digest of every option a CLI is spawned with but its session id. Functions do not
165
+ * serialise and have no say; everything else — the environment and its token included —
166
+ * does, which is also why this is a digest and not the text.
167
+ */
168
+ export function spawnFingerprint(options: Record<string, unknown>): string {
169
+ const { sessionId: _sessionId, ...rest } = options;
170
+ return createHash("sha256").update(JSON.stringify(rest, sortKeys)).digest("hex");
171
+ }
172
+
173
+ function sortKeys(_key: string, value: unknown): unknown {
174
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
175
+ return Object.fromEntries(Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
176
+ }
@@ -9,5 +9,6 @@ export type {
9
9
  UsageInfo,
10
10
  LimitBucket,
11
11
  SendMessageOpts,
12
+ PrewarmInput,
12
13
  ModelOption,
13
14
  } from "../types/chat.ts";
@@ -33,8 +33,10 @@ import { globalWebSocket } from "./ws/global.ts";
33
33
  import { groupChatWebSocket } from "./ws/group-chat.ts";
34
34
  import { remoteDesktopWebSocket } from "./ws/remote-desktop.ts";
35
35
  import { lspWebSocket } from "./ws/lsp.ts";
36
+ import { androidWebSocket } from "./ws/android.ts";
36
37
  import { lspManager } from "../services/lsp/lsp-manager.ts";
37
38
  import { isRemoteDesktopEnabled } from "../services/remote-desktop/remote-desktop-flag.ts";
39
+ import { isAndroidEmulatorEnabled } from "../services/android/android-flag.ts";
38
40
  import { ok, err } from "../types/api.ts";
39
41
 
40
42
  /** Tee console.log/error to ~/.ppm/ppm.log while preserving terminal output */
@@ -239,6 +241,12 @@ app.get("/api/system/event-loop", async (c) => {
239
241
  import { remoteDesktopRoutes } from "./routes/remote-desktop.ts";
240
242
  app.route("/api/remote-desktop", remoteDesktopRoutes);
241
243
 
244
+ // Android emulator — OFF by default, opt-in via ANDROID_EMULATOR_ENABLED=1, see android-flag.ts.
245
+ // Unlike remote desktop this spawns multi-gigabyte emulator processes, and most hosts have no
246
+ // Android SDK at all, so it stays dark until somebody asks for it.
247
+ import { androidRoutes } from "./routes/android.ts";
248
+ app.route("/api/android", androidRoutes);
249
+
242
250
  // Finishes an OAuth loopback login started from another device
243
251
  import { loopbackRoutes } from "./routes/oauth-loopback.ts";
244
252
  app.route("/api/loopback", loopbackRoutes);
@@ -270,6 +278,10 @@ app.route("/api/jira", jiraRoutes);
270
278
  import { schedulesRoutes } from "./routes/schedules.ts";
271
279
  app.route("/api/schedules", schedulesRoutes);
272
280
 
281
+ // Session trace — browser logs in, a session's timeline out
282
+ import { traceRoutes } from "./routes/trace.ts";
283
+ app.route("/api/trace", traceRoutes);
284
+
273
285
  // AI resources (skills / agents / commands) management
274
286
  import { aiResourcesRoutes } from "./routes/ai-resources.ts";
275
287
  app.route("/api/ai-resources", aiResourcesRoutes);
@@ -879,6 +891,30 @@ if (process.argv.includes("__serve__")) {
879
891
  setInterval(runCleanup, 24 * 60 * 60 * 1000);
880
892
  }
881
893
 
894
+ // Same again for the session trace: age, then size. Skipped until something has been traced.
895
+ {
896
+ const { existsSync } = await import("node:fs");
897
+ const { getTraceDbPath } = await import("../services/session-trace/session-trace-db.ts");
898
+ const { cleanupSessionTrace } = await import("../services/session-trace/session-trace-cleanup.ts");
899
+
900
+ const runTraceCleanup = () => {
901
+ if (!existsSync(getTraceDbPath())) return;
902
+ try {
903
+ const { retention_days, max_size_mb } = configService.get("session_trace");
904
+ const { deletedByAge, deletedBySize, freedBytes } = cleanupSessionTrace(retention_days, max_size_mb);
905
+ const removed = deletedByAge + deletedBySize;
906
+ if (removed > 0) {
907
+ console.log(`[session-trace] pruned ${removed} rows (${(freedBytes / 1024 / 1024).toFixed(1)} MB freed)`);
908
+ }
909
+ } catch (e) {
910
+ console.error(`[session-trace] cleanup failed: ${(e as Error).message}`);
911
+ }
912
+ };
913
+
914
+ runTraceCleanup();
915
+ setInterval(runTraceCleanup, 24 * 60 * 60 * 1000);
916
+ }
917
+
882
918
  // On Windows the supervisor reaps the previous server's whole process tree
883
919
  // before respawning, so the port is released cleanly. A lingering bind can
884
920
  // still appear for a moment during an upgrade handoff, so wait for it to
@@ -959,6 +995,20 @@ if (process.argv.includes("__serve__")) {
959
995
  return new Response("WebSocket upgrade failed", { status: 400 });
960
996
  }
961
997
 
998
+ if (url.pathname === "/ws/android") {
999
+ // Same shape and the same reasoning as the remote-desktop branch above: an explicit
1000
+ // branch so this can never fall through to the terminal (shell) handler, with the flag
1001
+ // and `auth.enabled` re-checked independently of `isWsUpgradeAuthorized`, which returns
1002
+ // true unconditionally when PPM auth is disabled.
1003
+ if (!isAndroidEmulatorEnabled()) return new Response("Not Found", { status: 404 });
1004
+ if (!configService.get("auth").enabled) {
1005
+ return new Response("Forbidden: android emulator control requires PPM authentication to be enabled", { status: 403 });
1006
+ }
1007
+ const upgraded = server.upgrade(req, { data: { type: "android" } });
1008
+ if (upgraded) return undefined;
1009
+ return new Response("WebSocket upgrade failed", { status: 400 });
1010
+ }
1011
+
962
1012
  if (url.pathname.startsWith("/ws/project/")) {
963
1013
  const parts = url.pathname.split("/");
964
1014
  const projectName = decodeURIComponent(parts[3] ?? "");
@@ -1014,6 +1064,7 @@ if (process.argv.includes("__serve__")) {
1014
1064
  else if (t === "extensions") extensionWebSocket.open(ws);
1015
1065
  else if (t === "global") globalWebSocket.open(ws);
1016
1066
  else if (t === "remote-desktop") remoteDesktopWebSocket.open(ws);
1067
+ else if (t === "android") androidWebSocket.open(ws);
1017
1068
  else if (t === "terminal") terminalWebSocket.open(ws);
1018
1069
  else if (t === "lsp") lspWebSocket.open(ws);
1019
1070
  else ws.close(1008, "unknown socket type");
@@ -1025,6 +1076,7 @@ if (process.argv.includes("__serve__")) {
1025
1076
  else if (t === "extensions") extensionWebSocket.message(ws, msg);
1026
1077
  else if (t === "global") globalWebSocket.message(ws, msg);
1027
1078
  else if (t === "remote-desktop") remoteDesktopWebSocket.message(ws, msg);
1079
+ else if (t === "android") androidWebSocket.message(ws, msg);
1028
1080
  else if (t === "terminal") terminalWebSocket.message(ws, msg);
1029
1081
  else if (t === "lsp") lspWebSocket.message(ws, msg);
1030
1082
  },
@@ -1035,6 +1087,7 @@ if (process.argv.includes("__serve__")) {
1035
1087
  else if (t === "extensions") extensionWebSocket.close(ws);
1036
1088
  else if (t === "global") globalWebSocket.close(ws);
1037
1089
  else if (t === "remote-desktop") remoteDesktopWebSocket.close(ws);
1090
+ else if (t === "android") androidWebSocket.close(ws);
1038
1091
  else if (t === "terminal") terminalWebSocket.close(ws);
1039
1092
  else if (t === "lsp") lspWebSocket.close(ws);
1040
1093
  },
@@ -5,9 +5,20 @@
5
5
  * untouched. JSON compresses ~5-8x; a 542KB file index becomes ~80KB on the wire.
6
6
  */
7
7
  import type { MiddlewareHandler } from "hono";
8
+ import { gzip } from "node:zlib";
9
+ import { promisify } from "node:util";
8
10
 
9
11
  const MIN_SIZE_BYTES = 1024;
10
12
 
13
+ /**
14
+ * From this size on, compress on zlib's thread pool instead of the event loop. `Bun.gzipSync`
15
+ * stopped the server for 93 ms on each download of nxsys-workspace's 22 MB file index, while the
16
+ * pool left it waiting 3 ms at most. Below it the synchronous call blocks for well under a
17
+ * millisecond (0.3 ms for 200 KB) and answers sooner than the pool does.
18
+ */
19
+ const ASYNC_FROM_BYTES = 256 * 1024;
20
+ const gzipAsync = promisify(gzip);
21
+
11
22
  export const gzipJson: MiddlewareHandler = async (c, next) => {
12
23
  await next();
13
24
 
@@ -27,7 +38,8 @@ export const gzipJson: MiddlewareHandler = async (c, next) => {
27
38
  return;
28
39
  }
29
40
 
30
- const gzipped = Bun.gzipSync(new Uint8Array(body));
41
+ const bytes = new Uint8Array(body);
42
+ const gzipped = body.byteLength < ASYNC_FROM_BYTES ? Bun.gzipSync(bytes) : await gzipAsync(bytes);
31
43
  const headers = new Headers(res.headers);
32
44
  headers.set("Content-Encoding", "gzip");
33
45
  headers.set("Content-Length", String(gzipped.byteLength));