@hienlh/ppm 0.23.6 → 0.23.7

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 (701) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/CLAUDE.md +21 -1
  3. package/Dockerfile.test +8 -1
  4. package/assets/skills/ppm/SKILL.md +1 -1
  5. package/assets/skills/ppm/references/cli-reference.md +4 -4
  6. package/assets/skills/ppm/references/http-api.md +29 -1
  7. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
  8. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
  9. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
  10. package/dist/web/assets/{ai-resource-editor-Dn_wB-o5.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
  11. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
  12. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
  13. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
  14. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
  15. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
  16. package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
  17. package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
  18. package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
  19. package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
  20. package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
  21. package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
  22. package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
  23. package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
  24. package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
  25. package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
  26. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
  27. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
  28. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
  29. package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
  30. package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
  31. package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
  32. package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
  33. package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
  34. package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
  35. package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
  36. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
  37. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
  38. package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
  39. package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
  40. package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
  41. package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
  42. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
  43. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
  44. package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
  45. package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
  46. package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
  47. package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
  48. package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
  49. package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
  50. package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
  51. package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
  52. package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
  53. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
  54. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
  55. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
  56. package/dist/web/assets/{conflict-editor-BA3y-qSH.js → conflict-editor-BpKW_vbL.js} +1 -1
  57. package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
  58. package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
  59. package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
  60. package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
  61. package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
  62. package/dist/web/assets/{csv-preview-BioxkrQF.js → csv-preview-COYdTABa.js} +1 -1
  63. package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
  64. package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
  65. package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
  66. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
  67. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
  68. package/dist/web/assets/{database-viewer-BSoJ0E6p.js → database-viewer-BQcBqCKm.js} +1 -1
  69. package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
  70. package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
  71. package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
  72. package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
  73. package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
  74. package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
  75. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
  76. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
  77. package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
  78. package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
  79. package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
  80. package/dist/web/assets/{designs-sidebar-panel-DHh5QsH9.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
  81. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
  82. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
  83. package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
  84. package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
  85. package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
  86. package/dist/web/assets/{diff-viewer-lctWoSmG.js → diff-viewer-Bj4DT6Mj.js} +1 -1
  87. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
  88. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
  89. package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
  90. package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
  91. package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
  92. package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
  93. package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
  94. package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
  95. package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
  96. package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
  97. package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
  98. package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
  99. package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
  100. package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
  101. package/dist/web/assets/{extension-manager-section-rbkXsZVR.js → extension-manager-section-Bu0qcB2i.js} +1 -1
  102. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
  103. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
  104. package/dist/web/assets/{extension-webview-uPO0WgCq.js → extension-webview-G_WJ0N52.js} +1 -1
  105. package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
  106. package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
  107. package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
  108. package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
  109. package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
  110. package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
  111. package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
  112. package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
  113. package/dist/web/assets/{files-settings-section-CT7mDb0L.js → files-settings-section-ChZ_CynX.js} +1 -1
  114. package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
  115. package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
  116. package/dist/web/assets/format-bytes-__396eCN.js +1 -0
  117. package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
  118. package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
  119. package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
  120. package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
  121. package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
  122. package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
  123. package/dist/web/assets/{general-settings-section-DANPfMRN.js → general-settings-section-MSvDEbFa.js} +1 -1
  124. package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
  125. package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
  126. package/dist/web/assets/{git-log-panel-BJPkLiEw.js → git-log-panel-gw5_a6j3.js} +1 -1
  127. package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
  128. package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
  129. package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
  130. package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
  131. package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
  132. package/dist/web/assets/{glide-data-grid-R4PcAntf.js → glide-data-grid-Db2Cl26B.js} +5 -5
  133. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
  134. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
  135. package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
  136. package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
  137. package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
  138. package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
  139. package/dist/web/assets/index-CtAvmybi.js +52 -0
  140. package/dist/web/assets/index-CtAvmybi.js.br +0 -0
  141. package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
  142. package/dist/web/assets/index-DeCJasyy.css +1 -0
  143. package/dist/web/assets/index-DeCJasyy.css.br +0 -0
  144. package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
  145. package/dist/web/assets/{jira-watcher-section-DHRoyWcG.js → jira-watcher-section-CKSI1Alo.js} +1 -1
  146. package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
  147. package/dist/web/assets/{keyboard-shortcuts-section-BKej4mUf.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
  148. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
  149. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
  150. package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
  151. package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
  152. package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
  153. package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
  154. package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
  155. package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
  156. package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
  157. package/dist/web/assets/{markdown-renderer-BHtYqkYZ.js → markdown-renderer-D05fAr57.js} +2 -2
  158. package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
  159. package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
  160. package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
  161. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
  162. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
  163. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
  164. package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
  165. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
  166. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
  167. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
  168. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
  169. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
  170. package/dist/web/assets/{new-design-dialog-DS_XrpTG.js → new-design-dialog-BgmQopJM.js} +1 -1
  171. package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
  172. package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
  173. package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
  174. package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
  175. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
  176. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
  177. package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
  178. package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
  179. package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
  180. package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
  181. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
  182. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
  183. package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
  184. package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
  185. package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
  186. package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
  187. package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
  188. package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
  189. package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
  190. package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
  191. package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
  192. package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
  193. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
  194. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
  195. package/dist/web/assets/{ppmbot-settings-section-D8AES1BA.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
  196. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
  197. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
  198. package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
  199. package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
  200. package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
  201. package/dist/web/assets/{problems-panel-DTBG4beI.js → problems-panel-BgY8oyo9.js} +1 -1
  202. package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
  203. package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
  204. package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
  205. package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
  206. package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
  207. package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
  208. package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
  209. package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
  210. package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
  211. package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
  212. package/dist/web/assets/{proxy-settings-section-CqtmbeRj.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
  213. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
  214. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
  215. package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
  216. package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
  217. package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
  218. package/dist/web/assets/{remote-desktop-clipboard-notice-Djt6cpNL.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
  219. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
  220. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
  221. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
  222. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
  223. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
  224. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
  225. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
  226. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
  227. package/dist/web/assets/{remote-desktop-readiness-gate-DNJF8TcF.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
  228. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
  229. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
  230. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
  231. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
  232. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
  233. package/dist/web/assets/{schedules-settings-section-BKoPovy2.js → schedules-settings-section-CvbjQM8z.js} +1 -1
  234. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
  235. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
  236. package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
  237. package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
  238. package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
  239. package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
  240. package/dist/web/assets/services-panel-CimW47P8.js +1 -0
  241. package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
  242. package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
  243. package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
  244. package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
  245. package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
  246. package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
  247. package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
  248. package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
  249. package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
  250. package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
  251. package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
  252. package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
  253. package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
  254. package/dist/web/assets/{sql-query-editor-BjIMi9Wk.js → sql-query-editor-Dn-cgDrW.js} +1 -1
  255. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
  256. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
  257. package/dist/web/assets/{sqlite-viewer-BNcA6Irq.js → sqlite-viewer-B0NfaMjq.js} +1 -1
  258. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
  259. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
  260. package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
  261. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
  262. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
  263. package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
  264. package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
  265. package/dist/web/assets/{tab-host-window-content-CIRGNCvi.js → tab-host-window-content-CSrcmKNG.js} +1 -1
  266. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
  267. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
  268. package/dist/web/assets/{team-member-sheet-CwXpLi3X.js → team-member-sheet-D4X6nh-x.js} +2 -2
  269. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
  270. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
  271. package/dist/web/assets/{team-member-window-content-4swiiDz7.js → team-member-window-content-BxkbGVIL.js} +1 -1
  272. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
  273. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
  274. package/dist/web/assets/{terminal-tab-BGcdtMMT.js → terminal-tab-BYo34IqU.js} +3 -3
  275. package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
  276. package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
  277. package/dist/web/assets/{tool-cards-D0-krtA2.js → tool-cards-DvXjOped.js} +4 -4
  278. package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
  279. package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
  280. package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
  281. package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
  282. package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
  283. package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
  284. package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
  285. package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
  286. package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
  287. package/dist/web/assets/{use-monaco-theme-C88KphGx.js → use-monaco-theme-UGOzyIhv.js} +1 -1
  288. package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
  289. package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
  290. package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
  291. package/dist/web/assets/{use-websocket-Chk9guIU.js → use-websocket-Dpl21cHG.js} +1 -1
  292. package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
  293. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
  294. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
  295. package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
  296. package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
  297. package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
  298. package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
  299. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
  300. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
  301. package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
  302. package/dist/web/index.html +20 -20
  303. package/dist/web/index.html.br +0 -0
  304. package/dist/web/index.html.gz +0 -0
  305. package/dist/web/sw.js +1 -1
  306. package/dist/web/sw.js.br +0 -0
  307. package/dist/web/sw.js.gz +0 -0
  308. package/docs/deployment-guide.md +23 -0
  309. package/package.json +1 -1
  310. package/release-from-worktree.sh +224 -0
  311. package/src/cli/commands/config-cmd.ts +12 -0
  312. package/src/providers/claude-agent-sdk.ts +65 -2
  313. package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
  314. package/src/providers/codex-app-server/codex-provider.ts +39 -7
  315. package/src/providers/provider-probe.ts +63 -0
  316. package/src/providers/registry.ts +109 -29
  317. package/src/server/index.ts +9 -0
  318. package/src/server/middleware/auth.ts +5 -1
  319. package/src/server/routes/cross-origin-guard.ts +20 -0
  320. package/src/server/routes/git.ts +40 -4
  321. package/src/server/routes/lsp.ts +97 -4
  322. package/src/server/routes/resources.ts +72 -9
  323. package/src/server/routes/settings.ts +19 -1
  324. package/src/server/routes/speech.ts +66 -0
  325. package/src/server/routes/system-services.ts +76 -0
  326. package/src/server/routes/tunnel.ts +33 -1
  327. package/src/server/ws/chat.ts +74 -3
  328. package/src/services/codex-account-login.ts +26 -2
  329. package/src/services/codex-reset-credit.service.ts +16 -3
  330. package/src/services/compaction-savings.ts +127 -0
  331. package/src/services/db.service.ts +123 -8
  332. package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
  333. package/src/services/git-refs/for-each-ref.ts +118 -0
  334. package/src/services/git.service.ts +25 -2
  335. package/src/services/host-info/spawn-runner.ts +48 -4
  336. package/src/services/jsonl-transcript-parser.ts +7 -42
  337. package/src/services/lsp/lsp-install.ts +289 -0
  338. package/src/services/lsp/lsp-manager.ts +160 -29
  339. package/src/services/lsp/server-registry.ts +120 -4
  340. package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
  341. package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
  342. package/src/services/read-lines.ts +54 -0
  343. package/src/services/speech-to-text/whisper-catalog.ts +142 -0
  344. package/src/services/speech-to-text/whisper-download.ts +113 -0
  345. package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
  346. package/src/services/speech-to-text/whisper-install.service.ts +247 -0
  347. package/src/services/speech-to-text/whisper-paths.ts +62 -0
  348. package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
  349. package/src/services/supervisor.ts +94 -11
  350. package/src/services/system-metrics/cpu-details-linux.ts +252 -0
  351. package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
  352. package/src/services/system-metrics/device-collector-linux.ts +31 -0
  353. package/src/services/system-metrics/device-collector-types.ts +40 -0
  354. package/src/services/system-metrics/disk-devices-linux.ts +156 -0
  355. package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
  356. package/src/services/system-metrics/fans-linux.ts +51 -0
  357. package/src/services/system-metrics/gpu-api-versions.ts +120 -0
  358. package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
  359. package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
  360. package/src/services/system-metrics/hardware-inventory.ts +50 -0
  361. package/src/services/system-metrics/linux-fs.ts +43 -0
  362. package/src/services/system-metrics/memory-darwin.ts +91 -0
  363. package/src/services/system-metrics/memory-linux.ts +156 -0
  364. package/src/services/system-metrics/net-devices-linux.ts +114 -0
  365. package/src/services/system-metrics/net-inventory-linux.ts +100 -0
  366. package/src/services/system-metrics/partitions-linux.ts +158 -0
  367. package/src/services/system-metrics/process-collector-linux.ts +58 -6
  368. package/src/services/system-metrics/process-collector-types.ts +8 -1
  369. package/src/services/system-metrics/process-details-darwin.ts +166 -0
  370. package/src/services/system-metrics/process-details-linux.ts +150 -0
  371. package/src/services/system-metrics/process-grouping.ts +2 -1
  372. package/src/services/system-metrics/process-rows-builder.ts +2 -0
  373. package/src/services/system-metrics/process-swap-linux.ts +37 -0
  374. package/src/services/system-metrics/signal-executor.ts +84 -0
  375. package/src/services/system-metrics/signal-request-handler.ts +92 -0
  376. package/src/services/system-metrics/system-metrics-platform.ts +30 -4
  377. package/src/services/system-metrics/system-metrics-tick.ts +73 -4
  378. package/src/services/system-metrics/system-metrics.service.ts +87 -2
  379. package/src/services/system-metrics/udev-db.ts +40 -0
  380. package/src/services/system-services/app-cgroup-linux.ts +115 -0
  381. package/src/services/system-services/app-icon-service.ts +31 -0
  382. package/src/services/system-services/app-icons-linux.ts +124 -0
  383. package/src/services/system-services/apps-linux.ts +174 -0
  384. package/src/services/system-services/desktop-entry.ts +103 -0
  385. package/src/services/system-services/service-guard.ts +124 -0
  386. package/src/services/system-services/systemd-collector.ts +203 -0
  387. package/src/services/system-services/systemd-parse.ts +162 -0
  388. package/src/shared/prompt-cache-idle.ts +197 -0
  389. package/src/shared/turn-usage.ts +85 -1
  390. package/src/types/chat.ts +27 -0
  391. package/src/types/config.ts +14 -0
  392. package/src/types/git.ts +41 -0
  393. package/src/types/system-hardware.ts +137 -0
  394. package/src/types/system-metrics.ts +231 -2
  395. package/src/types/system-services.ts +73 -0
  396. package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
  397. package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
  398. package/src/web/components/chat/chat-tab.tsx +3 -0
  399. package/src/web/components/chat/compaction-divider.tsx +48 -0
  400. package/src/web/components/chat/idle-cache-notice.tsx +67 -0
  401. package/src/web/components/chat/message-input.tsx +48 -13
  402. package/src/web/components/chat/message-list.tsx +15 -0
  403. package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
  404. package/src/web/components/editor/code-editor.tsx +1 -0
  405. package/src/web/components/editor/editor-language-service.tsx +11 -3
  406. package/src/web/components/editor/lsp-status.tsx +115 -13
  407. package/src/web/components/git/branch-picker.tsx +419 -0
  408. package/src/web/components/git/branch-select.tsx +34 -0
  409. package/src/web/components/git/create-worktree-dialog.tsx +17 -16
  410. package/src/web/components/git/git-repo-picker.tsx +28 -40
  411. package/src/web/components/layout/status-bar.tsx +42 -19
  412. package/src/web/components/settings/accounts/account-card.tsx +5 -1
  413. package/src/web/components/settings/ai-settings-section.tsx +67 -3
  414. package/src/web/components/settings/appearance-settings-section.tsx +2 -28
  415. package/src/web/components/settings/language-servers-section.tsx +362 -0
  416. package/src/web/components/settings/settings-categories.ts +8 -3
  417. package/src/web/components/settings/settings-section-content.tsx +2 -0
  418. package/src/web/components/settings/voice-settings-section.tsx +283 -0
  419. package/src/web/components/system/apps/app-row.tsx +110 -0
  420. package/src/web/components/system/apps/app-rows.ts +140 -0
  421. package/src/web/components/system/apps/apps-panel.tsx +129 -0
  422. package/src/web/components/system/metric-chart-canvas.tsx +79 -3
  423. package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
  424. package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
  425. package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
  426. package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
  427. package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
  428. package/src/web/components/system/overview-cards/net-card.tsx +11 -6
  429. package/src/web/components/system/overview-device-target.ts +69 -0
  430. package/src/web/components/system/overview-panel.tsx +15 -1
  431. package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
  432. package/src/web/components/system/performance/cpu-detail.tsx +220 -0
  433. package/src/web/components/system/performance/detail-parts.tsx +149 -0
  434. package/src/web/components/system/performance/device-list.ts +139 -0
  435. package/src/web/components/system/performance/disk-detail.tsx +64 -0
  436. package/src/web/components/system/performance/fans-detail.tsx +35 -0
  437. package/src/web/components/system/performance/gpu-detail.tsx +116 -0
  438. package/src/web/components/system/performance/memory-detail.tsx +109 -0
  439. package/src/web/components/system/performance/nic-detail.tsx +55 -0
  440. package/src/web/components/system/performance/partition-list.tsx +79 -0
  441. package/src/web/components/system/performance/performance-panel.tsx +206 -0
  442. package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
  443. package/src/web/components/system/process-columns-grid.ts +5 -3
  444. package/src/web/components/system/process-details-dialog.tsx +116 -0
  445. package/src/web/components/system/process-group-row.tsx +6 -1
  446. package/src/web/components/system/process-row-format.ts +6 -0
  447. package/src/web/components/system/process-row-menu.tsx +72 -0
  448. package/src/web/components/system/process-row.tsx +7 -1
  449. package/src/web/components/system/process-table-model.ts +1 -1
  450. package/src/web/components/system/process-table-sort.ts +8 -4
  451. package/src/web/components/system/process-table-toolbar.tsx +10 -2
  452. package/src/web/components/system/process-table-totals.ts +3 -0
  453. package/src/web/components/system/process-table.tsx +25 -2
  454. package/src/web/components/system/services/service-action-confirm.tsx +100 -0
  455. package/src/web/components/system/services/service-columns.ts +103 -0
  456. package/src/web/components/system/services/service-details-sheet.tsx +97 -0
  457. package/src/web/components/system/services/service-resources.ts +105 -0
  458. package/src/web/components/system/services/service-row.tsx +146 -0
  459. package/src/web/components/system/services/service-rows.ts +92 -0
  460. package/src/web/components/system/services/service-sort.ts +90 -0
  461. package/src/web/components/system/services/services-header.tsx +51 -0
  462. package/src/web/components/system/services/services-panel.tsx +207 -0
  463. package/src/web/components/system/services/use-services.ts +92 -0
  464. package/src/web/components/system/sortable-header.tsx +13 -8
  465. package/src/web/components/system/sysmon-preferences.tsx +85 -0
  466. package/src/web/components/system/system-monitor-body.tsx +101 -43
  467. package/src/web/components/system/system-monitor-window-content.tsx +2 -3
  468. package/src/web/components/system/use-process-signal.ts +87 -0
  469. package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
  470. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  471. package/src/web/components/ui/dialog.tsx +14 -1
  472. package/src/web/components/ui/search-select.tsx +279 -0
  473. package/src/web/components/ui/start-ellipsis.tsx +18 -0
  474. package/src/web/hooks/use-chat.ts +28 -0
  475. package/src/web/hooks/use-global-keybindings.ts +7 -5
  476. package/src/web/hooks/use-lsp.ts +23 -2
  477. package/src/web/hooks/use-minute-clock.ts +20 -0
  478. package/src/web/hooks/use-whisper-voice-input.ts +113 -0
  479. package/src/web/lib/api-tunnels.ts +19 -0
  480. package/src/web/lib/branch-select-items.ts +29 -0
  481. package/src/web/lib/cpu-graph-mode.ts +90 -0
  482. package/src/web/lib/format-bytes.ts +14 -0
  483. package/src/web/lib/git-ref-picker.ts +120 -0
  484. package/src/web/lib/lsp/lsp-client.ts +32 -0
  485. package/src/web/lib/search-select-rows.ts +55 -0
  486. package/src/web/lib/temperature.ts +27 -0
  487. package/src/web/lib/voice-wav.ts +69 -0
  488. package/src/web/stores/git-status-store.ts +31 -17
  489. package/src/web/stores/keybindings-store.ts +14 -1
  490. package/src/web/stores/settings-store.ts +65 -0
  491. package/src/web/styles/globals.css +11 -0
  492. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js +0 -1
  493. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.br +0 -0
  494. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.gz +0 -0
  495. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.br +0 -0
  496. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.gz +0 -0
  497. package/dist/web/assets/ai-settings-section-CEbW8jRy.js +0 -1
  498. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.br +0 -0
  499. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.gz +0 -0
  500. package/dist/web/assets/ai-settings-section-D-mwEYFZ.js +0 -1
  501. package/dist/web/assets/api-client-BgedDTvo.js +0 -1
  502. package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
  503. package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
  504. package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
  505. package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
  506. package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
  507. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js +0 -1
  508. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.br +0 -0
  509. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.gz +0 -0
  510. package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
  511. package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
  512. package/dist/web/assets/branch-review-tab-MBuMWp_i.js +0 -1
  513. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.br +0 -0
  514. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.gz +0 -0
  515. package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
  516. package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
  517. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
  518. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
  519. package/dist/web/assets/chat-tab-DVvnqhw6.js +0 -1
  520. package/dist/web/assets/chat-tab-DVvnqhw6.js.br +0 -0
  521. package/dist/web/assets/chat-tab-DVvnqhw6.js.gz +0 -0
  522. package/dist/web/assets/chat-tab-DaEHva22.js +0 -15
  523. package/dist/web/assets/chat-tab-DaEHva22.js.br +0 -0
  524. package/dist/web/assets/chat-tab-DaEHva22.js.gz +0 -0
  525. package/dist/web/assets/code-editor-Bu9lhTVp.js +0 -7
  526. package/dist/web/assets/code-editor-Bu9lhTVp.js.br +0 -0
  527. package/dist/web/assets/code-editor-Bu9lhTVp.js.gz +0 -0
  528. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js +0 -1
  529. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.br +0 -0
  530. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.gz +0 -0
  531. package/dist/web/assets/conflict-editor-BA3y-qSH.js.br +0 -0
  532. package/dist/web/assets/conflict-editor-BA3y-qSH.js.gz +0 -0
  533. package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
  534. package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
  535. package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
  536. package/dist/web/assets/csv-preview-BioxkrQF.js.br +0 -0
  537. package/dist/web/assets/csv-preview-BioxkrQF.js.gz +0 -0
  538. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
  539. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
  540. package/dist/web/assets/database-viewer-BSoJ0E6p.js.br +0 -0
  541. package/dist/web/assets/database-viewer-BSoJ0E6p.js.gz +0 -0
  542. package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
  543. package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
  544. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
  545. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
  546. package/dist/web/assets/design-tab-iU2CviE3.js +0 -33
  547. package/dist/web/assets/design-tab-iU2CviE3.js.br +0 -0
  548. package/dist/web/assets/design-tab-iU2CviE3.js.gz +0 -0
  549. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.br +0 -0
  550. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.gz +0 -0
  551. package/dist/web/assets/dialog-B8clVkyi.js +0 -1
  552. package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
  553. package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
  554. package/dist/web/assets/diff-viewer-lctWoSmG.js.br +0 -0
  555. package/dist/web/assets/diff-viewer-lctWoSmG.js.gz +0 -0
  556. package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
  557. package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
  558. package/dist/web/assets/editor-language-service-fPG56hQO.js +0 -1
  559. package/dist/web/assets/editor-language-service-fPG56hQO.js.br +0 -0
  560. package/dist/web/assets/editor-language-service-fPG56hQO.js.gz +0 -0
  561. package/dist/web/assets/explorer-body-BgF7FsxI.js +0 -2
  562. package/dist/web/assets/explorer-body-BgF7FsxI.js.br +0 -0
  563. package/dist/web/assets/explorer-body-BgF7FsxI.js.gz +0 -0
  564. package/dist/web/assets/explorer-window-content-C21w_7lf.js +0 -1
  565. package/dist/web/assets/explorer-window-content-C21w_7lf.js.br +0 -0
  566. package/dist/web/assets/explorer-window-content-C21w_7lf.js.gz +0 -0
  567. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.br +0 -0
  568. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.gz +0 -0
  569. package/dist/web/assets/extension-webview-uPO0WgCq.js.br +0 -0
  570. package/dist/web/assets/extension-webview-uPO0WgCq.js.gz +0 -0
  571. package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
  572. package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
  573. package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
  574. package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
  575. package/dist/web/assets/files-settings-section-CT7mDb0L.js.br +0 -0
  576. package/dist/web/assets/files-settings-section-CT7mDb0L.js.gz +0 -0
  577. package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
  578. package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
  579. package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
  580. package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
  581. package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
  582. package/dist/web/assets/general-settings-section-DANPfMRN.js.br +0 -0
  583. package/dist/web/assets/general-settings-section-DANPfMRN.js.gz +0 -0
  584. package/dist/web/assets/git-log-panel-BJPkLiEw.js.br +0 -0
  585. package/dist/web/assets/git-log-panel-BJPkLiEw.js.gz +0 -0
  586. package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
  587. package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
  588. package/dist/web/assets/glide-data-grid-R4PcAntf.js.br +0 -0
  589. package/dist/web/assets/glide-data-grid-R4PcAntf.js.gz +0 -0
  590. package/dist/web/assets/group-chat-tab-BXMdo8w9.js +0 -1
  591. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.br +0 -0
  592. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.gz +0 -0
  593. package/dist/web/assets/index-C8nGqkKN.js +0 -52
  594. package/dist/web/assets/index-C8nGqkKN.js.br +0 -0
  595. package/dist/web/assets/index-C8nGqkKN.js.gz +0 -0
  596. package/dist/web/assets/index-DvClbTQx.css +0 -1
  597. package/dist/web/assets/index-DvClbTQx.css.br +0 -0
  598. package/dist/web/assets/index-DvClbTQx.css.gz +0 -0
  599. package/dist/web/assets/keybindings-store-BGKlQQAv.js +0 -1
  600. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.br +0 -0
  601. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.gz +0 -0
  602. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.br +0 -0
  603. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.gz +0 -0
  604. package/dist/web/assets/markdown-renderer-vDNuKjel.js +0 -1
  605. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
  606. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
  607. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js +0 -1
  608. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.br +0 -0
  609. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.gz +0 -0
  610. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.br +0 -0
  611. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.gz +0 -0
  612. package/dist/web/assets/notification-store-Dnnj20Ky.js +0 -1
  613. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
  614. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
  615. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
  616. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
  617. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
  618. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
  619. package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
  620. package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
  621. package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
  622. package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
  623. package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
  624. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
  625. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
  626. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.br +0 -0
  627. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.gz +0 -0
  628. package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
  629. package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
  630. package/dist/web/assets/problems-panel-DTBG4beI.js.br +0 -0
  631. package/dist/web/assets/problems-panel-DTBG4beI.js.gz +0 -0
  632. package/dist/web/assets/process-table-D_gR2XA6.js +0 -1
  633. package/dist/web/assets/process-table-D_gR2XA6.js.br +0 -0
  634. package/dist/web/assets/process-table-D_gR2XA6.js.gz +0 -0
  635. package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
  636. package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
  637. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.br +0 -0
  638. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.gz +0 -0
  639. package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
  640. package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
  641. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.br +0 -0
  642. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.gz +0 -0
  643. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js +0 -2
  644. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.br +0 -0
  645. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.gz +0 -0
  646. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js +0 -1
  647. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.br +0 -0
  648. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.gz +0 -0
  649. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.br +0 -0
  650. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.gz +0 -0
  651. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js +0 -1
  652. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.br +0 -0
  653. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.gz +0 -0
  654. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.br +0 -0
  655. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.gz +0 -0
  656. package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
  657. package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
  658. package/dist/web/assets/settings-body-k2qPgRFe.js +0 -2
  659. package/dist/web/assets/settings-body-k2qPgRFe.js.br +0 -0
  660. package/dist/web/assets/settings-body-k2qPgRFe.js.gz +0 -0
  661. package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
  662. package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
  663. package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
  664. package/dist/web/assets/settings-tab-Bb23VdBu.js +0 -1
  665. package/dist/web/assets/settings-window-content-ClarWusz.js +0 -1
  666. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.br +0 -0
  667. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.gz +0 -0
  668. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.br +0 -0
  669. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.gz +0 -0
  670. package/dist/web/assets/system-monitor-body-D0T3ggt2.js +0 -2
  671. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.br +0 -0
  672. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.gz +0 -0
  673. package/dist/web/assets/system-monitor-tab-I1Igmoey.js +0 -1
  674. package/dist/web/assets/system-monitor-window-content-C5SeUv1H.js +0 -1
  675. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.br +0 -0
  676. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.gz +0 -0
  677. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.br +0 -0
  678. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.gz +0 -0
  679. package/dist/web/assets/team-member-window-content-4swiiDz7.js.br +0 -0
  680. package/dist/web/assets/team-member-window-content-4swiiDz7.js.gz +0 -0
  681. package/dist/web/assets/terminal-tab-BGcdtMMT.js.br +0 -0
  682. package/dist/web/assets/terminal-tab-BGcdtMMT.js.gz +0 -0
  683. package/dist/web/assets/tool-cards-D0-krtA2.js.br +0 -0
  684. package/dist/web/assets/tool-cards-D0-krtA2.js.gz +0 -0
  685. package/dist/web/assets/use-inline-blame-pKaXyGU-.js +0 -16
  686. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.br +0 -0
  687. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.gz +0 -0
  688. package/dist/web/assets/use-lsp-71azTXQz.js +0 -6
  689. package/dist/web/assets/use-lsp-71azTXQz.js.br +0 -0
  690. package/dist/web/assets/use-lsp-71azTXQz.js.gz +0 -0
  691. package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
  692. package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
  693. package/dist/web/assets/video-preview-DxEX-uGo.js +0 -1
  694. package/dist/web/assets/video-preview-DxEX-uGo.js.br +0 -0
  695. package/dist/web/assets/video-preview-DxEX-uGo.js.gz +0 -0
  696. package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
  697. /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
  698. /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
  699. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
  700. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
  701. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
@@ -9,6 +9,8 @@ import { homedir } from "node:os";
9
9
  import type { ChatEvent, ChatMessage } from "../types/chat.ts";
10
10
  import { stringifyToolResultContent } from "../shared/tool-result-content.ts";
11
11
  import { stripSharedContext } from "../shared/provider-context.ts";
12
+ import { readLines } from "./read-lines.ts";
13
+ import { readCompactions, applyCompactions } from "./compaction-savings.ts";
12
14
 
13
15
  /**
14
16
  * How large a transcript this module will look at, for the callers that go
@@ -307,48 +309,6 @@ export function validateJsonlPath(inputPath: string, maxBytes = MAX_FILE_SIZE):
307
309
  return real;
308
310
  }
309
311
 
310
- /**
311
- * Yield a file's lines without holding the file in memory.
312
- *
313
- * `Bun.file().text()` plus `split("\n")` costs the whole transcript twice over —
314
- * 277MB resident for a 77MB file, which is what forced a cap low enough to
315
- * reject real sessions. Peak here is one chunk plus one line.
316
- */
317
- async function* readLines(filePath: string, fromByte = 0): AsyncGenerator<string> {
318
- const decoder = new TextDecoder();
319
- // Explicit reader rather than `for await` over the stream: the DOM lib's
320
- // ReadableStream is not typed as async-iterable, and the `finally` is what
321
- // releases it when a caller breaks early on `beforeUuid`.
322
- // One byte *before* the offset, so the first line the split produces is
323
- // always the tail of the record the offset fell inside — the empty string
324
- // when it fell exactly on a newline. That makes the drop below unconditional
325
- // instead of a boundary case, and a boundary case here silently costs a whole
326
- // record rather than a fragment.
327
- const file = fromByte > 0 ? Bun.file(filePath).slice(fromByte - 1) : Bun.file(filePath);
328
- const reader = file.stream().getReader();
329
- // A fragment is not always unparseable — the tail of one record is sometimes
330
- // a complete smaller document — so it has to go by position rather than be
331
- // left for `JSON.parse` to reject, or it enters as an invented message.
332
- let dropPartial = fromByte > 0;
333
- let buffered = "";
334
- try {
335
- while (true) {
336
- const { done, value } = await reader.read();
337
- if (done) break;
338
- buffered += decoder.decode(value, { stream: true });
339
- const lines = buffered.split("\n");
340
- buffered = lines.pop() ?? "";
341
- for (const line of lines) {
342
- if (dropPartial) { dropPartial = false; continue; }
343
- yield line;
344
- }
345
- }
346
- } finally {
347
- reader.releaseLock();
348
- }
349
- buffered += decoder.decode();
350
- if (buffered && !dropPartial) yield buffered;
351
- }
352
312
 
353
313
  /**
354
314
  * Read a JSONL transcript file, parse entries, apply merge/nest pipeline, return ChatMessage[].
@@ -418,6 +378,11 @@ export async function parseJsonlTranscript(
418
378
  const { mergeSubagentChildren } = await import("./subagent-transcript-merger.ts");
419
379
  mergeSubagentChildren(filePath.replace(/\.jsonl$/, ""), merged);
420
380
 
381
+ // An expanded segment opens with its own compact summary, so it needs the same
382
+ // divider the newest one gets — otherwise only the last compaction in a chat is
383
+ // labelled and the earlier ones read as ordinary messages.
384
+ applyCompactions(merged, await readCompactions(filePath).catch(() => new Map()));
385
+
421
386
  return merged.filter(
422
387
  (msg) => msg.content.trim().length > 0 || (msg.events && msg.events.length > 0),
423
388
  );
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Installing a language server, when someone presses Install.
3
+ *
4
+ * Nothing here runs because a file was opened. The editor says which server is missing and
5
+ * offers the button; pressing it is the consent, and that is the whole difference between this
6
+ * and an editor that fetches a binary off the network on its own.
7
+ *
8
+ * Four decisions worth keeping:
9
+ *
10
+ * - **Into `<ppm dir>/lsp-servers`, never `-g` and never `~/go/bin`.** A global
11
+ * `bun add typescript@5` replaces whatever TypeScript the user had installed globally, and a
12
+ * global bin directory is only found when it happens to be on the *service's* PATH — which
13
+ * for a systemd-started PPM is four entries and nothing of the sort. PPM's own directory is
14
+ * neither, `PPM_HOME` already isolates it for tests, and deleting it is the whole uninstall.
15
+ * `rustup` is the one exception, below.
16
+ * - **The packages come from the registry, by server id.** Nothing the browser sends is ever
17
+ * part of a command, so the route cannot be talked into installing something else.
18
+ * - **PPM installs servers, never toolchains.** `go install` needs a Go and
19
+ * `rustup component add` needs a rustup; where the host has neither, there is no button at
20
+ * all rather than one that fails when pressed.
21
+ * - **The directory gets a `package.json` before `bun add` runs.** Measured: `bun add` in a
22
+ * directory with no manifest does not create one there — it walks *up* to the nearest parent
23
+ * that has one and installs into that, leaving the directory it was asked about empty.
24
+ */
25
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
26
+ import path from "node:path";
27
+ import { resolveBunPath } from "../autostart-generator.ts";
28
+ import { getPpmDir } from "../ppm-dir.ts";
29
+ import {
30
+ installedBinaryPath,
31
+ installedServerEntry,
32
+ packageName,
33
+ type LanguageServerDefinition,
34
+ type LanguageServerInstall,
35
+ } from "./server-registry.ts";
36
+
37
+ /** Generous: a cold `go install` builds the server from source. 10.6 s here, minutes elsewhere. */
38
+ const INSTALL_TIMEOUT_MS = 5 * 60_000;
39
+ /** `rustup which` is a lookup, not work. Measured at 3 ms; anything near this is a hung host. */
40
+ const QUERY_TIMEOUT_MS = 10_000;
41
+
42
+ /** Where the Install button puts servers. Inside the PPM dir, so `PPM_HOME` isolates it. */
43
+ export function lspInstallDir(): string {
44
+ return path.join(getPpmDir(), "lsp-servers");
45
+ }
46
+
47
+ export interface RunResult {
48
+ code: number;
49
+ stdout: string;
50
+ stderr: string;
51
+ }
52
+
53
+ /**
54
+ * How this module runs a command.
55
+ *
56
+ * One injectable seam for all of it, so a test can drive an install with no toolchain on the
57
+ * machine — and named rather than `typeof Bun.spawn`, whose type widens the pipes back to a
58
+ * union with a raw file descriptor that `new Response()` will not take.
59
+ */
60
+ export type Runner = (
61
+ cmd: string[],
62
+ options: { cwd: string; env?: Record<string, string | undefined>; timeoutMs: number },
63
+ ) => Promise<RunResult>;
64
+
65
+ const runCommand: Runner = async (cmd, { cwd, env, timeoutMs }) => {
66
+ const proc = Bun.spawn(cmd, { cwd, env: env as Record<string, string> | undefined, stdout: "pipe", stderr: "pipe" });
67
+ const timer = setTimeout(() => proc.kill(), timeoutMs);
68
+ // Drained while it runs: a pipe nobody reads fills up, and a full pipe blocks the child
69
+ // instead of failing it, so awaiting the exit first can wait forever on a noisy install.
70
+ const [code, stdout, stderr] = await Promise.all([
71
+ proc.exited,
72
+ new Response(proc.stdout).text(),
73
+ new Response(proc.stderr).text(),
74
+ ]);
75
+ clearTimeout(timer);
76
+ return { code, stdout, stderr };
77
+ };
78
+
79
+ /**
80
+ * The binary that would carry out this plan, or null where the host has none.
81
+ *
82
+ * The lookup is `PATH`, deliberately: it is the same PATH a language server PPM starts will
83
+ * inherit, so a host where PPM cannot see the Go toolchain is also a host where gopls could
84
+ * not run `go list`. Offering the button there would install a server that cannot work.
85
+ */
86
+ export function installToolPath(plan: LanguageServerInstall): string | null {
87
+ if (plan.with === "bun") {
88
+ try {
89
+ return resolveBunPath();
90
+ } catch {
91
+ return null; // a compiled PPM on a host with no bun
92
+ }
93
+ }
94
+ // The PATH is passed explicitly because `Bun.which` otherwise reads the one the *process
95
+ // started with* and never looks at `process.env.PATH` again — measured: adding a directory to
96
+ // it changes nothing, and neither does emptying it. The tool is then spawned by the absolute
97
+ // path this returns, so the lookup and the run can never disagree.
98
+ return Bun.which(plan.with === "go" ? "go" : "rustup", { PATH: process.env.PATH ?? "" });
99
+ }
100
+
101
+ /** Whether the Install button can work here. The editor draws the button from this. */
102
+ export function canInstall(definition: LanguageServerDefinition): boolean {
103
+ return definition.install ? installToolPath(definition.install) !== null : false;
104
+ }
105
+
106
+ /**
107
+ * Where rustup says this server is, or null when the component is not installed.
108
+ *
109
+ * `rustup which` is both the lookup and the installed-check, and it has to be: the proxy in
110
+ * `~/.cargo/bin` exists whether or not the component does — measured on this host, with no
111
+ * rust-analyzer installed, `~/.cargo/bin/rust-analyzer` is right there pointing at rustup — so
112
+ * a path test would report a server that cannot start. It answers in 3 ms, and it answers for
113
+ * the toolchain `cwd` selects, which a symlink made at install time could not.
114
+ */
115
+ export async function rustupServerPath(
116
+ definition: LanguageServerDefinition,
117
+ cwd: string,
118
+ run: Runner = runCommand,
119
+ ): Promise<string | null> {
120
+ if (definition.install?.with !== "rustup") return null;
121
+ const rustup = installToolPath(definition.install);
122
+ if (!rustup) return null;
123
+ try {
124
+ const result = await run([rustup, "which", definition.command], { cwd, timeoutMs: QUERY_TIMEOUT_MS });
125
+ const found = result.stdout.trim();
126
+ return result.code === 0 && found ? found : null;
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+
132
+ /** One at a time: every install and uninstall shares one `package.json`, lockfile and toolchain. */
133
+ let queue: Promise<unknown> = Promise.resolve();
134
+ /** Keyed by operation *and* id, so a second Uninstall click joins that uninstall — never an install. */
135
+ const inFlight = new Map<string, Promise<void>>();
136
+
137
+ /**
138
+ * Install one server, and resolve once it is really there.
139
+ *
140
+ * Two clicks on one button — a second tab, an impatient user — join the same install rather
141
+ * than starting a second one over the first one's lockfile.
142
+ */
143
+ export function installLanguageServer(
144
+ definition: LanguageServerDefinition,
145
+ options: { projectPath?: string; run?: Runner } = {},
146
+ ): Promise<void> {
147
+ return enqueue(`install:${definition.id}`, () => install(definition, options.projectPath, options.run ?? runCommand));
148
+ }
149
+
150
+ /**
151
+ * Remove one server, running the exact inverse of what installed it.
152
+ *
153
+ * Offered only for a server PPM itself put there, which is a question about where it was
154
+ * *found* rather than about what is on this machine — `lsp-manager.availability` answers it
155
+ * with `origin`, and the route gates on that. A copy on `PATH` is the user's, one in a
156
+ * project's `node_modules` is the repository's, and the one PPM ships is its own dependency:
157
+ * deleting any of the three would be PPM tidying up after someone else.
158
+ *
159
+ * rustup is again the exception that reaches outside PPM's directory, for the same reason
160
+ * installing it did — the component belongs to a toolchain and there is no copy of PPM's to
161
+ * delete. Removing it is one `rustup component add` away from being back.
162
+ */
163
+ export function uninstallLanguageServer(
164
+ definition: LanguageServerDefinition,
165
+ options: { projectPath?: string; run?: Runner } = {},
166
+ ): Promise<void> {
167
+ return enqueue(`uninstall:${definition.id}`, () => uninstall(definition, options.projectPath, options.run ?? runCommand));
168
+ }
169
+
170
+ function enqueue(key: string, work: () => Promise<void>): Promise<void> {
171
+ const existing = inFlight.get(key);
172
+ if (existing) return existing;
173
+
174
+ const started = queue.then(work);
175
+ queue = started.catch(() => {}); // a failure must not poison the queue behind it
176
+ const tracked = started.finally(() => inFlight.delete(key));
177
+ inFlight.set(key, tracked);
178
+ return tracked;
179
+ }
180
+
181
+ async function install(definition: LanguageServerDefinition, projectPath: string | undefined, run: Runner): Promise<void> {
182
+ const plan = definition.install;
183
+ if (!plan) throw new Error(`PPM cannot install ${definition.displayName}`);
184
+ const tool = installToolPath(plan);
185
+ if (!tool) {
186
+ throw new Error(`${plan.with} is not installed on this host, so PPM cannot install ${definition.displayName}.`);
187
+ }
188
+
189
+ const dir = lspInstallDir();
190
+ const failed = (result: RunResult, what: string) => new Error(`${what} failed to install: ${output(result)}`);
191
+
192
+ if (plan.with === "bun") {
193
+ ensureInstallDir(dir);
194
+ const result = await run([tool, "add", ...plan.packages], { cwd: dir, timeoutMs: INSTALL_TIMEOUT_MS });
195
+ if (result.code !== 0) throw failed(result, plan.packages.join(" "));
196
+ // bun can succeed and still leave nothing to run — a package that dropped its binary, or a
197
+ // name that now points somewhere else. Saying so beats a second "not installed".
198
+ if (!installedServerEntry(definition, dir)) {
199
+ throw new Error(`Installed ${plan.packages.join(" ")}, but it provides no ${definition.command}`);
200
+ }
201
+ return;
202
+ }
203
+
204
+ if (plan.with === "go") {
205
+ const binDir = path.join(dir, "bin");
206
+ mkdirSync(binDir, { recursive: true });
207
+ // `GOBIN` is the whole reason this lands in PPM's directory rather than `~/go/bin`. The
208
+ // module and build caches stay where the user's Go already keeps them — those are the
209
+ // toolchain's, and re-downloading the world into the PPM directory would be rude.
210
+ const result = await run([tool, "install", plan.module], {
211
+ cwd: dir,
212
+ env: { ...process.env, GOBIN: binDir },
213
+ timeoutMs: INSTALL_TIMEOUT_MS,
214
+ });
215
+ if (result.code !== 0) throw failed(result, plan.module);
216
+ const built = installedBinaryPath(definition, dir);
217
+ if (!built || !existsSync(built)) {
218
+ throw new Error(`Built ${plan.module}, but no ${definition.command} appeared in ${binDir}`);
219
+ }
220
+ return;
221
+ }
222
+
223
+ // rustup. Run where the project is, so a repository pinned to its own toolchain gets the
224
+ // component added to *that* one rather than to whichever is default.
225
+ const cwd = projectPath && existsSync(projectPath) ? projectPath : process.cwd();
226
+ const result = await run([tool, "component", "add", plan.component], { cwd, timeoutMs: INSTALL_TIMEOUT_MS });
227
+ if (result.code !== 0) throw failed(result, plan.component);
228
+ if (!(await rustupServerPath(definition, cwd, run))) {
229
+ throw new Error(`rustup reported success but still has no ${definition.command} for this toolchain`);
230
+ }
231
+ }
232
+
233
+ async function uninstall(definition: LanguageServerDefinition, projectPath: string | undefined, run: Runner): Promise<void> {
234
+ const plan = definition.install;
235
+ // Both of these are the route's job to prevent; they are here because this function deletes
236
+ // things, and "the caller checked" is not a property a deleting function should rely on.
237
+ if (!plan) throw new Error(`PPM did not install ${definition.displayName}, so there is nothing to remove.`);
238
+ const dir = lspInstallDir();
239
+
240
+ if (plan.with === "bun") {
241
+ if (!installedServerEntry(definition, dir)) {
242
+ throw new Error(`${definition.displayName} is not in PPM's own folder, so there is nothing for PPM to remove.`);
243
+ }
244
+ const tool = installToolPath(plan);
245
+ if (!tool) throw new Error(`bun is not installed on this host, so PPM cannot remove ${definition.displayName}.`);
246
+ // By name, never by the spec that installed it: `bun remove typescript@5` is not the same
247
+ // request as `bun remove typescript`, and the manifest holds the name.
248
+ const names = plan.packages.map(packageName);
249
+ const result = await run([tool, "remove", ...names], { cwd: dir, timeoutMs: INSTALL_TIMEOUT_MS });
250
+ if (result.code !== 0) throw new Error(`Could not remove ${names.join(" ")}: ${output(result)}`);
251
+ return;
252
+ }
253
+
254
+ if (plan.with === "go") {
255
+ const binary = installedBinaryPath(definition, dir);
256
+ if (!binary || !existsSync(binary)) {
257
+ throw new Error(`${definition.displayName} is not in PPM's own folder, so there is nothing for PPM to remove.`);
258
+ }
259
+ try {
260
+ rmSync(binary);
261
+ } catch (e) {
262
+ // Windows refuses to unlink a running executable, which is the one platform where an
263
+ // uninstall fails for a reason the user can act on.
264
+ throw new Error(`Could not delete ${binary}: ${(e as Error).message}`);
265
+ }
266
+ return;
267
+ }
268
+
269
+ // rustup, in the same directory the install would have used, so the component leaves the
270
+ // toolchain it was added to rather than whichever happens to be default.
271
+ const cwd = projectPath && existsSync(projectPath) ? projectPath : process.cwd();
272
+ const tool = installToolPath(plan);
273
+ if (!tool) throw new Error(`rustup is not installed on this host, so PPM cannot remove ${definition.displayName}.`);
274
+ const result = await run([tool, "component", "remove", plan.component], { cwd, timeoutMs: INSTALL_TIMEOUT_MS });
275
+ if (result.code !== 0) throw new Error(`Could not remove ${plan.component}: ${output(result)}`);
276
+ }
277
+
278
+ /** What a failed command said, bounded — a build log's last 400 characters hold the reason. */
279
+ function output(result: RunResult): string {
280
+ return (result.stderr.trim() || result.stdout.trim()).slice(-400) || `exit ${result.code}`;
281
+ }
282
+
283
+ function ensureInstallDir(dir: string): void {
284
+ mkdirSync(dir, { recursive: true });
285
+ const manifest = path.join(dir, "package.json");
286
+ if (!existsSync(manifest)) {
287
+ writeFileSync(manifest, `${JSON.stringify({ name: "ppm-lsp-servers", private: true, dependencies: {} }, null, 2)}\n`);
288
+ }
289
+ }
@@ -16,14 +16,20 @@
16
16
  */
17
17
  import { stat } from "node:fs/promises";
18
18
  import path from "node:path";
19
+ import { resolveBunPath } from "../autostart-generator.ts";
20
+ import { canInstall, lspInstallDir, rustupServerPath } from "./lsp-install.ts";
19
21
  import { LspSession, type LspSessionState } from "./lsp-session.ts";
20
22
  import {
21
23
  LANGUAGE_SERVERS,
22
24
  ancestorDirs,
23
25
  bundledServerEntry,
24
26
  candidateCommandPaths,
27
+ installedBinaryPath,
28
+ installedServerEntry,
25
29
  lspLanguageForPath,
30
+ serversSharingInstall,
26
31
  type LanguageServerDefinition,
32
+ type LanguageServerInstall,
27
33
  } from "./server-registry.ts";
28
34
 
29
35
  /** How long a session with no subscribers is kept before being shut down. */
@@ -52,10 +58,34 @@ export type LspUnavailableReason = "no-language" | "not-installed" | "failed";
52
58
  export interface LspUnavailable {
53
59
  reason: LspUnavailableReason;
54
60
  /** The server that would have served it, when one is known. */
55
- server?: { id: string; displayName: string; installHint: string };
61
+ server?: {
62
+ id: string;
63
+ displayName: string;
64
+ installHint: string;
65
+ installable: boolean;
66
+ /** What the button would use, so the editor can say what pressing it does. */
67
+ installWith?: "bun" | "go" | "rustup";
68
+ };
56
69
  message: string;
57
70
  }
58
71
 
72
+ /**
73
+ * What the editor needs to name a missing server, and to decide whether to offer to install it.
74
+ *
75
+ * `installable` is the host's answer rather than the editor's guess, and it is not the registry's
76
+ * either: `go install` needs a Go on this machine and `rustup component add` needs a rustup, so
77
+ * the same server is installable on one host and a command to copy on the next.
78
+ */
79
+ function serverSummary(definition: LanguageServerDefinition): NonNullable<LspUnavailable["server"]> {
80
+ return {
81
+ id: definition.id,
82
+ displayName: definition.displayName,
83
+ installHint: definition.installHint,
84
+ installable: canInstall(definition),
85
+ installWith: definition.install?.with,
86
+ };
87
+ }
88
+
59
89
  export function isUnavailable(result: LspHandle | LspUnavailable): result is LspUnavailable {
60
90
  return "reason" in result;
61
91
  }
@@ -68,6 +98,33 @@ interface Entry {
68
98
  lastUsed: number;
69
99
  }
70
100
 
101
+ /**
102
+ * The bun that runs a server's entry script.
103
+ *
104
+ * Not `process.execPath`: that is bun only while PPM runs from source. A compiled PPM is its
105
+ * own executable, so spawning it with a script path reaches PPM's *CLI* — the same trap that
106
+ * made a compiled PPM answer `<ppm> x @openai/codex app-server` with "unknown command". `null`
107
+ * on a host with no bun at all, where such a copy cannot be run and must not be called
108
+ * installed.
109
+ */
110
+ function bunRuntime(): string | null {
111
+ try {
112
+ return resolveBunPath();
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Where a server was found, in the order `resolveCommand` looks.
120
+ *
121
+ * It exists for the Remove button: PPM may delete what PPM installed and nothing else.
122
+ * `project` is the repository's copy, `path` is one the user installed themselves, and
123
+ * `bundled` is PPM's own dependency — removing any of those would be PPM tidying up after
124
+ * someone else, and for `bundled` it would break the TypeScript server a fresh install has.
125
+ */
126
+ export type ServerOrigin = "project" | "rustup" | "path" | "ppm" | "bundled";
127
+
71
128
  async function exists(candidate: string): Promise<boolean> {
72
129
  try {
73
130
  await stat(candidate);
@@ -107,6 +164,8 @@ export class LspManager {
107
164
  private readonly servers: LanguageServerDefinition[] = LANGUAGE_SERVERS,
108
165
  private readonly idleGraceMs: number = IDLE_GRACE_MS,
109
166
  private readonly maxSessions: number = MAX_SESSIONS,
167
+ /** Called rather than held, so `PPM_HOME` is read when a server is looked for, not at import. */
168
+ private readonly installDir: () => string = lspInstallDir,
110
169
  ) {}
111
170
 
112
171
  onNotification(listener: (key: string, method: string, params: unknown) => void): () => void {
@@ -136,8 +195,8 @@ export class LspManager {
136
195
 
137
196
  let lastMissing: LanguageServerDefinition | null = null;
138
197
  for (const definition of candidates) {
139
- const command = await this.resolveCommand(definition, dirs);
140
- if (!command) {
198
+ const resolved = await this.resolveCommand(definition, dirs);
199
+ if (!resolved) {
141
200
  lastMissing = definition;
142
201
  continue;
143
202
  }
@@ -146,7 +205,7 @@ export class LspManager {
146
205
 
147
206
  this.claim(key);
148
207
  try {
149
- const session = await this.startOrReuse(key, definition, command, rootPath);
208
+ const session = await this.startOrReuse(key, definition, resolved.command, rootPath);
150
209
  // Subscribe *then* trim, so the session this call is about to hand out is never the
151
210
  // one the cap takes away.
152
211
  if (!this.subscribe(key, subscriber)) {
@@ -161,7 +220,7 @@ export class LspManager {
161
220
  } catch (e) {
162
221
  return {
163
222
  reason: "failed",
164
- server: { id: definition.id, displayName: definition.displayName, installHint: definition.installHint },
223
+ server: serverSummary(definition),
165
224
  message: e instanceof Error ? e.message : String(e),
166
225
  };
167
226
  } finally {
@@ -172,7 +231,7 @@ export class LspManager {
172
231
  const missing = lastMissing ?? candidates[0]!;
173
232
  return {
174
233
  reason: "not-installed",
175
- server: { id: missing.id, displayName: missing.displayName, installHint: missing.installHint },
234
+ server: serverSummary(missing),
176
235
  message: `${missing.displayName} is not installed.`,
177
236
  };
178
237
  }
@@ -322,25 +381,51 @@ export class LspManager {
322
381
  *
323
382
  * The project's own copy first, because a repository pinned to TypeScript 4 has to be
324
383
  * analysed by its own server — the same reason VS Code offers "Use Workspace Version".
325
- * Then `PATH`, which is whatever the user deliberately installed. Then the copy PPM ships,
326
- * which is the floor rather than a preference: it is how a fresh install has a working
327
- * TypeScript server with nothing else done, and it must never win over either of the two
328
- * choices someone actually made.
384
+ * Then rustup, which owns its answer completely (below). Then `PATH`, which is whatever the
385
+ * user deliberately installed. Then PPM's own directory: what the Install button put there,
386
+ * and then the copy PPM ships, which is the floor rather than a preference — it is how a
387
+ * fresh install has a working TypeScript server with nothing else done, and it must never win
388
+ * over either of the two choices someone actually made.
329
389
  */
330
- private async resolveCommand(definition: LanguageServerDefinition, dirs: string[]): Promise<string[] | null> {
390
+ private async resolveCommand(
391
+ definition: LanguageServerDefinition,
392
+ dirs: string[],
393
+ ): Promise<{ command: string[]; origin: ServerOrigin } | null> {
331
394
  const candidates = candidateCommandPaths(definition.command, dirs);
332
395
  for (const candidate of candidates.slice(0, -1)) {
333
- if (await exists(candidate)) return [candidate];
396
+ if (await exists(candidate)) return { command: [candidate], origin: "project" };
334
397
  }
398
+ // rust-analyzer is a toolchain component rather than a file PPM owns, so rustup is asked
399
+ // where it is — in the file's own directory, so a repository pinning a toolchain gets that
400
+ // toolchain's server. This has to come *before* PATH, because `~/.cargo/bin/rust-analyzer`
401
+ // is a rustup proxy that exists whether or not the component does: found on PATH it reports
402
+ // an installed server, and spawning it prints "unknown binary" and exits, which is a broken
403
+ // server rather than the missing one the Install button is offered for. Costs nothing for
404
+ // every other server — it answers null on sight of a definition that is not rustup's.
405
+ const fromRustup = await rustupServerPath(definition, dirs[0] ?? process.cwd());
406
+ if (fromRustup) return { command: [fromRustup], origin: "rustup" };
407
+
335
408
  // The last candidate is the bare command, which means PATH.
336
409
  const onPath = Bun.which(definition.command);
337
- if (onPath) return [onPath];
410
+ if (onPath) return { command: [onPath], origin: "path" };
411
+
412
+ // What the Install button built with the host's Go: a real binary in PPM's own directory,
413
+ // spawned as itself.
414
+ const binary = installedBinaryPath(definition, this.installDir());
415
+ if (binary && (await exists(binary))) return { command: [binary], origin: "ppm" };
338
416
 
339
- const bundled = bundledServerEntry(definition);
340
- // Run by the runtime PPM is already using, not through npm's `.bin` shim: that shim is
417
+ // Both of PPM's npm copies are entry scripts rather than npm's `.bin` shims: that shim is
341
418
  // `#!/usr/bin/env node`, and someone who installed PPM with bun may have no node at all —
342
419
  // which fails as exit code 127 at spawn time, long after the server looked installed.
343
- return bundled && (await exists(bundled)) ? [process.execPath, bundled] : null;
420
+ for (const [entry, origin] of [
421
+ [installedServerEntry(definition, this.installDir()), "ppm"],
422
+ [bundledServerEntry(definition), "bundled"],
423
+ ] as const) {
424
+ if (!entry || !(await exists(entry))) continue;
425
+ const runtime = bunRuntime();
426
+ return runtime ? { command: [runtime, entry], origin } : null;
427
+ }
428
+ return null;
344
429
  }
345
430
 
346
431
  /**
@@ -382,24 +467,70 @@ export class LspManager {
382
467
  }
383
468
 
384
469
  /**
385
- * Which of the registered servers this project could actually use.
470
+ * Which of the registered servers could actually be used.
386
471
  *
387
- * Answers the editor's "why is nothing happening" question directly, with the
388
- * install command for anything missing.
472
+ * Answers the editor's "why is nothing happening" question directly, with the install
473
+ * command for anything missing. With no `projectPath` it answers for the *machine* — no
474
+ * project `node_modules/.bin` is consulted — which is what the Settings pane asks, since it
475
+ * is not open on any one project.
389
476
  */
390
- async availability(projectPath: string): Promise<
391
- Array<{ id: string; displayName: string; languages: string[]; installed: boolean; installHint: string }>
477
+ async availability(projectPath?: string): Promise<
478
+ Array<{
479
+ id: string;
480
+ displayName: string;
481
+ languages: string[];
482
+ installed: boolean;
483
+ installHint: string;
484
+ installable: boolean;
485
+ installWith?: LanguageServerInstall["with"];
486
+ origin?: ServerOrigin;
487
+ /** Whether PPM may remove it — that is, whether PPM is what put it there. */
488
+ removable: boolean;
489
+ /** Servers the same removal would also take, because one npm package provides several. */
490
+ alsoRemoves?: string[];
491
+ }>
392
492
  > {
393
- const dirs = [projectPath];
493
+ const dirs = projectPath ? [projectPath] : [];
394
494
  return Promise.all(
395
- this.servers.map(async (definition) => ({
396
- id: definition.id,
397
- displayName: definition.displayName,
398
- languages: definition.languages,
399
- installed: (await this.resolveCommand(definition, dirs)) !== null,
400
- installHint: definition.installHint,
401
- })),
495
+ this.servers.map(async (definition) => {
496
+ const resolved = await this.resolveCommand(definition, dirs);
497
+ const origin = resolved?.origin;
498
+ const removable = origin === "ppm" || origin === "rustup";
499
+ const shared = removable ? serversSharingInstall(definition).map((s) => s.displayName) : [];
500
+ return {
501
+ id: definition.id,
502
+ displayName: definition.displayName,
503
+ languages: definition.languages,
504
+ installed: resolved !== null,
505
+ installHint: definition.installHint,
506
+ installable: canInstall(definition),
507
+ installWith: definition.install?.with,
508
+ origin,
509
+ removable,
510
+ ...(shared.length > 0 ? { alsoRemoves: shared } : {}),
511
+ };
512
+ }),
513
+ );
514
+ }
515
+
516
+ /**
517
+ * Stop this server's idle sessions, for an uninstall that is about to delete it.
518
+ *
519
+ * Only the ones nobody is holding. A session with a subscriber is an editor open on it, and
520
+ * taking that away answers every later request with "the language server is no longer
521
+ * running" until the tab is closed and reopened — the same reason `enforceSessionCap` leaves
522
+ * held sessions alone. One that keeps running is running on files it already opened, which
523
+ * is harmless everywhere except Windows, where it is also what refuses the unlink.
524
+ */
525
+ async stopIdle(serverId: string): Promise<void> {
526
+ const doomed = [...this.entries.entries()].filter(
527
+ ([, entry]) => entry.session.definition.id === serverId && entry.subscribers.size === 0,
402
528
  );
529
+ for (const [key, entry] of doomed) {
530
+ if (entry.idleTimer) clearTimeout(entry.idleTimer);
531
+ this.entries.delete(key);
532
+ }
533
+ await Promise.all(doomed.map(([, entry]) => entry.session.dispose()));
403
534
  }
404
535
 
405
536
  /**