@hienlh/ppm 0.23.5 → 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 (714) hide show
  1. package/CHANGELOG.md +89 -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 +30 -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-DKcsVDle.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-qMGJH0Bx.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-D2I742dl.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-Bz4LjgIa.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-CapP1yXq.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-CdXi7cZN.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-B2nZzJ2b.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-BGoDxkdF.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-DC3OzzOl.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-i41W43ER.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-DHzPIkJg.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-Dj4vrDvj.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-BJ9edGEP.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-CxdGSNGr.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-ok96IgnS.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-Drkjb_LI.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-C8PFlvaq.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-CFYO0Ro3.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-BcHIEANE.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-BGsp0edA.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-CsZCCRJI.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-Ci0O2Ng6.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-4iCGE4h2.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-CK6DulYk.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-CWBaWKjA.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-Br6mrxrw.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-CwCy7ZWf.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-BW14RpCb.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-CgOBEUnb.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-rH6epJYA.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-QwURkjpV.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/codex-app-server/codex-reset-credit.ts +49 -0
  316. package/src/providers/provider-probe.ts +63 -0
  317. package/src/providers/registry.ts +109 -29
  318. package/src/server/index.ts +9 -0
  319. package/src/server/middleware/auth.ts +5 -1
  320. package/src/server/routes/codex-accounts.ts +14 -0
  321. package/src/server/routes/cross-origin-guard.ts +20 -0
  322. package/src/server/routes/git.ts +40 -4
  323. package/src/server/routes/lsp.ts +97 -4
  324. package/src/server/routes/resources.ts +72 -9
  325. package/src/server/routes/settings.ts +19 -1
  326. package/src/server/routes/speech.ts +66 -0
  327. package/src/server/routes/system-services.ts +76 -0
  328. package/src/server/routes/tunnel.ts +33 -1
  329. package/src/server/ws/chat.ts +74 -3
  330. package/src/services/codex-account-login.ts +26 -2
  331. package/src/services/codex-reset-credit.service.ts +83 -0
  332. package/src/services/compaction-savings.ts +127 -0
  333. package/src/services/db.service.ts +123 -8
  334. package/src/services/edge-forwarder.ts +191 -191
  335. package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
  336. package/src/services/git-refs/for-each-ref.ts +118 -0
  337. package/src/services/git.service.ts +25 -2
  338. package/src/services/host-info/spawn-runner.ts +48 -4
  339. package/src/services/jsonl-transcript-parser.ts +7 -42
  340. package/src/services/lsp/lsp-install.ts +289 -0
  341. package/src/services/lsp/lsp-manager.ts +160 -29
  342. package/src/services/lsp/server-registry.ts +120 -4
  343. package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
  344. package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
  345. package/src/services/read-lines.ts +54 -0
  346. package/src/services/speech-to-text/whisper-catalog.ts +142 -0
  347. package/src/services/speech-to-text/whisper-download.ts +113 -0
  348. package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
  349. package/src/services/speech-to-text/whisper-install.service.ts +247 -0
  350. package/src/services/speech-to-text/whisper-paths.ts +62 -0
  351. package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
  352. package/src/services/supervisor.ts +94 -11
  353. package/src/services/system-metrics/cpu-details-linux.ts +252 -0
  354. package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
  355. package/src/services/system-metrics/device-collector-linux.ts +31 -0
  356. package/src/services/system-metrics/device-collector-types.ts +40 -0
  357. package/src/services/system-metrics/disk-devices-linux.ts +156 -0
  358. package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
  359. package/src/services/system-metrics/fans-linux.ts +51 -0
  360. package/src/services/system-metrics/gpu-api-versions.ts +120 -0
  361. package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
  362. package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
  363. package/src/services/system-metrics/hardware-inventory.ts +50 -0
  364. package/src/services/system-metrics/linux-fs.ts +43 -0
  365. package/src/services/system-metrics/memory-darwin.ts +91 -0
  366. package/src/services/system-metrics/memory-linux.ts +156 -0
  367. package/src/services/system-metrics/net-devices-linux.ts +114 -0
  368. package/src/services/system-metrics/net-inventory-linux.ts +100 -0
  369. package/src/services/system-metrics/partitions-linux.ts +158 -0
  370. package/src/services/system-metrics/process-collector-linux.ts +58 -6
  371. package/src/services/system-metrics/process-collector-types.ts +8 -1
  372. package/src/services/system-metrics/process-details-darwin.ts +166 -0
  373. package/src/services/system-metrics/process-details-linux.ts +150 -0
  374. package/src/services/system-metrics/process-grouping.ts +2 -1
  375. package/src/services/system-metrics/process-rows-builder.ts +2 -0
  376. package/src/services/system-metrics/process-swap-linux.ts +37 -0
  377. package/src/services/system-metrics/signal-executor.ts +84 -0
  378. package/src/services/system-metrics/signal-request-handler.ts +92 -0
  379. package/src/services/system-metrics/system-metrics-platform.ts +30 -4
  380. package/src/services/system-metrics/system-metrics-tick.ts +73 -4
  381. package/src/services/system-metrics/system-metrics.service.ts +87 -2
  382. package/src/services/system-metrics/udev-db.ts +40 -0
  383. package/src/services/system-services/app-cgroup-linux.ts +115 -0
  384. package/src/services/system-services/app-icon-service.ts +31 -0
  385. package/src/services/system-services/app-icons-linux.ts +124 -0
  386. package/src/services/system-services/apps-linux.ts +174 -0
  387. package/src/services/system-services/desktop-entry.ts +103 -0
  388. package/src/services/system-services/service-guard.ts +124 -0
  389. package/src/services/system-services/systemd-collector.ts +203 -0
  390. package/src/services/system-services/systemd-parse.ts +162 -0
  391. package/src/services/windows-process-tree.ts +351 -351
  392. package/src/shared/prompt-cache-idle.ts +197 -0
  393. package/src/shared/turn-usage.ts +85 -1
  394. package/src/shared/usage-extra.ts +19 -0
  395. package/src/types/chat.ts +29 -0
  396. package/src/types/config.ts +14 -0
  397. package/src/types/git.ts +41 -0
  398. package/src/types/system-hardware.ts +137 -0
  399. package/src/types/system-metrics.ts +231 -2
  400. package/src/types/system-services.ts +73 -0
  401. package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
  402. package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
  403. package/src/web/components/chat/chat-tab.tsx +3 -0
  404. package/src/web/components/chat/codex-usage-panel.tsx +4 -0
  405. package/src/web/components/chat/compaction-divider.tsx +48 -0
  406. package/src/web/components/chat/idle-cache-notice.tsx +67 -0
  407. package/src/web/components/chat/message-input.tsx +48 -13
  408. package/src/web/components/chat/message-list.tsx +15 -0
  409. package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
  410. package/src/web/components/editor/code-editor.tsx +1 -0
  411. package/src/web/components/editor/editor-language-service.tsx +11 -3
  412. package/src/web/components/editor/lsp-status.tsx +115 -13
  413. package/src/web/components/git/branch-picker.tsx +419 -0
  414. package/src/web/components/git/branch-select.tsx +34 -0
  415. package/src/web/components/git/create-worktree-dialog.tsx +17 -16
  416. package/src/web/components/git/git-repo-picker.tsx +28 -40
  417. package/src/web/components/layout/status-bar.tsx +42 -19
  418. package/src/web/components/settings/accounts/account-card.tsx +10 -2
  419. package/src/web/components/settings/accounts/account-usage-extras.tsx +3 -2
  420. package/src/web/components/settings/accounts/codex-accounts-section.tsx +3 -1
  421. package/src/web/components/settings/accounts/codex-reset-credit-button.tsx +120 -0
  422. package/src/web/components/settings/ai-settings-section.tsx +67 -3
  423. package/src/web/components/settings/appearance-settings-section.tsx +2 -28
  424. package/src/web/components/settings/language-servers-section.tsx +362 -0
  425. package/src/web/components/settings/settings-categories.ts +8 -3
  426. package/src/web/components/settings/settings-section-content.tsx +2 -0
  427. package/src/web/components/settings/voice-settings-section.tsx +283 -0
  428. package/src/web/components/system/apps/app-row.tsx +110 -0
  429. package/src/web/components/system/apps/app-rows.ts +140 -0
  430. package/src/web/components/system/apps/apps-panel.tsx +129 -0
  431. package/src/web/components/system/metric-chart-canvas.tsx +79 -3
  432. package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
  433. package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
  434. package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
  435. package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
  436. package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
  437. package/src/web/components/system/overview-cards/net-card.tsx +11 -6
  438. package/src/web/components/system/overview-device-target.ts +69 -0
  439. package/src/web/components/system/overview-panel.tsx +15 -1
  440. package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
  441. package/src/web/components/system/performance/cpu-detail.tsx +220 -0
  442. package/src/web/components/system/performance/detail-parts.tsx +149 -0
  443. package/src/web/components/system/performance/device-list.ts +139 -0
  444. package/src/web/components/system/performance/disk-detail.tsx +64 -0
  445. package/src/web/components/system/performance/fans-detail.tsx +35 -0
  446. package/src/web/components/system/performance/gpu-detail.tsx +116 -0
  447. package/src/web/components/system/performance/memory-detail.tsx +109 -0
  448. package/src/web/components/system/performance/nic-detail.tsx +55 -0
  449. package/src/web/components/system/performance/partition-list.tsx +79 -0
  450. package/src/web/components/system/performance/performance-panel.tsx +206 -0
  451. package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
  452. package/src/web/components/system/process-columns-grid.ts +5 -3
  453. package/src/web/components/system/process-details-dialog.tsx +116 -0
  454. package/src/web/components/system/process-group-row.tsx +6 -1
  455. package/src/web/components/system/process-row-format.ts +6 -0
  456. package/src/web/components/system/process-row-menu.tsx +72 -0
  457. package/src/web/components/system/process-row.tsx +7 -1
  458. package/src/web/components/system/process-table-model.ts +1 -1
  459. package/src/web/components/system/process-table-sort.ts +8 -4
  460. package/src/web/components/system/process-table-toolbar.tsx +10 -2
  461. package/src/web/components/system/process-table-totals.ts +3 -0
  462. package/src/web/components/system/process-table.tsx +25 -2
  463. package/src/web/components/system/services/service-action-confirm.tsx +100 -0
  464. package/src/web/components/system/services/service-columns.ts +103 -0
  465. package/src/web/components/system/services/service-details-sheet.tsx +97 -0
  466. package/src/web/components/system/services/service-resources.ts +105 -0
  467. package/src/web/components/system/services/service-row.tsx +146 -0
  468. package/src/web/components/system/services/service-rows.ts +92 -0
  469. package/src/web/components/system/services/service-sort.ts +90 -0
  470. package/src/web/components/system/services/services-header.tsx +51 -0
  471. package/src/web/components/system/services/services-panel.tsx +207 -0
  472. package/src/web/components/system/services/use-services.ts +92 -0
  473. package/src/web/components/system/sortable-header.tsx +13 -8
  474. package/src/web/components/system/sysmon-preferences.tsx +85 -0
  475. package/src/web/components/system/system-monitor-body.tsx +101 -43
  476. package/src/web/components/system/system-monitor-window-content.tsx +2 -3
  477. package/src/web/components/system/use-process-signal.ts +87 -0
  478. package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
  479. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  480. package/src/web/components/ui/dialog.tsx +14 -1
  481. package/src/web/components/ui/search-select.tsx +279 -0
  482. package/src/web/components/ui/start-ellipsis.tsx +18 -0
  483. package/src/web/hooks/use-chat.ts +28 -0
  484. package/src/web/hooks/use-global-keybindings.ts +7 -5
  485. package/src/web/hooks/use-lsp.ts +23 -2
  486. package/src/web/hooks/use-minute-clock.ts +20 -0
  487. package/src/web/hooks/use-whisper-voice-input.ts +113 -0
  488. package/src/web/lib/api-tunnels.ts +19 -0
  489. package/src/web/lib/branch-select-items.ts +29 -0
  490. package/src/web/lib/cpu-graph-mode.ts +90 -0
  491. package/src/web/lib/format-bytes.ts +14 -0
  492. package/src/web/lib/git-ref-picker.ts +120 -0
  493. package/src/web/lib/lsp/lsp-client.ts +32 -0
  494. package/src/web/lib/search-select-rows.ts +55 -0
  495. package/src/web/lib/temperature.ts +27 -0
  496. package/src/web/lib/voice-wav.ts +69 -0
  497. package/src/web/stores/git-status-store.ts +31 -17
  498. package/src/web/stores/keybindings-store.ts +14 -1
  499. package/src/web/stores/settings-store.ts +65 -0
  500. package/src/web/styles/globals.css +11 -0
  501. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js +0 -1
  502. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.br +0 -0
  503. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.gz +0 -0
  504. package/dist/web/assets/ai-resource-editor-DKcsVDle.js.br +0 -0
  505. package/dist/web/assets/ai-resource-editor-DKcsVDle.js.gz +0 -0
  506. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js +0 -1
  507. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.br +0 -0
  508. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.gz +0 -0
  509. package/dist/web/assets/ai-settings-section-OPqC2bYG.js +0 -1
  510. package/dist/web/assets/api-client-BgedDTvo.js +0 -1
  511. package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
  512. package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
  513. package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
  514. package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
  515. package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
  516. package/dist/web/assets/appearance-settings-section-DL466x83.js +0 -1
  517. package/dist/web/assets/appearance-settings-section-DL466x83.js.br +0 -0
  518. package/dist/web/assets/appearance-settings-section-DL466x83.js.gz +0 -0
  519. package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
  520. package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
  521. package/dist/web/assets/branch-review-tab-Dag86n_R.js +0 -1
  522. package/dist/web/assets/branch-review-tab-Dag86n_R.js.br +0 -0
  523. package/dist/web/assets/branch-review-tab-Dag86n_R.js.gz +0 -0
  524. package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
  525. package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
  526. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
  527. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
  528. package/dist/web/assets/chat-tab-CcYZLXls.js +0 -15
  529. package/dist/web/assets/chat-tab-CcYZLXls.js.br +0 -0
  530. package/dist/web/assets/chat-tab-CcYZLXls.js.gz +0 -0
  531. package/dist/web/assets/chat-tab-QFDhzzBZ.js +0 -1
  532. package/dist/web/assets/chat-tab-QFDhzzBZ.js.br +0 -0
  533. package/dist/web/assets/chat-tab-QFDhzzBZ.js.gz +0 -0
  534. package/dist/web/assets/code-editor-K-IN8VwJ.js +0 -7
  535. package/dist/web/assets/code-editor-K-IN8VwJ.js.br +0 -0
  536. package/dist/web/assets/code-editor-K-IN8VwJ.js.gz +0 -0
  537. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js +0 -1
  538. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.br +0 -0
  539. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.gz +0 -0
  540. package/dist/web/assets/conflict-editor-qMGJH0Bx.js.br +0 -0
  541. package/dist/web/assets/conflict-editor-qMGJH0Bx.js.gz +0 -0
  542. package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
  543. package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
  544. package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
  545. package/dist/web/assets/csv-preview-D2I742dl.js.br +0 -0
  546. package/dist/web/assets/csv-preview-D2I742dl.js.gz +0 -0
  547. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
  548. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
  549. package/dist/web/assets/database-viewer-Bz4LjgIa.js.br +0 -0
  550. package/dist/web/assets/database-viewer-Bz4LjgIa.js.gz +0 -0
  551. package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
  552. package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
  553. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
  554. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
  555. package/dist/web/assets/design-tab-C987MtMR.js +0 -33
  556. package/dist/web/assets/design-tab-C987MtMR.js.br +0 -0
  557. package/dist/web/assets/design-tab-C987MtMR.js.gz +0 -0
  558. package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.br +0 -0
  559. package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.gz +0 -0
  560. package/dist/web/assets/dialog-B8clVkyi.js +0 -1
  561. package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
  562. package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
  563. package/dist/web/assets/diff-viewer-CdXi7cZN.js.br +0 -0
  564. package/dist/web/assets/diff-viewer-CdXi7cZN.js.gz +0 -0
  565. package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
  566. package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
  567. package/dist/web/assets/editor-language-service-Zle_PZV8.js +0 -1
  568. package/dist/web/assets/editor-language-service-Zle_PZV8.js.br +0 -0
  569. package/dist/web/assets/editor-language-service-Zle_PZV8.js.gz +0 -0
  570. package/dist/web/assets/explorer-body-DHMQR1Rk.js +0 -2
  571. package/dist/web/assets/explorer-body-DHMQR1Rk.js.br +0 -0
  572. package/dist/web/assets/explorer-body-DHMQR1Rk.js.gz +0 -0
  573. package/dist/web/assets/explorer-window-content-Df40nQBk.js +0 -1
  574. package/dist/web/assets/explorer-window-content-Df40nQBk.js.br +0 -0
  575. package/dist/web/assets/explorer-window-content-Df40nQBk.js.gz +0 -0
  576. package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.br +0 -0
  577. package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.gz +0 -0
  578. package/dist/web/assets/extension-webview-BGoDxkdF.js.br +0 -0
  579. package/dist/web/assets/extension-webview-BGoDxkdF.js.gz +0 -0
  580. package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
  581. package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
  582. package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
  583. package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
  584. package/dist/web/assets/files-settings-section-DC3OzzOl.js.br +0 -0
  585. package/dist/web/assets/files-settings-section-DC3OzzOl.js.gz +0 -0
  586. package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
  587. package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
  588. package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
  589. package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
  590. package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
  591. package/dist/web/assets/general-settings-section-i41W43ER.js.br +0 -0
  592. package/dist/web/assets/general-settings-section-i41W43ER.js.gz +0 -0
  593. package/dist/web/assets/git-log-panel-DHzPIkJg.js.br +0 -0
  594. package/dist/web/assets/git-log-panel-DHzPIkJg.js.gz +0 -0
  595. package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
  596. package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
  597. package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.br +0 -0
  598. package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.gz +0 -0
  599. package/dist/web/assets/group-chat-tab-DfwZb-fI.js +0 -1
  600. package/dist/web/assets/group-chat-tab-DfwZb-fI.js.br +0 -0
  601. package/dist/web/assets/group-chat-tab-DfwZb-fI.js.gz +0 -0
  602. package/dist/web/assets/index-DMA-So69.css +0 -1
  603. package/dist/web/assets/index-DMA-So69.css.br +0 -0
  604. package/dist/web/assets/index-DMA-So69.css.gz +0 -0
  605. package/dist/web/assets/index-jG9mLs-J.js +0 -52
  606. package/dist/web/assets/index-jG9mLs-J.js.br +0 -0
  607. package/dist/web/assets/index-jG9mLs-J.js.gz +0 -0
  608. package/dist/web/assets/keybindings-store-BlapkC6O.js +0 -1
  609. package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.br +0 -0
  610. package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.gz +0 -0
  611. package/dist/web/assets/markdown-renderer-DJ9EVU1B.js +0 -1
  612. package/dist/web/assets/markdown-renderer-ok96IgnS.js.br +0 -0
  613. package/dist/web/assets/markdown-renderer-ok96IgnS.js.gz +0 -0
  614. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
  615. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
  616. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js +0 -1
  617. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.br +0 -0
  618. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.gz +0 -0
  619. package/dist/web/assets/new-design-dialog-Drkjb_LI.js.br +0 -0
  620. package/dist/web/assets/new-design-dialog-Drkjb_LI.js.gz +0 -0
  621. package/dist/web/assets/notification-store-DCyxho0O.js +0 -1
  622. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
  623. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
  624. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
  625. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
  626. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
  627. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
  628. package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
  629. package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
  630. package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
  631. package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
  632. package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
  633. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
  634. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
  635. package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.br +0 -0
  636. package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.gz +0 -0
  637. package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
  638. package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
  639. package/dist/web/assets/problems-panel-CFYO0Ro3.js.br +0 -0
  640. package/dist/web/assets/problems-panel-CFYO0Ro3.js.gz +0 -0
  641. package/dist/web/assets/process-table-BVeRguFg.js +0 -1
  642. package/dist/web/assets/process-table-BVeRguFg.js.br +0 -0
  643. package/dist/web/assets/process-table-BVeRguFg.js.gz +0 -0
  644. package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
  645. package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
  646. package/dist/web/assets/proxy-settings-section-BcHIEANE.js.br +0 -0
  647. package/dist/web/assets/proxy-settings-section-BcHIEANE.js.gz +0 -0
  648. package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
  649. package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
  650. package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.br +0 -0
  651. package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.gz +0 -0
  652. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js +0 -2
  653. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.br +0 -0
  654. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.gz +0 -0
  655. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js +0 -1
  656. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.br +0 -0
  657. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.gz +0 -0
  658. package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.br +0 -0
  659. package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.gz +0 -0
  660. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js +0 -1
  661. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.br +0 -0
  662. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.gz +0 -0
  663. package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.br +0 -0
  664. package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.gz +0 -0
  665. package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
  666. package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
  667. package/dist/web/assets/settings-body-B6JGOIYb.js +0 -2
  668. package/dist/web/assets/settings-body-B6JGOIYb.js.br +0 -0
  669. package/dist/web/assets/settings-body-B6JGOIYb.js.gz +0 -0
  670. package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
  671. package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
  672. package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
  673. package/dist/web/assets/settings-tab-CIQM4fNE.js +0 -1
  674. package/dist/web/assets/settings-window-content-BGNNz-E5.js +0 -1
  675. package/dist/web/assets/sql-query-editor-4iCGE4h2.js.br +0 -3
  676. package/dist/web/assets/sql-query-editor-4iCGE4h2.js.gz +0 -0
  677. package/dist/web/assets/sqlite-viewer-CK6DulYk.js.br +0 -0
  678. package/dist/web/assets/sqlite-viewer-CK6DulYk.js.gz +0 -0
  679. package/dist/web/assets/system-monitor-body-J9JtvAWV.js +0 -2
  680. package/dist/web/assets/system-monitor-body-J9JtvAWV.js.br +0 -0
  681. package/dist/web/assets/system-monitor-body-J9JtvAWV.js.gz +0 -0
  682. package/dist/web/assets/system-monitor-tab-DjBeRE81.js +0 -1
  683. package/dist/web/assets/system-monitor-window-content-BT7-ugFx.js +0 -1
  684. package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.br +0 -0
  685. package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.gz +0 -0
  686. package/dist/web/assets/team-member-sheet-Br6mrxrw.js.br +0 -0
  687. package/dist/web/assets/team-member-sheet-Br6mrxrw.js.gz +0 -0
  688. package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.br +0 -0
  689. package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.gz +0 -0
  690. package/dist/web/assets/terminal-tab-BW14RpCb.js.br +0 -0
  691. package/dist/web/assets/terminal-tab-BW14RpCb.js.gz +0 -0
  692. package/dist/web/assets/tool-cards-CgOBEUnb.js.br +0 -0
  693. package/dist/web/assets/tool-cards-CgOBEUnb.js.gz +0 -0
  694. package/dist/web/assets/use-inline-blame-Bzjfru4n.js +0 -16
  695. package/dist/web/assets/use-inline-blame-Bzjfru4n.js.br +0 -0
  696. package/dist/web/assets/use-inline-blame-Bzjfru4n.js.gz +0 -0
  697. package/dist/web/assets/use-lsp-hGdjL2hV.js +0 -6
  698. package/dist/web/assets/use-lsp-hGdjL2hV.js.br +0 -0
  699. package/dist/web/assets/use-lsp-hGdjL2hV.js.gz +0 -0
  700. package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
  701. package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
  702. package/dist/web/assets/video-preview-P9T-ZVdN.js +0 -1
  703. package/dist/web/assets/video-preview-P9T-ZVdN.js.br +0 -0
  704. package/dist/web/assets/video-preview-P9T-ZVdN.js.gz +0 -0
  705. package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
  706. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  707. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  708. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  709. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  710. /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
  711. /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
  712. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
  713. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
  714. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
@@ -9,6 +9,7 @@ import type {
9
9
  SendMessageOpts,
10
10
  UsageInfo,
11
11
  } from "../provider.interface.ts";
12
+ import { stderrReason, type ProviderProbeResult } from "../provider-probe.ts";
12
13
  import { configService } from "../../services/config.service.ts";
13
14
  import { withSharedContext } from "../../shared/provider-context.ts";
14
15
  import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount, getSessionTitles, insertTurnUsage } from "../../services/db.service.ts";
@@ -33,7 +34,7 @@ import {
33
34
  import { killProcessTree } from "../../services/windows-process-tree.ts";
34
35
  import { homedir } from "node:os";
35
36
  import { join } from "node:path";
36
- import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
37
+ import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS, codexCommand } from "./codex-jsonrpc-client.ts";
37
38
  import { permissionModeToCodex, type CodexPermission } from "./codex-permission-map.ts";
38
39
  import { buildThreadParams, designMcpEnv, requestWithInstructionsFallback, type CodexThreadParams } from "./codex-thread-params.ts";
39
40
  import type { DesignMcpAccess } from "../../services/design/mcp/design-mcp-tool.ts";
@@ -1243,22 +1244,53 @@ export class CodexAppServerProvider implements AIProvider {
1243
1244
  }
1244
1245
 
1245
1246
  // ── Capability probes ──
1246
- async isAvailable(): Promise<boolean> {
1247
+ /**
1248
+ * Whether `bun x @openai/codex` runs here, and when it does not, why.
1249
+ *
1250
+ * The reason is the point: a failure is rarely "codex is not installed" —
1251
+ * bun fetches the package on demand — it is usually the manifest refresh
1252
+ * failing on a host whose network is not up yet. `retryable` is what tells
1253
+ * the registry to ask again instead of hiding the provider until the next
1254
+ * restart; only a missing bun is hopeless, since nothing can run without it.
1255
+ */
1256
+ async probe(): Promise<ProviderProbeResult> {
1257
+ let cmd: string[];
1258
+ try {
1259
+ cmd = codexCommand("--version");
1260
+ } catch (e) {
1261
+ return { ok: false, reason: (e as Error).message, retryable: false };
1262
+ }
1247
1263
  try {
1248
- const proc = Bun.spawn([process.execPath, "x", "@openai/codex", "--version"], {
1264
+ const proc = Bun.spawn(cmd, {
1249
1265
  stdout: "pipe", stderr: "pipe",
1250
1266
  });
1251
1267
  // 30s: a cold `bun x` may download the package, and the probe runs during
1252
1268
  // heavy concurrent server startup where process spawn can be starved.
1253
- const timeout = setTimeout(() => { try { proc.kill(); } catch { /* ignore */ } }, 30_000);
1269
+ let timedOut = false;
1270
+ const timeout = setTimeout(() => {
1271
+ timedOut = true;
1272
+ try { proc.kill(); } catch { /* ignore */ }
1273
+ }, 30_000);
1254
1274
  await proc.exited;
1255
1275
  clearTimeout(timeout);
1256
- return proc.exitCode === 0;
1257
- } catch {
1258
- return false;
1276
+ if (proc.exitCode === 0) return { ok: true };
1277
+ const stderr = timedOut ? "" : await new Response(proc.stderr).text();
1278
+ return {
1279
+ ok: false,
1280
+ retryable: true,
1281
+ reason: timedOut
1282
+ ? "`bun x @openai/codex --version` timed out after 30s"
1283
+ : redactTruncate(stderrReason(stderr), 200) || `\`bun x @openai/codex --version\` exited ${proc.exitCode}`,
1284
+ };
1285
+ } catch (e) {
1286
+ return { ok: false, reason: (e as Error).message, retryable: true };
1259
1287
  }
1260
1288
  }
1261
1289
 
1290
+ async isAvailable(): Promise<boolean> {
1291
+ return (await this.probe()).ok;
1292
+ }
1293
+
1262
1294
  async listModels(): Promise<ModelOption[]> {
1263
1295
  if (this.modelsCache && Date.now() < this.modelsCache.expiry) return this.modelsCache.models;
1264
1296
  if (!this.modelsPending) {
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Spend one of Codex's free rate-limit resets, through the app-server's own
3
+ * `account/rateLimitResetCredit/consume` (codex ≥ 0.157).
4
+ *
5
+ * Deliberately thin: one short-lived app-server on the account's CODEX_HOME, one call, the
6
+ * outcome back. Whether a reset *should* be spent is decided by the caller
7
+ * (`codex-reset-credit.service.ts`), never here.
8
+ */
9
+ import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
10
+
11
+ const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
12
+ const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
13
+
14
+ /**
15
+ * What Codex did. Straight from its protocol: `nothingToReset` means no window was refreshed and
16
+ * the credit is kept (OpenAI: "If there is nothing eligible to reset, the benefit remains
17
+ * available"); `alreadyRedeemed` answers a retry of an attempt that already went through.
18
+ */
19
+ export type ResetCreditOutcome = "reset" | "nothingToReset" | "noCredit" | "alreadyRedeemed";
20
+
21
+ const OUTCOMES = new Set<ResetCreditOutcome>(["reset", "nothingToReset", "noCredit", "alreadyRedeemed"]);
22
+
23
+ /**
24
+ * @param idempotencyKey one logical attempt; Codex treats a repeat of the same key as the same
25
+ * attempt, so a retried request cannot spend a second credit.
26
+ * @param creditId which credit to spend; omitted lets Codex pick the next available one.
27
+ */
28
+ export async function consumeCodexResetCredit(
29
+ codexHome: string,
30
+ idempotencyKey: string,
31
+ creditId?: string,
32
+ ): Promise<ResetCreditOutcome> {
33
+ const client = new CodexJsonRpcClient();
34
+ try {
35
+ client.start({ cwd: process.cwd(), codexHome });
36
+ await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
37
+ client.notify("initialized");
38
+ const res = await client.request<{ outcome?: string }>(
39
+ "account/rateLimitResetCredit/consume",
40
+ { idempotencyKey, ...(creditId ? { creditId } : {}) },
41
+ CONTROL_REQUEST_TIMEOUT_MS,
42
+ );
43
+ const outcome = res?.outcome as ResetCreditOutcome | undefined;
44
+ if (!outcome || !OUTCOMES.has(outcome)) throw new Error(`Codex answered the reset with an unknown outcome: ${String(res?.outcome)}`);
45
+ return outcome;
46
+ } finally {
47
+ client.close();
48
+ }
49
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Why a CLI provider is not registered, and whether asking again could change it.
3
+ *
4
+ * The probe that decides whether Codex exists is `bun x @openai/codex --version`,
5
+ * and bun re-fetches the npm manifest whenever its cached copy has gone stale —
6
+ * so a server restarting during a network blip probes a perfectly good install
7
+ * and is told `ConnectionRefused downloading package manifest @openai/codex`.
8
+ * Registration only ever happened at startup, so that one bad second hid Codex
9
+ * from the chat composer for the whole life of the process, with nothing but a
10
+ * log line to say why (the composer's provider chip is hidden while only one
11
+ * provider is registered, so the option does not even render greyed out).
12
+ *
13
+ * Everything except a missing bun is therefore `retryable`: with `bun x` there
14
+ * is no real "not installed" state — the package is fetched on demand — so a
15
+ * failure is almost always the network, not the host.
16
+ */
17
+ export type ProviderProbeResult =
18
+ | { ok: true }
19
+ | { ok: false; reason: string; retryable: boolean };
20
+
21
+ /** What the last probe of a provider concluded — rendered in Settings → AI. */
22
+ export interface ProviderProbeStatus {
23
+ id: string;
24
+ registered: boolean;
25
+ /** Absent while registered. */
26
+ reason?: string;
27
+ /** Probes made so far in this process, successful or not. */
28
+ attempts: number;
29
+ lastProbeAt: string;
30
+ /** Absent when nothing is scheduled: registered, or a failure retrying cannot fix. */
31
+ nextProbeAt?: string;
32
+ }
33
+
34
+ /**
35
+ * Backoff between probes: 30s, 1m, 2m, 5m, then every 15 minutes.
36
+ *
37
+ * It never gives up. The case this exists for is a host that starts PPM before
38
+ * its network is up and is not looked at again for hours — a bounded set of
39
+ * attempts puts that user back in front of the same silent gap. A warm probe is
40
+ * one ~20ms spawn against bun's cache, so the 15-minute ceiling costs nothing
41
+ * measurable, and it stops the moment the provider registers.
42
+ */
43
+ const BACKOFF_MS = [30_000, 60_000, 120_000, 300_000, 900_000];
44
+
45
+ /** Delay before the next probe, given how many have already failed (1 = the first). */
46
+ export function nextProbeDelayMs(failedAttempts: number): number {
47
+ const index = Math.min(Math.max(failedAttempts, 1), BACKOFF_MS.length) - 1;
48
+ return BACKOFF_MS[index]!;
49
+ }
50
+
51
+ /**
52
+ * The one line of a failed probe's stderr worth showing a user.
53
+ *
54
+ * bun narrates its work before it fails: a cold `bun x` writes "Resolving
55
+ * dependencies" and "Resolved, downloaded and extracted [6]" ahead of
56
+ * `error: ConnectionRefused downloading package manifest @openai/codex`.
57
+ * Handing all three to a settings strip buries the only sentence that says
58
+ * what went wrong.
59
+ */
60
+ export function stderrReason(stderr: string): string {
61
+ const lines = stderr.split("\n").map((line) => line.trim()).filter(Boolean);
62
+ return lines.find((line) => line.toLowerCase().startsWith("error:")) ?? lines.at(-1) ?? "";
63
+ }
@@ -2,6 +2,7 @@ import type { AIProvider } from "./provider.interface.ts";
2
2
  import { MockProvider } from "./mock-provider.ts";
3
3
  import { ClaudeAgentSdkProvider } from "./claude-agent-sdk.ts";
4
4
  import { configService } from "../services/config.service.ts";
5
+ import { nextProbeDelayMs, type ProviderProbeStatus } from "./provider-probe.ts";
5
6
  import { CODEX_DEFAULT_MODEL } from "../types/config.ts";
6
7
 
7
8
  export interface ProviderInfo {
@@ -56,6 +57,10 @@ providerRegistry.register(new MockProvider()); // testing only
56
57
  * Bootstrap CLI providers asynchronously.
57
58
  * Checks isAvailable() before registering — call at server startup.
58
59
  *
60
+ * Cursor's probe is a local `which`, so it answers the same at every restart.
61
+ * Codex's reaches the network, so its failure is retried rather than final —
62
+ * see probeCodexProvider() below.
63
+ *
59
64
  * Persists provider entries with set() only, never save(): set() writes just the
60
65
  * "ai" row, while save() rewrites every config key and re-syncs the projects
61
66
  * table from this process's in-memory config. A caller that bootstraps without
@@ -87,36 +92,111 @@ export async function bootstrapProviders(): Promise<void> {
87
92
  console.warn("[registry] Failed to load Cursor provider:", (e as Error).message);
88
93
  }
89
94
 
90
- try {
91
- const { CodexAppServerProvider } = await import("./codex-app-server/codex-provider.ts");
92
- const codex = new CodexAppServerProvider();
93
- if (await codex.isAvailable()) {
94
- providerRegistry.register(codex);
95
- const ai = configService.get("ai");
96
- // Only when codex has never been configured. An absent `model` is a real
97
- // choice here — the settings picker writes it for "Auto (default)", which
98
- // hands model selection back to codex — so filling one in on every startup
99
- // would undo that choice each restart. Existing installs are given the
100
- // default once, by migration.
101
- if (!ai.providers["codex"]) {
102
- configService.set("ai", {
103
- ...ai,
104
- providers: {
105
- ...ai.providers,
106
- codex: {
107
- type: "cli",
108
- cli_command: "codex",
109
- permission_mode: "bypassPermissions",
110
- model: CODEX_DEFAULT_MODEL,
111
- },
112
- },
113
- });
95
+ await probeCodexProvider();
96
+ }
97
+
98
+ // ── Codex availability: probed, remembered, and retried ──────────────────
99
+
100
+ const probeStatuses = new Map<string, ProviderProbeStatus>();
101
+ let codexRetryTimer: ReturnType<typeof setTimeout> | null = null;
102
+ let codexProbeInFlight: Promise<ProviderProbeStatus> | null = null;
103
+
104
+ /** What the last probe of each CLI provider concluded. Empty before bootstrap. */
105
+ export function providerProbeStatuses(): ProviderProbeStatus[] {
106
+ return Array.from(probeStatuses.values());
107
+ }
108
+
109
+ /** Probe again now, ahead of whatever the backoff had scheduled (Settings' Retry). */
110
+ export function retryProviderProbe(id: string): Promise<ProviderProbeStatus> {
111
+ if (id !== "codex") throw new Error(`Provider "${id}" has no retryable probe`);
112
+ return probeCodexProvider();
113
+ }
114
+
115
+ /**
116
+ * Give codex a config entry, but only when it has never had one. An absent
117
+ * `model` is a real choice — the settings picker writes it for "Auto (default)",
118
+ * which hands model selection back to codex — so filling one in on every probe
119
+ * would undo that choice. Existing installs are given the default once, by
120
+ * migration.
121
+ */
122
+ function ensureCodexConfigEntry(): void {
123
+ const ai = configService.get("ai");
124
+ if (ai.providers["codex"]) return;
125
+ configService.set("ai", {
126
+ ...ai,
127
+ providers: {
128
+ ...ai.providers,
129
+ codex: {
130
+ type: "cli",
131
+ cli_command: "codex",
132
+ permission_mode: "bypassPermissions",
133
+ model: CODEX_DEFAULT_MODEL,
134
+ },
135
+ },
136
+ });
137
+ }
138
+
139
+ /** Arm the next probe. The timer is unref'd so it never holds the process open. */
140
+ function scheduleCodexRetry(failedAttempts: number): string {
141
+ const delay = nextProbeDelayMs(failedAttempts);
142
+ codexRetryTimer = setTimeout(() => {
143
+ codexRetryTimer = null;
144
+ void probeCodexProvider();
145
+ }, delay);
146
+ codexRetryTimer.unref?.();
147
+ return new Date(Date.now() + delay).toISOString();
148
+ }
149
+
150
+ /**
151
+ * Probe codex and register it if it answers. On a retryable failure — which is
152
+ * nearly every failure, see `provider-probe.ts` — arm the next attempt instead
153
+ * of leaving the provider missing until someone restarts PPM.
154
+ */
155
+ async function probeCodexProvider(): Promise<ProviderProbeStatus> {
156
+ // Probing again once it serves would put a fresh instance in the registry and
157
+ // orphan the live app-server clients the old one holds — every open codex
158
+ // session, and the cleanup handle the server shuts down through.
159
+ const current = probeStatuses.get("codex");
160
+ if (current?.registered) return current;
161
+ if (codexProbeInFlight) return codexProbeInFlight;
162
+ if (codexRetryTimer) {
163
+ clearTimeout(codexRetryTimer);
164
+ codexRetryTimer = null;
165
+ }
166
+ codexProbeInFlight = (async (): Promise<ProviderProbeStatus> => {
167
+ const attempts = (probeStatuses.get("codex")?.attempts ?? 0) + 1;
168
+ const lastProbeAt = new Date().toISOString();
169
+ let status: ProviderProbeStatus;
170
+ try {
171
+ const { CodexAppServerProvider } = await import("./codex-app-server/codex-provider.ts");
172
+ const codex = new CodexAppServerProvider();
173
+ const result = await codex.probe();
174
+ if (result.ok) {
175
+ providerRegistry.register(codex);
176
+ ensureCodexConfigEntry();
177
+ console.log("[registry] Codex provider registered (@openai/codex found)");
178
+ status = { id: "codex", registered: true, attempts, lastProbeAt };
179
+ } else {
180
+ status = { id: "codex", registered: false, attempts, lastProbeAt, reason: result.reason };
181
+ if (result.retryable) status.nextProbeAt = scheduleCodexRetry(attempts);
182
+ console.log(
183
+ `[registry] Codex provider unavailable: ${result.reason}` +
184
+ (status.nextProbeAt ? ` — retrying at ${status.nextProbeAt}` : ""),
185
+ );
114
186
  }
115
- console.log("[registry] Codex provider registered (@openai/codex found)");
116
- } else {
117
- console.log("[registry] Codex provider skipped (@openai/codex not found)");
187
+ } catch (e) {
188
+ // A broken import is a bug, not a flat host — but it is still worth
189
+ // retrying, since the alternative is silence until the next restart.
190
+ status = { id: "codex", registered: false, attempts, lastProbeAt, reason: (e as Error).message };
191
+ status.nextProbeAt = scheduleCodexRetry(attempts);
192
+ console.warn("[registry] Failed to load Codex provider:", (e as Error).message);
118
193
  }
119
- } catch (e) {
120
- console.warn("[registry] Failed to load Codex provider:", (e as Error).message);
194
+ probeStatuses.set("codex", status);
195
+ return status;
196
+ })();
197
+ try {
198
+ return await codexProbeInFlight;
199
+ } finally {
200
+ codexProbeInFlight = null;
121
201
  }
122
202
  }
@@ -218,7 +218,9 @@ app.route("/api/fs/sqlite", fsSqliteRoutes);
218
218
 
219
219
  // System resource monitoring (SSE + JSON)
220
220
  import { resourceRoutes } from "./routes/resources.ts";
221
+ import { systemServiceRoutes } from "./routes/system-services.ts";
221
222
  app.route("/api/system", resourceRoutes);
223
+ app.route("/api/system", systemServiceRoutes);
222
224
 
223
225
  // Host OS facts for the file explorer (platform, drives, known + pinned folders)
224
226
  import { hostInfoRoutes } from "./routes/host-info.ts";
@@ -290,6 +292,13 @@ app.route("/api/upgrade", upgradeRoutes);
290
292
  import { cloudRoutes } from "./routes/cloud.ts";
291
293
  app.route("/api/cloud", cloudRoutes);
292
294
 
295
+ // Speech-to-text (Whisper on the host) for the chat mic
296
+ import { speechRoutes } from "./routes/speech.ts";
297
+ app.route("/api/speech", speechRoutes);
298
+ // Language servers, machine-wide (the Settings pane). The per-project half is project-scoped.
299
+ import { lspGlobalRoutes } from "./routes/lsp.ts";
300
+ app.route("/api/lsp", lspGlobalRoutes);
301
+
293
302
  // Static files / SPA fallback (non-API routes)
294
303
  app.route("/", staticRoutes);
295
304
 
@@ -30,7 +30,11 @@ export async function authMiddleware(c: Context, next: Next) {
30
30
  if (c.req.method === "GET") {
31
31
  const p = c.req.path;
32
32
  const isMediaPath = p.endsWith("/files/raw") || p.endsWith("/files/transcode") || p === "/api/fs/raw" || p === "/api/fs/transcode";
33
- if (p.endsWith("/stream") || isMediaPath || p.endsWith("/image")) {
33
+ // An <img> cannot send an Authorization header either. This one route is safe
34
+ // to widen to: it takes an APP ID, not a path, and answers only with the icon
35
+ // that app's own desktop entry already points at.
36
+ const isAppIcon = p.startsWith("/api/system/app-icon/");
37
+ if (p.endsWith("/stream") || isMediaPath || isAppIcon || p.endsWith("/image")) {
34
38
  const queryToken = c.req.query("token");
35
39
  if (queryToken && queryToken === authConfig.token) {
36
40
  return next();
@@ -4,6 +4,7 @@ import { listCodexAccounts, removeCodexAccount, getAllCodexUsages, getCodexStrat
4
4
  import { addApiKeyAccount, startDeviceLogin, getDeviceLoginStatus, cancelDeviceLogin, startBrowserLogin, submitBrowserCallback, getBrowserLoginStatus, cancelBrowserLogin } from "../../services/codex-account-login.ts";
5
5
  import { exportCodexEncrypted, importCodexEncrypted } from "../../services/codex-account-portability.ts";
6
6
  import { isCodexAccountAuthFailed } from "../../services/codex-account-auth-state.ts";
7
+ import { ResetCreditRefusedError, spendCodexResetCredit } from "../../services/codex-reset-credit.service.ts";
7
8
 
8
9
  /** Codex multi-account management. Mounted under /api/codex-accounts (auth-guarded). */
9
10
  export const codexAccountsRoutes = new Hono();
@@ -65,6 +66,19 @@ codexAccountsRoutes.patch("/:id", async (c) => {
65
66
  return c.json(ok(updated));
66
67
  });
67
68
 
69
+ /**
70
+ * POST /api/codex-accounts/:id/reset-credit — spend one free rate-limit reset.
71
+ * Refused with 409 unless a limit is reached right now (checked live) and a credit is left.
72
+ */
73
+ codexAccountsRoutes.post("/:id/reset-credit", async (c) => {
74
+ try {
75
+ return c.json(ok(await spendCodexResetCredit(c.req.param("id"))));
76
+ } catch (e) {
77
+ if (e instanceof ResetCreditRefusedError) return c.json(err(e.message), e.status);
78
+ return c.json(err((e as Error).message), 502);
79
+ }
80
+ });
81
+
68
82
  /** Set the selection strategy. */
69
83
  codexAccountsRoutes.put("/strategy", async (c) => {
70
84
  const body = await c.req.json<{ strategy?: CodexStrategy }>().catch(() => ({} as { strategy?: CodexStrategy }));
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The header pair every state-changing system route requires.
3
+ *
4
+ * PPM can be configured with auth disabled on a LAN, and a page on any other
5
+ * origin can submit an HTML form to this server. Such a form can set neither a
6
+ * JSON content type nor a custom header, so demanding BOTH forces a CORS
7
+ * preflight the browser will refuse to make on its behalf.
8
+ *
9
+ * One function, so the kill, signal and service-action routes cannot drift into
10
+ * three slightly different ideas of what a same-origin request looks like. A
11
+ * bodyless action still sends `{}` rather than being granted an exception here.
12
+ */
13
+ import type { Context } from "hono";
14
+
15
+ export function crossOriginRefusal(c: Context): string | null {
16
+ const contentType = c.req.header("content-type") ?? "";
17
+ if (!contentType.toLowerCase().startsWith("application/json")) return "Content-Type must be application/json";
18
+ if (c.req.header("x-ppm-request") !== "1") return "Missing X-PPM-Request header";
19
+ return null;
20
+ }
@@ -4,9 +4,11 @@ import { gitService } from "../../services/git.service.ts";
4
4
  import { gitHunksService, type HunkRequest, type HunkScope } from "../../services/git-hunks/git-hunks.service.ts";
5
5
  import { assertSafeRev, gitBlameService } from "../../services/git-blame/git-blame.service.ts";
6
6
  import { branchDiff } from "../../services/git-branch-diff/branch-diff.service.ts";
7
+ import { assertRef } from "../../services/git-branch-diff/branch-diff-parse.ts";
7
8
  import { discoverGitRepos, isGitRepo } from "../../services/git-repos/git-repo-discovery.ts";
8
9
  import { isInsideDir, realPathOrSelfSync } from "../../services/fs-ops/fs-real-path.ts";
9
10
  import { ok, err } from "../../types/api.ts";
11
+ import type { CheckoutMode } from "../../types/git.ts";
10
12
 
11
13
  type Env = { Variables: { projectPath: string; projectName: string } };
12
14
 
@@ -267,6 +269,22 @@ gitRoutes.get("/branches", async (c) => {
267
269
  }
268
270
  });
269
271
 
272
+ /**
273
+ * GET /git/refs — every checkout target the branch picker offers.
274
+ *
275
+ * Separate from `/branches` rather than an enrichment of it: this answer costs
276
+ * one `for-each-ref` over *three* namespaces and carries a commit per row,
277
+ * where `/branches` is the cheap list the graph and the review pickers read on
278
+ * mount.
279
+ */
280
+ gitRoutes.get("/refs", async (c) => {
281
+ try {
282
+ return c.json(ok(await gitService.refs(c.get("projectPath"))));
283
+ } catch (e) {
284
+ return c.json(err((e as Error).message), 500);
285
+ }
286
+ });
287
+
270
288
  /** GET /git/pr-url?branch= */
271
289
  gitRoutes.get("/pr-url", async (c) => {
272
290
  try {
@@ -495,20 +513,38 @@ gitRoutes.post("/branch/create", async (c) => {
495
513
  const projectPath = c.get("projectPath");
496
514
  const { name, from } = await c.req.json<{ name: string; from?: string }>();
497
515
  if (!name) return c.json(err("Missing: name"), 400);
498
- await gitService.createBranch(projectPath, name, from);
516
+ // Both land as arguments of `git checkout -b`, so neither may open with a dash.
517
+ await gitService.createBranch(
518
+ projectPath,
519
+ assertRef(name, "name"),
520
+ from ? assertRef(from, "from") : undefined,
521
+ );
499
522
  return c.json(ok({ created: name }));
500
523
  } catch (e) {
501
524
  return c.json(err((e as Error).message), 500);
502
525
  }
503
526
  });
504
527
 
505
- /** POST /git/checkout { ref } */
528
+ /**
529
+ * POST /git/checkout { ref, mode? }
530
+ *
531
+ * `mode` is `checkout` (the default), `detach` or `track` — see
532
+ * `GitService.checkout`. It is validated rather than passed through because it
533
+ * decides which flag precedes the ref, and `assertRef` is what stops the ref
534
+ * itself from *being* a flag: an unchecked `-f` here is a forced checkout that
535
+ * discards the working tree.
536
+ */
537
+ const CHECKOUT_MODES = new Set<CheckoutMode>(["checkout", "detach", "track"]);
538
+
506
539
  gitRoutes.post("/checkout", async (c) => {
507
540
  try {
508
541
  const projectPath = c.get("projectPath");
509
- const { ref } = await c.req.json<{ ref: string }>();
542
+ const { ref, mode } = await c.req.json<{ ref: string; mode?: CheckoutMode }>();
510
543
  if (!ref) return c.json(err("Missing: ref"), 400);
511
- await gitService.checkout(projectPath, ref);
544
+ if (mode && !CHECKOUT_MODES.has(mode)) {
545
+ return c.json(err(`Unknown checkout mode: "${mode}"`), 400);
546
+ }
547
+ await gitService.checkout(projectPath, assertRef(ref, "ref"), mode);
512
548
  return c.json(ok({ checkedOut: ref }));
513
549
  } catch (e) {
514
550
  return c.json(err((e as Error).message), 500);
@@ -6,13 +6,19 @@
6
6
  * at all, which is indistinguishable from a broken feature unless something
7
7
  * says so — hence the install hint travelling with the availability.
8
8
  *
9
- * Nothing here installs anything. A silent network install triggered by opening
10
- * a file is not a thing an editor should do on the user's behalf.
9
+ * Installing is a POST, and nothing else here triggers one. A network install because a file
10
+ * was opened is not a thing an editor should do on the user's behalf; pressing Install is.
11
+ *
12
+ * There are two routers because there are two questions. The editor asks about *this project*
13
+ * — its `node_modules/.bin` counts, and a rustup component belongs in the toolchain that
14
+ * project selects. Settings asks about *this machine*, with no project open at all. They share
15
+ * the install handler, so neither can drift into accepting a package name.
11
16
  */
12
- import { Hono } from "hono";
17
+ import { Hono, type Context } from "hono";
13
18
  import { sep } from "node:path";
14
19
  import { lspManager } from "../../services/lsp/lsp-manager.ts";
15
- import { lspLanguageForPath } from "../../services/lsp/server-registry.ts";
20
+ import { installLanguageServer, lspInstallDir, uninstallLanguageServer } from "../../services/lsp/lsp-install.ts";
21
+ import { lspLanguageForPath, serverById, serversSharingInstall } from "../../services/lsp/server-registry.ts";
16
22
  import { ok, err } from "../../types/api.ts";
17
23
 
18
24
  type Env = { Variables: { projectPath: string; projectName: string } };
@@ -55,4 +61,91 @@ lspRoutes.get("/status", async (c) => {
55
61
  }
56
62
  });
57
63
 
64
+ /**
65
+ * POST /lsp/install — install the missing server, because someone pressed Install.
66
+ *
67
+ * The project, because `rustup component add` acts on the toolchain that directory selects.
68
+ */
69
+ lspRoutes.post("/install", (c) => installServer(c, c.get("projectPath")));
70
+
71
+ /**
72
+ * The machine-wide pair, for the Settings pane: `/api/lsp/*`.
73
+ *
74
+ * Settings is not open on a project, so there is no `node_modules/.bin` to consider and
75
+ * `rustup component add` lands in whichever toolchain PPM's own directory selects — the
76
+ * default one. That is the honest answer to "install rust-analyzer on this machine", and the
77
+ * pane says so; a project pinning its own toolchain still gets it from the editor's button.
78
+ */
79
+ export const lspGlobalRoutes = new Hono();
80
+
81
+ /** GET /api/lsp/servers — every registered server, whether the machine has it, and where installs go. */
82
+ lspGlobalRoutes.get("/servers", async (c) => {
83
+ try {
84
+ return c.json(ok({
85
+ servers: await lspManager.availability(),
86
+ installDir: lspInstallDir(),
87
+ running: lspManager.running(),
88
+ }));
89
+ } catch (e) {
90
+ return c.json(err((e as Error).message), 500);
91
+ }
92
+ });
93
+
94
+ lspGlobalRoutes.post("/install", (c) => installServer(c, undefined));
95
+
96
+ /**
97
+ * POST /api/lsp/uninstall — remove a server, from the Settings pane.
98
+ *
99
+ * Only here, and not on the editor's router: that dialog is only ever shown for a server that
100
+ * is *missing*, so it has nothing to remove. The gate is `removable`, which comes from where
101
+ * the server was found rather than from what the browser claims — a copy on `PATH` is the
102
+ * user's, and PPM has no business deleting it.
103
+ */
104
+ lspGlobalRoutes.post("/uninstall", async (c) => {
105
+ const body = await c.req.json().catch(() => ({}) as Record<string, unknown>);
106
+ const definition = serverById(String(body.serverId ?? ""));
107
+ if (!definition) return c.json(err("No such language server"), 400);
108
+
109
+ const row = (await lspManager.availability()).find((s) => s.id === definition.id);
110
+ if (!row?.removable) {
111
+ return c.json(err(`PPM did not install ${definition.displayName}, so there is nothing for it to remove.`), 400);
112
+ }
113
+
114
+ try {
115
+ // The idle sessions first: the files are about to go, and on Windows a running binary
116
+ // cannot be unlinked at all. Every server the package serves, not just the row that was
117
+ // clicked — `vscode-langservers-extracted` is JSON, HTML and CSS, so removing the JSON
118
+ // row deletes files an open `.html` buffer is still running out of.
119
+ for (const id of new Set([definition.id, ...serversSharingInstall(definition).map((s) => s.id)])) {
120
+ await lspManager.stopIdle(id);
121
+ }
122
+ await uninstallLanguageServer(definition);
123
+ return c.json(ok({ id: definition.id, displayName: definition.displayName }));
124
+ } catch (e) {
125
+ return c.json(err((e as Error).message), 500);
126
+ }
127
+ });
128
+
129
+ /**
130
+ * The one install handler, shared by both routers.
131
+ *
132
+ * The body carries a server **id** and nothing else: the packages are the registry's, so no
133
+ * part of the command being run was chosen by the browser.
134
+ */
135
+ async function installServer(c: Context, projectPath: string | undefined): Promise<Response> {
136
+ const body = await c.req.json().catch(() => ({}) as Record<string, unknown>);
137
+ const definition = serverById(String(body.serverId ?? ""));
138
+ if (!definition) return c.json(err("No such language server"), 400);
139
+ if (!definition.install) {
140
+ return c.json(err(`PPM cannot install ${definition.displayName}. Install it yourself: ${definition.installHint}`), 400);
141
+ }
142
+
143
+ try {
144
+ await installLanguageServer(definition, { projectPath });
145
+ return c.json(ok({ id: definition.id, displayName: definition.displayName }));
146
+ } catch (e) {
147
+ return c.json(err((e as Error).message), 500);
148
+ }
149
+ }
150
+
58
151
  export default lspRoutes;