@hienlh/ppm 0.18.12 → 0.18.14

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 (548) hide show
  1. package/AGENTS.md +17 -5
  2. package/CHANGELOG.md +27 -0
  3. package/CLAUDE.md +3 -0
  4. package/README.md +6 -6
  5. package/assets/skills/ppm/SKILL.md +1 -1
  6. package/assets/skills/ppm/references/cli-reference.md +4 -4
  7. package/assets/skills/ppm/references/http-api.md +19 -1
  8. package/dist/web/assets/{adaptive-context-menu-DGCKKeTy.js → adaptive-context-menu-DCZtgOL7.js} +1 -1
  9. package/dist/web/assets/{ai-resource-editor-BOHHTTe7.js → ai-resource-editor-D5CPBg06.js} +1 -1
  10. package/dist/web/assets/{ai-settings-section-BigC_nZR.js → ai-settings-section-DY-t1bK8.js} +1 -1
  11. package/dist/web/assets/{angular-html-BYPaydvh.js → angular-html-CTvM4ulF.js} +1 -1
  12. package/dist/web/assets/{angular-ts-Bb4AMKlk.js → angular-ts-B_vSkjco.js} +1 -1
  13. package/dist/web/assets/api-client-BogqsFna.js +1 -0
  14. package/dist/web/assets/{api-settings-Bd3M4YpI.js → api-settings-B2iNXQ0c.js} +1 -1
  15. package/dist/web/assets/api-settings-DRF9oYkn.js +1 -0
  16. package/dist/web/assets/{api-themes-Cpx419SL.js → api-themes-DrWnJbhs.js} +1 -1
  17. package/dist/web/assets/{apl-DB2VjFCS.js → apl-DywzTry0.js} +1 -1
  18. package/dist/web/assets/architecture-PBZL5I3N-nw5-j_I_.js +1 -0
  19. package/dist/web/assets/{astro-BeoJdVpk.js → astro-1JaRgaSb.js} +1 -1
  20. package/dist/web/assets/{audio-preview-BgFuTn-0.js → audio-preview-DAuGvOiK.js} +1 -1
  21. package/dist/web/assets/{blade-Cf2q1sPf.js → blade-CDeeJWBb.js} +1 -1
  22. package/dist/web/assets/{bsl-W1kOaNpu.js → bsl-BfgoPVYR.js} +1 -1
  23. package/dist/web/assets/{button-5zTrkEoN.js → button-tNy0ba3y.js} +1 -1
  24. package/dist/web/assets/{cairo-BoAZFcje.js → cairo-C26gNwWW.js} +1 -1
  25. package/dist/web/assets/chat-tab-IcnU3nqQ.js +15 -0
  26. package/dist/web/assets/{cobol-B0Nm7RXj.js → cobol-D92nBnON.js} +1 -1
  27. package/dist/web/assets/code-editor-Dno5Srkm.js +10 -0
  28. package/dist/web/assets/{coffee-BakMn3on.js → coffee-CIWH40R1.js} +1 -1
  29. package/dist/web/assets/{conflict-editor-BUs5k9q_.js → conflict-editor-CDp0I3mD.js} +1 -1
  30. package/dist/web/assets/{context-menu-Bq92km4s.js → context-menu-BO1c9jKy.js} +1 -1
  31. package/dist/web/assets/{cpp-BRAJQHK2.js → cpp-DOrBqXCn.js} +1 -1
  32. package/dist/web/assets/{crystal-kqqO3zkK.js → crystal-BNKqmHux.js} +1 -1
  33. package/dist/web/assets/{csv-preview-ByoDgLAZ.js → csv-preview-D4svNDAq.js} +1 -1
  34. package/dist/web/assets/{data-grid-overlay-editor-Brkf9z41.js → data-grid-overlay-editor-BqV0AxZg.js} +1 -1
  35. package/dist/web/assets/{database-viewer-Btc3h8Yu.js → database-viewer-BCvv_Bwf.js} +1 -1
  36. package/dist/web/assets/{dialog-DwtGlowE.js → dialog-DcLGDwaX.js} +1 -1
  37. package/dist/web/assets/diff-viewer-D41fCFAi.js +4 -0
  38. package/dist/web/assets/{docx-preview-DAD_vg59.js → docx-preview-DfaQn9v7.js} +1 -1
  39. package/dist/web/assets/{edge-Cq1ZKZuE.js → edge-Dbjp42Pt.js} +1 -1
  40. package/dist/web/assets/{edit-diff-preview-B_VE7ppQ.js → edit-diff-preview-BqcUuFCc.js} +1 -1
  41. package/dist/web/assets/{elixir-BM_JoJRk.js → elixir-na3b1pYy.js} +1 -1
  42. package/dist/web/assets/{elm-Dw7oO08Y.js → elm-_Nalil1R.js} +1 -1
  43. package/dist/web/assets/{erb-CfKOGAfk.js → erb-CW_7dubf.js} +1 -1
  44. package/dist/web/assets/{erlang-DlDmGVeE.js → erlang-DmZ7Zzb0.js} +1 -1
  45. package/dist/web/assets/{esm-DGAP0GFh.js → esm-CwyBetO1.js} +1 -1
  46. package/dist/web/assets/explorer-body-DB1L30pa.js +2 -0
  47. package/dist/web/assets/explorer-window-content-Cwlt3C3I.js +1 -0
  48. package/dist/web/assets/{extension-store-Cpfh2vMm.js → extension-store-DUaZINyC.js} +1 -1
  49. package/dist/web/assets/{extension-webview-B2OnjuCu.js → extension-webview-BW_mccb3.js} +1 -1
  50. package/dist/web/assets/{file-store-aOERIEo-.js → file-store-yReVbR8q.js} +1 -1
  51. package/dist/web/assets/{fortran-fixed-form-XnAhQWxS.js → fortran-fixed-form-DB2A8L4-.js} +1 -1
  52. package/dist/web/assets/{fsharp-CdNvy0PG.js → fsharp-BYHrti7z.js} +1 -1
  53. package/dist/web/assets/{gdresource-DxuG5i8i.js → gdresource-D5GBin40.js} +1 -1
  54. package/dist/web/assets/{git-commit-3lMonsur.js → git-commit-CUiOBoIL.js} +1 -1
  55. package/dist/web/assets/{git-log-panel-Co0PBPHC.js → git-log-panel-C1QDkmgl.js} +1 -1
  56. package/dist/web/assets/{git-rebase-N8Z9kIMf.js → git-rebase-DOxGnpdw.js} +1 -1
  57. package/dist/web/assets/gitGraph-HDMCJU4V-C1xf87gN.js +1 -0
  58. package/dist/web/assets/glide-data-grid-Dz8lx6n2.js +138 -0
  59. package/dist/web/assets/{glimmer-js-Dp9OXiib.js → glimmer-js-Begy4UT7.js} +1 -1
  60. package/dist/web/assets/{glimmer-ts-CDVKBcDj.js → glimmer-ts-rPApRY8N.js} +1 -1
  61. package/dist/web/assets/{glsl-DPJxI4us.js → glsl-wrbPvrBL.js} +1 -1
  62. package/dist/web/assets/{graphql-BrFhaQQl.js → graphql-Cu4-NR__.js} +1 -1
  63. package/dist/web/assets/group-chat-tab-DFwr-pig.js +1 -0
  64. package/dist/web/assets/{hack-BzXbDMlA.js → hack-Ddo93XKD.js} +1 -1
  65. package/dist/web/assets/{haml-CPpkX0s5.js → haml-BFX_1i8j.js} +1 -1
  66. package/dist/web/assets/{handlebars-BqrApy52.js → handlebars-5gFKA4H5.js} +1 -1
  67. package/dist/web/assets/{html-DmjUl-OA.js → html-C06I-zeO.js} +1 -1
  68. package/dist/web/assets/{html-derivative-Cnd6XFR5.js → html-derivative-e5JLAFZF.js} +1 -1
  69. package/dist/web/assets/{http-DMLWYun2.js → http-CrAAhSU7.js} +1 -1
  70. package/dist/web/assets/{hurl-CKkCVxbj.js → hurl-T1V3SX9T.js} +1 -1
  71. package/dist/web/assets/{hxml-CAx19TtQ.js → hxml-B056LLKN.js} +1 -1
  72. package/dist/web/assets/{image-preview-DHUoylQ1.js → image-preview-DWyuCYT3.js} +1 -1
  73. package/dist/web/assets/index-DWpNR3nB.css +2 -0
  74. package/dist/web/assets/index-oUKV5nIA.js +52 -0
  75. package/dist/web/assets/info-3K5VOQVL-C2z7FTDe.js +1 -0
  76. package/dist/web/assets/{input-DcEk7mA3.js → input-DouJ9Zvt.js} +1 -1
  77. package/dist/web/assets/{jinja-BmB9YN9l.js → jinja-DGdtRh43.js} +1 -1
  78. package/dist/web/assets/{jison-BaVsKKpw.js → jison-Ah6QobPS.js} +1 -1
  79. package/dist/web/assets/{julia-BgVBLveX.js → julia-BJeGOK0K.js} +1 -1
  80. package/dist/web/assets/{just-C2ENIbl9.js → just-iw9oRs7j.js} +1 -1
  81. package/dist/web/assets/{keybindings-store-BGIyqXHI.js → keybindings-store-0Wqfa7Qp.js} +1 -1
  82. package/dist/web/assets/keybindings-store-d54pv2NK.js +1 -0
  83. package/dist/web/assets/{latex-BiDIWxKL.js → latex-DHjj5hyN.js} +1 -1
  84. package/dist/web/assets/{liquid-NxpapreE.js → liquid-B-FFecDc.js} +1 -1
  85. package/dist/web/assets/{lua-DVepQvwH.js → lua-DDianJp_.js} +1 -1
  86. package/dist/web/assets/{markdown-renderer-DlcDhgrF.js → markdown-renderer-BHiUhQN8.js} +3 -3
  87. package/dist/web/assets/markdown-renderer-CnE36_gd.js +1 -0
  88. package/dist/web/assets/{marko-CJ2606Xl.js → marko-BW5SBVng.js} +1 -1
  89. package/dist/web/assets/{mdc-D2bjqclE.js → mdc-B9gL9bjl.js} +1 -1
  90. package/dist/web/assets/{media-url-H17XJF-I.js → media-url-DUK-k0bB.js} +1 -1
  91. package/dist/web/assets/{mobile-bottom-sheet-g-r2hCFa.js → mobile-bottom-sheet-CJ7ApOkI.js} +1 -1
  92. package/dist/web/assets/mobile-explorer-sheet-BzjlS1Xn.js +1 -0
  93. package/dist/web/assets/{nextflow-BtJwUbfF.js → nextflow-dTluY6qy.js} +1 -1
  94. package/dist/web/assets/{nginx-j4gyIhHE.js → nginx-DlwghGI-.js} +1 -1
  95. package/dist/web/assets/{nim-ClH_gjP5.js → nim-N9jddb5D.js} +1 -1
  96. package/dist/web/assets/notification-store-C7UBqxYP.js +1 -0
  97. package/dist/web/assets/{number-overlay-editor-C1EqJnWq.js → number-overlay-editor-BVXM7aAs.js} +1 -1
  98. package/dist/web/assets/{overview-panel-vTeeJYVZ.js → overview-panel-DCCDmtCQ.js} +1 -1
  99. package/dist/web/assets/packet-RMMSAZCW-DQUxN0wU.js +1 -0
  100. package/dist/web/assets/{panel-store-BSnkjgHt.js → panel-store-B4rijFKN.js} +1 -1
  101. package/dist/web/assets/{pdf-preview-CqFGRY0Z.js → pdf-preview-D7yLmAZW.js} +1 -1
  102. package/dist/web/assets/{perl-C9H7X7CT.js → perl-CkmpYKa_.js} +1 -1
  103. package/dist/web/assets/{php-Bx2U-cQ_.js → php-BwZ3KDPo.js} +1 -1
  104. package/dist/web/assets/pie-UPGHQEXC-BOr9ek4Q.js +1 -0
  105. package/dist/web/assets/{postgres-viewer-DHwcQucn.js → postgres-viewer--CRN1fvO.js} +3 -3
  106. package/dist/web/assets/{process-table-BGRJNlpn.js → process-table-CXC10GSy.js} +1 -1
  107. package/dist/web/assets/{project-store--nvQiy75.js → project-store-BuY7rxn_.js} +1 -1
  108. package/dist/web/assets/{pug-Cw74sKsE.js → pug-B3rBPqQo.js} +1 -1
  109. package/dist/web/assets/{qml-BXD94Eqz.js → qml-BfDbWFmg.js} +1 -1
  110. package/dist/web/assets/radar-KQ55EAFF-DSErxZFb.js +1 -0
  111. package/dist/web/assets/{razor-DZ0-Ge0S.js → razor-B1ww1r38.js} +1 -1
  112. package/dist/web/assets/{rst-Dtdh0QUj.js → rst-C0MSq6m-.js} +1 -1
  113. package/dist/web/assets/{ruby-BC51BW2Q.js → ruby-ClIZ1wb3.js} +1 -1
  114. package/dist/web/assets/{run-in-terminal-Sd3KyjN4.js → run-in-terminal-4efbW2Xv.js} +1 -1
  115. package/dist/web/assets/{sas-BN8i4qOU.js → sas-DR0j3o4_.js} +1 -1
  116. package/dist/web/assets/{scroll-area-0gljZ6lF.js → scroll-area-ZP8wcwTI.js} +1 -1
  117. package/dist/web/assets/{scss-H-QtA7Rz.js → scss-Vh3JLayR.js} +1 -1
  118. package/dist/web/assets/{send-to-chat-u6m8l-rH.js → send-to-chat-BNrEpAyC.js} +1 -1
  119. package/dist/web/assets/{settings-store-CHY6Kzin.js → settings-store-OLJE7dPH.js} +2 -2
  120. package/dist/web/assets/{settings-tab-IY6K1MiZ.js → settings-tab-B1rvHFc6.js} +1 -1
  121. package/dist/web/assets/settings-tab-BUlmPJ2w.js +1 -0
  122. package/dist/web/assets/{shaderlab-CalNsj_x.js → shaderlab-0rHRnQ18.js} +1 -1
  123. package/dist/web/assets/{shellsession-BFrcoR8x.js → shellsession-Dxdw6D8c.js} +1 -1
  124. package/dist/web/assets/{soy-CNbku7vP.js → soy-BHlSNj1y.js} +1 -1
  125. package/dist/web/assets/{sparql-BN_orcVp.js → sparql-B2QaPpni.js} +1 -1
  126. package/dist/web/assets/{sql-query-editor-C6pC3I8l.js → sql-query-editor-R_iKjPP9.js} +1 -1
  127. package/dist/web/assets/{sqlite-viewer-DTr5PzUb.js → sqlite-viewer-b2onA0SP.js} +1 -1
  128. package/dist/web/assets/{stata-C6a5Ijzq.js → stata-CwIxjsEJ.js} +1 -1
  129. package/dist/web/assets/{surrealql-ClplI_HY.js → surrealql-C6vo-rp-.js} +1 -1
  130. package/dist/web/assets/{svelte-DNm-UNXB.js → svelte-LLdJ6rlH.js} +1 -1
  131. package/dist/web/assets/{switch-DKvKya9y.js → switch-DV-BDjyk.js} +1 -1
  132. package/dist/web/assets/system-monitor-body-DPYQlBEt.js +2 -0
  133. package/dist/web/assets/system-monitor-tab-CPQdWv27.js +1 -0
  134. package/dist/web/assets/{system-monitor-window-content-BUqRsPK2.js → system-monitor-window-content-BPif0azo.js} +1 -1
  135. package/dist/web/assets/tab-host-window-content-BnAN6m4K.js +1 -0
  136. package/dist/web/assets/{tab-store-CJuJRapl.js → tab-store-tFnyPmm4.js} +1 -1
  137. package/dist/web/assets/team-member-sheet-Bu2wG1sm.js +2 -0
  138. package/dist/web/assets/{team-member-window-content-T4Q5JI-G.js → team-member-window-content-BSyU-5Uc.js} +1 -1
  139. package/dist/web/assets/{templ-CSdqVobu.js → templ-CJGvhEP5.js} +1 -1
  140. package/dist/web/assets/{terminal-tab-Bb2rZegQ.js → terminal-tab-Ncor0Rfu.js} +3 -3
  141. package/dist/web/assets/{tex-DzSJ4kcZ.js → tex-psXWhc4t.js} +1 -1
  142. package/dist/web/assets/{tool-cards-lhqhrDTT.js → tool-cards-DdVP1wrD.js} +4 -4
  143. package/dist/web/assets/treemap-KZPCXAKY-C17p0LQw.js +1 -0
  144. package/dist/web/assets/{ts-tags-C28w3bTg.js → ts-tags-D5Ar_ZCO.js} +1 -1
  145. package/dist/web/assets/{twig-i5jY3QXB.js → twig-vJgGC-qY.js} +1 -1
  146. package/dist/web/assets/{use-blob-url-Dsq9OjTh.js → use-blob-url-BOVGWg9F.js} +1 -1
  147. package/dist/web/assets/use-coarse-long-press-BmI_GVW5.js +1 -0
  148. package/dist/web/assets/use-monaco-theme-BshnLXoY.js +1 -0
  149. package/dist/web/assets/{use-open-team-member-DkiEjFYE.js → use-open-team-member-CY3wOdWL.js} +1 -1
  150. package/dist/web/assets/{use-websocket-B8R50f7f.js → use-websocket-B7xjNsyD.js} +1 -1
  151. package/dist/web/assets/{vendor-mermaid-By4AVvJY.js → vendor-mermaid-999ksD45.js} +1 -1
  152. package/dist/web/assets/video-preview-7F72sRwf.js +1 -0
  153. package/dist/web/assets/{vue-Ceyet_lv.js → vue-BWngFyav.js} +1 -1
  154. package/dist/web/assets/{vue-html-GuU7g_hg.js → vue-html-BN5ZLu-H.js} +1 -1
  155. package/dist/web/assets/{vue-vine-CxXoaJr2.js → vue-vine-BZHnO8yV.js} +1 -1
  156. package/dist/web/assets/window-pip-registry-BnYU83LE.js +1 -0
  157. package/dist/web/assets/{window-store-CsEW6jiE.js → window-store-CQ1lghvv.js} +1 -1
  158. package/dist/web/assets/{xml-CbqOVhkP.js → xml-DS2beZHp.js} +1 -1
  159. package/dist/web/assets/{xsl-KfAmCauy.js → xsl-Ciiku1Bq.js} +1 -1
  160. package/dist/web/index.html +47 -45
  161. package/dist/web/sw.js +1 -1
  162. package/docs/architecture/ai-chat-and-providers.md +309 -0
  163. package/docs/architecture/data-and-storage.md +356 -0
  164. package/docs/architecture/extensions.md +496 -0
  165. package/docs/architecture/integrations.md +214 -0
  166. package/docs/architecture/workspace-and-ui.md +399 -0
  167. package/docs/claude-agent-sdk-reference.md +1 -1
  168. package/docs/code-patterns.md +361 -0
  169. package/docs/code-standards.md +8 -358
  170. package/docs/codebase-subsystems.md +364 -0
  171. package/docs/codebase-summary.md +34 -379
  172. package/docs/deployment-guide.md +280 -490
  173. package/docs/design-guidelines.md +4 -3
  174. package/docs/lessons-learned.md +27 -10
  175. package/docs/project-changelog.md +18 -806
  176. package/docs/project-overview-pdr.md +117 -111
  177. package/docs/project-roadmap.md +89 -133
  178. package/docs/system-architecture.md +77 -1826
  179. package/package.json +2 -2
  180. package/src/cli/commands/autostart.ts +2 -2
  181. package/src/cli/commands/config-cmd.ts +12 -3
  182. package/src/cli/commands/status.ts +3 -2
  183. package/src/cli/commands/stop.ts +32 -4
  184. package/src/server/index.ts +17 -3
  185. package/src/server/routes/chat-unread.ts +36 -0
  186. package/src/server/routes/named-tunnel.ts +132 -0
  187. package/src/server/routes/tunnel.ts +13 -0
  188. package/src/server/ws/chat.ts +5 -2
  189. package/src/services/autostart-register.ts +47 -29
  190. package/src/services/cloud.service.ts +26 -1
  191. package/src/services/config-secret-keys.ts +48 -0
  192. package/src/services/config.service.ts +1 -1
  193. package/src/services/db.service.ts +62 -12
  194. package/src/services/edge-forwarder.ts +191 -191
  195. package/src/services/extension-rpc-handlers.ts +9 -1
  196. package/src/services/file-watcher/watch-tree.ts +67 -33
  197. package/src/services/file-watcher.service.ts +28 -10
  198. package/src/services/fs-credential-path-guard.ts +103 -0
  199. package/src/services/fs-path-guard.service.ts +14 -66
  200. package/src/services/named-tunnel/cloudflare-dns-api.ts +40 -0
  201. package/src/services/named-tunnel/cloudflare-zone-api.ts +28 -0
  202. package/src/services/named-tunnel/cloudflared-cert.ts +95 -0
  203. package/src/services/named-tunnel/cloudflared-exec.ts +50 -0
  204. package/src/services/named-tunnel/cloudflared-login-helpers.ts +98 -0
  205. package/src/services/named-tunnel/cloudflared-login.service.ts +182 -0
  206. package/src/services/named-tunnel/hostname-rules.ts +58 -0
  207. package/src/services/named-tunnel/login-output-parser.ts +36 -0
  208. package/src/services/named-tunnel/named-tunnel-args.ts +110 -0
  209. package/src/services/named-tunnel/named-tunnel-config.ts +67 -0
  210. package/src/services/named-tunnel/named-tunnel-probe-state.ts +95 -0
  211. package/src/services/named-tunnel/named-tunnel-readiness.ts +59 -0
  212. package/src/services/named-tunnel/named-tunnel-runtime.ts +42 -0
  213. package/src/services/named-tunnel/named-tunnel-setup-confirm.ts +98 -0
  214. package/src/services/named-tunnel/named-tunnel-setup.service.ts +191 -0
  215. package/src/services/supervisor-state.ts +67 -2
  216. package/src/services/supervisor.ts +454 -157
  217. package/src/services/tunnel-registry-parse.ts +27 -0
  218. package/src/services/tunnel-registry.service.ts +2 -15
  219. package/src/services/tunnel.service.ts +12 -3
  220. package/src/services/windows-process-tree.ts +351 -351
  221. package/src/types/config.ts +31 -0
  222. package/src/web/app.tsx +5 -0
  223. package/src/web/components/chat/chat-history-bar.tsx +95 -98
  224. package/src/web/components/chat/chat-toolbar-overflow-menu.tsx +57 -0
  225. package/src/web/components/chat/session-debug-dialog.tsx +35 -27
  226. package/src/web/components/floating-window/floating-window.tsx +8 -1
  227. package/src/web/components/floating-window/open-tab-in-pip.ts +78 -0
  228. package/src/web/components/floating-window/window-pip-registry.ts +46 -0
  229. package/src/web/components/layout/cloud-share-named-tunnel-row.tsx +111 -0
  230. package/src/web/components/layout/cloud-share-popover.tsx +56 -14
  231. package/src/web/components/layout/tab-pop-out-menu-item.tsx +25 -2
  232. package/src/web/components/shared/connection-lost-overlay.tsx +44 -5
  233. package/src/web/components/tunnels/named-tunnel/hostname-validation.ts +14 -0
  234. package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +96 -0
  235. package/src/web/components/tunnels/named-tunnel/named-tunnel-hostname-field.tsx +51 -0
  236. package/src/web/components/tunnels/named-tunnel/named-tunnel-login-step.tsx +105 -0
  237. package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +159 -0
  238. package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-content.tsx +197 -0
  239. package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-popup.tsx +57 -0
  240. package/src/web/components/tunnels/named-tunnel/named-tunnel-step-reducer.ts +191 -0
  241. package/src/web/components/tunnels/named-tunnel/use-named-tunnel-setup.ts +212 -0
  242. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  243. package/src/web/hooks/use-global-events.ts +3 -1
  244. package/src/web/lib/api-named-tunnel.ts +54 -0
  245. package/src/web/lib/last-known-local-url.ts +23 -0
  246. package/src/web/stores/notification-store.ts +20 -1
  247. package/dist/web/assets/api-client-DTZEgjBQ.js +0 -1
  248. package/dist/web/assets/api-settings-kd1j4iR8.js +0 -1
  249. package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +0 -1
  250. package/dist/web/assets/chat-tab-E3bf_V8X.js +0 -15
  251. package/dist/web/assets/code-editor-BUlM2gXk.js +0 -10
  252. package/dist/web/assets/diff-viewer-CZaDnR4w.js +0 -4
  253. package/dist/web/assets/explorer-body-9aBmyVpZ.js +0 -2
  254. package/dist/web/assets/explorer-window-content-DRtqoSPA.js +0 -1
  255. package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +0 -1
  256. package/dist/web/assets/glide-data-grid-C4_zIneN.js +0 -138
  257. package/dist/web/assets/group-chat-tab-rOd8J8GC.js +0 -1
  258. package/dist/web/assets/index-BImUaigO.js +0 -52
  259. package/dist/web/assets/index-CSfi6DSU.css +0 -2
  260. package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +0 -1
  261. package/dist/web/assets/keybindings-store-CzV2sPls.js +0 -1
  262. package/dist/web/assets/markdown-renderer-CcbR33VG.js +0 -1
  263. package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +0 -1
  264. package/dist/web/assets/notification-store-DV5QtUTg.js +0 -1
  265. package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +0 -1
  266. package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +0 -1
  267. package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +0 -1
  268. package/dist/web/assets/settings-tab-Dic6TKkU.js +0 -1
  269. package/dist/web/assets/system-monitor-body-iwGiCns9.js +0 -2
  270. package/dist/web/assets/system-monitor-tab-DdXQhEel.js +0 -1
  271. package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +0 -1
  272. package/dist/web/assets/team-member-sheet-LkAFSCvb.js +0 -2
  273. package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +0 -1
  274. package/dist/web/assets/use-monaco-theme-BZvlsoBv.js +0 -1
  275. package/dist/web/assets/video-preview-m0-3p7QZ.js +0 -1
  276. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  277. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  278. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  279. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  280. /package/dist/web/assets/{abap-C6nB04tn.js → abap-CjzrhAS2.js} +0 -0
  281. /package/dist/web/assets/{actionscript-3-Vx4rw2sC.js → actionscript-3-B59Kbl-9.js} +0 -0
  282. /package/dist/web/assets/{ada-Ccd8vM20.js → ada-B7gItKAE.js} +0 -0
  283. /package/dist/web/assets/{andromeeda-DnBX5xMg.js → andromeeda-Dy5zcy0Q.js} +0 -0
  284. /package/dist/web/assets/{apache-B-9_sx0g.js → apache-B6T9jrc0.js} +0 -0
  285. /package/dist/web/assets/{apex-_wPVBYoL.js → apex-CTsIxDQw.js} +0 -0
  286. /package/dist/web/assets/{api-client-aQb5hHE5.js → api-client-oY1tC3tM.js} +0 -0
  287. /package/dist/web/assets/{applescript-CcvD-qr0.js → applescript-DuycKmmb.js} +0 -0
  288. /package/dist/web/assets/{apply-theme-BeLRfsSu.js → apply-theme-r8tKDrCR.js} +0 -0
  289. /package/dist/web/assets/{ara-C40Ztoms.js → ara-CISL3599.js} +0 -0
  290. /package/dist/web/assets/{asciidoc-CybYkJV4.js → asciidoc-BXyE2Lpr.js} +0 -0
  291. /package/dist/web/assets/{asm-9eOKwzR0.js → asm-y258phtP.js} +0 -0
  292. /package/dist/web/assets/{aurora-x-B5ZH4t7t.js → aurora-x-Dq3Jc78M.js} +0 -0
  293. /package/dist/web/assets/{awk-Dqilob-2.js → awk-DxL6XSJv.js} +0 -0
  294. /package/dist/web/assets/{ayu-dark-CPgRhf5r.js → ayu-dark-DjoK6Evo.js} +0 -0
  295. /package/dist/web/assets/{ayu-light-Do06Q52f.js → ayu-light-CKKXBLMI.js} +0 -0
  296. /package/dist/web/assets/{ayu-mirage-_BhxcrxY.js → ayu-mirage-DGXSrrXB.js} +0 -0
  297. /package/dist/web/assets/{ballerina-DDwK54QW.js → ballerina-DZSXFmUf.js} +0 -0
  298. /package/dist/web/assets/{bat-BGyGlzGk.js → bat-BNsZk6nY.js} +0 -0
  299. /package/dist/web/assets/{beancount-CRWBdapI.js → beancount-cPl4gJct.js} +0 -0
  300. /package/dist/web/assets/{berry-DbSFn2gO.js → berry-DGAodERk.js} +0 -0
  301. /package/dist/web/assets/{bibtex-QpsV9gm9.js → bibtex-DftVoRif.js} +0 -0
  302. /package/dist/web/assets/{bicep-CxS8CUve.js → bicep-Suioyyzh.js} +0 -0
  303. /package/dist/web/assets/{bird2-CuZhQzYR.js → bird2-DjU24I2P.js} +0 -0
  304. /package/dist/web/assets/{c-9bnDqE3g.js → c-DFi8Y_nN.js} +0 -0
  305. /package/dist/web/assets/{c3-JMZTrOhA.js → c3-1eSHnH5V.js} +0 -0
  306. /package/dist/web/assets/{cadence-DsDNayJS.js → cadence-DLLsFwQP.js} +0 -0
  307. /package/dist/web/assets/{can-open-in-ppm-BJfpynya.js → can-open-in-ppm-in727eFQ.js} +0 -0
  308. /package/dist/web/assets/{catppuccin-frappe-DYIKXXBe.js → catppuccin-frappe-DDj0JEiY.js} +0 -0
  309. /package/dist/web/assets/{catppuccin-latte-IYYOnUJ8.js → catppuccin-latte-DPyANHyR.js} +0 -0
  310. /package/dist/web/assets/{catppuccin-macchiato-BrJ_7mfS.js → catppuccin-macchiato-CO-h8VTT.js} +0 -0
  311. /package/dist/web/assets/{catppuccin-mocha-gzSu7v7-.js → catppuccin-mocha-BCmbN2IZ.js} +0 -0
  312. /package/dist/web/assets/{clarity-DLzsC0Hb.js → clarity-C0pYsZjs.js} +0 -0
  313. /package/dist/web/assets/{clipboard-7fw0Shic.js → clipboard-DBLGKMrH.js} +0 -0
  314. /package/dist/web/assets/{clojure-DS1BvoTt.js → clojure-JFr6s8iZ.js} +0 -0
  315. /package/dist/web/assets/{cmake-CDvsJwYp.js → cmake-EEcLEgVy.js} +0 -0
  316. /package/dist/web/assets/{codeowners-BjsYiflJ.js → codeowners-Deh3Lx0u.js} +0 -0
  317. /package/dist/web/assets/{codeql-CG-7ARat.js → codeql-C317igT5.js} +0 -0
  318. /package/dist/web/assets/{common-lisp-DSO1Lbh9.js → common-lisp-DepbATZs.js} +0 -0
  319. /package/dist/web/assets/{coq-DYdh3oP_.js → coq-MxgxU5ya.js} +0 -0
  320. /package/dist/web/assets/{csharp-DxEBz5s0.js → csharp-eEFXdsAq.js} +0 -0
  321. /package/dist/web/assets/{css-dal3Q-8C.js → css-Db-syWW9.js} +0 -0
  322. /package/dist/web/assets/{csv-CpqjMGiA.js → csv-DHeYcbaq.js} +0 -0
  323. /package/dist/web/assets/{csv-parser-3umBA4NY.js → csv-parser-_JWMLGl3.js} +0 -0
  324. /package/dist/web/assets/{cue-DinoJ_5k.js → cue-BmUNowrt.js} +0 -0
  325. /package/dist/web/assets/{cypher-DzxqmkUW.js → cypher-XjXHgCNS.js} +0 -0
  326. /package/dist/web/assets/{d-BxNwJuEC.js → d-BWJnZtig.js} +0 -0
  327. /package/dist/web/assets/{dark-plus-Clmv3V-0.js → dark-plus-Db7umas1.js} +0 -0
  328. /package/dist/web/assets/{dart-BWVtXD35.js → dart-DSI4HYh1.js} +0 -0
  329. /package/dist/web/assets/{data-grid-types-B4n51Fck.js → data-grid-types-CfVHh9gv.js} +0 -0
  330. /package/dist/web/assets/{dax-DsImuWgJ.js → dax-yw1JsAni.js} +0 -0
  331. /package/dist/web/assets/{desktop-B0jJuG2r.js → desktop-C2QO4RvD.js} +0 -0
  332. /package/dist/web/assets/{diff-CWqAAxoE.js → diff-Drt8aEyp.js} +0 -0
  333. /package/dist/web/assets/{dist-B-EXdSYE.js → dist-DNRvhVdz.js} +0 -0
  334. /package/dist/web/assets/{dist-C0eNNfbt.js → dist-VBxOHLmN.js} +0 -0
  335. /package/dist/web/assets/{docker-CYFCJdIL.js → docker-ByDKbmLl.js} +0 -0
  336. /package/dist/web/assets/{dotenv-CKDUjURg.js → dotenv-BkfOLytR.js} +0 -0
  337. /package/dist/web/assets/{dracula-CSoPspHE.js → dracula-DAmrm-Un.js} +0 -0
  338. /package/dist/web/assets/{dracula-soft-BuFjw5L1.js → dracula-soft-BUOEnKqR.js} +0 -0
  339. /package/dist/web/assets/{dream-maker-B6PdDRZu.js → dream-maker-DQBIfSiO.js} +0 -0
  340. /package/dist/web/assets/{emacs-lisp-CMcXvD0G.js → emacs-lisp-Blh5kBD3.js} +0 -0
  341. /package/dist/web/assets/{everforest-dark-cU8-wYzi.js → everforest-dark-CEzhDxHq.js} +0 -0
  342. /package/dist/web/assets/{everforest-light-KhorllqK.js → everforest-light-CPk_5Khm.js} +0 -0
  343. /package/dist/web/assets/{external-link-B8BynhvY.js → external-link-B6Hl0U4X.js} +0 -0
  344. /package/dist/web/assets/{fennel-BCELZK87.js → fennel-B1MT_EBZ.js} +0 -0
  345. /package/dist/web/assets/{file-exclamation-point-CZ4DiR75.js → file-exclamation-point-JzhTU2TX.js} +0 -0
  346. /package/dist/web/assets/{fish-BQc0y_jy.js → fish-C_HGcewt.js} +0 -0
  347. /package/dist/web/assets/{fluent-BTINnwF6.js → fluent-Dp1Iclmx.js} +0 -0
  348. /package/dist/web/assets/{folder-symlink-B8XrtvQK.js → folder-symlink-Dx1hOk8X.js} +0 -0
  349. /package/dist/web/assets/{format-bytes-WVcFxJuT.js → format-bytes-53WBtyi2.js} +0 -0
  350. /package/dist/web/assets/{fortran-free-form-BQim9wDz.js → fortran-free-form-B_-UA4XC.js} +0 -0
  351. /package/dist/web/assets/{gdscript-03w5u8un.js → gdscript-Bm_JpjS_.js} +0 -0
  352. /package/dist/web/assets/{gdshader-Dp2daNzU.js → gdshader-C_PNmfYU.js} +0 -0
  353. /package/dist/web/assets/{genie-CoNcjPiD.js → genie-B5rmR2TF.js} +0 -0
  354. /package/dist/web/assets/{gherkin-NrPOSPQL.js → gherkin-BTJ34TJ9.js} +0 -0
  355. /package/dist/web/assets/{github-dark-z4RE9ZqA.js → github-dark-DOkNVj9H.js} +0 -0
  356. /package/dist/web/assets/{github-dark-default-DOKw-1cI.js → github-dark-default-DTsmiyVo.js} +0 -0
  357. /package/dist/web/assets/{github-dark-dimmed-DJRNMkEA.js → github-dark-dimmed-CjbxAe9s.js} +0 -0
  358. /package/dist/web/assets/{github-dark-high-contrast-Bj7jJ_Gs.js → github-dark-high-contrast-r_M8F_k7.js} +0 -0
  359. /package/dist/web/assets/{github-light-B4k_yMFu.js → github-light-BzfxyMyb.js} +0 -0
  360. /package/dist/web/assets/{github-light-default-BHc-Uzhs.js → github-light-default-BOqiBIy5.js} +0 -0
  361. /package/dist/web/assets/{github-light-high-contrast-CHisIywL.js → github-light-high-contrast-DQzBrDM4.js} +0 -0
  362. /package/dist/web/assets/{gleam-CfbypZ4q.js → gleam-BWmuAtD8.js} +0 -0
  363. /package/dist/web/assets/{gn-YoAjyhJa.js → gn-CNQPjiZW.js} +0 -0
  364. /package/dist/web/assets/{gnuplot-xVkc1f1c.js → gnuplot-BlHjcPMe.js} +0 -0
  365. /package/dist/web/assets/{go-GPCwP3Gu.js → go-Bn8Ba9uz.js} +0 -0
  366. /package/dist/web/assets/{groovy-Crh4Yww9.js → groovy-C1Y1_F4V.js} +0 -0
  367. /package/dist/web/assets/{gruvbox-dark-hard-BluUFuDS.js → gruvbox-dark-hard-DueOsHav.js} +0 -0
  368. /package/dist/web/assets/{gruvbox-dark-medium-Cxk1FWQp.js → gruvbox-dark-medium-DaQjD538.js} +0 -0
  369. /package/dist/web/assets/{gruvbox-dark-soft-CHXMiFmj.js → gruvbox-dark-soft-CbbX2WOm.js} +0 -0
  370. /package/dist/web/assets/{gruvbox-light-hard-B6eKPjAD.js → gruvbox-light-hard-E2M70ljZ.js} +0 -0
  371. /package/dist/web/assets/{gruvbox-light-medium-pDwMm1ut.js → gruvbox-light-medium-B_DDLY6h.js} +0 -0
  372. /package/dist/web/assets/{gruvbox-light-soft-Cxu6kHqK.js → gruvbox-light-soft-2SZmyC1F.js} +0 -0
  373. /package/dist/web/assets/{haskell-C6JKHjbK.js → haskell-D8DeoXtG.js} +0 -0
  374. /package/dist/web/assets/{haxe-BuBNdF0a.js → haxe-BmZm7B0W.js} +0 -0
  375. /package/dist/web/assets/{hcl-DZpDdGj2.js → hcl-CKnBM3ng.js} +0 -0
  376. /package/dist/web/assets/{hjson-CBkhYRuo.js → hjson-Ct9t4-ci.js} +0 -0
  377. /package/dist/web/assets/{hlsl-C5nMxnp9.js → hlsl-BZSASBqS.js} +0 -0
  378. /package/dist/web/assets/{horizon-VAFvA6R6.js → horizon-CzX1AZ08.js} +0 -0
  379. /package/dist/web/assets/{horizon-bright-BC0xn7T3.js → horizon-bright-CCVNeRIP.js} +0 -0
  380. /package/dist/web/assets/{houston-BxrUivmz.js → houston-DBlJN7xc.js} +0 -0
  381. /package/dist/web/assets/{hy-DLtOXoaH.js → hy-Dyc6h6Xb.js} +0 -0
  382. /package/dist/web/assets/{image-gallery-Gnf7TdCR.js → image-gallery-DujlrjOC.js} +0 -0
  383. /package/dist/web/assets/{imba-BdpFXM2W.js → imba-Bauru7s2.js} +0 -0
  384. /package/dist/web/assets/{ini-BInJO_T0.js → ini-SjdwtaTp.js} +0 -0
  385. /package/dist/web/assets/{java-Dxuddnkb.js → java-D2r0ocpf.js} +0 -0
  386. /package/dist/web/assets/{javascript-CVamJfLY.js → javascript-y-lof7iP.js} +0 -0
  387. /package/dist/web/assets/{json-BLZ0ozYk.js → json-DO4LSx5A.js} +0 -0
  388. /package/dist/web/assets/{json5-BnXzmMKs.js → json5-BEwWf-W3.js} +0 -0
  389. /package/dist/web/assets/{jsonc-CSgkSga7.js → jsonc-OBEFv7gP.js} +0 -0
  390. /package/dist/web/assets/{jsonl-CY5W2nF2.js → jsonl-DOyW4Mg3.js} +0 -0
  391. /package/dist/web/assets/{jsonnet-CEJYH3sF.js → jsonnet-BL5R2CpP.js} +0 -0
  392. /package/dist/web/assets/{jssm-CsJc7Uhk.js → jssm-ksPusAyg.js} +0 -0
  393. /package/dist/web/assets/{jsx-jCiRaHU7.js → jsx-B6XEu6O-.js} +0 -0
  394. /package/dist/web/assets/{kanagawa-dragon-DfoA_GxX.js → kanagawa-dragon-JBVe_ji_.js} +0 -0
  395. /package/dist/web/assets/{kanagawa-lotus-BOLYJpWd.js → kanagawa-lotus-ChprO68_.js} +0 -0
  396. /package/dist/web/assets/{kanagawa-wave-DfKlbT1G.js → kanagawa-wave-D_uB_R0Q.js} +0 -0
  397. /package/dist/web/assets/{kdl-CmssIFTi.js → kdl-pf5B8N_m.js} +0 -0
  398. /package/dist/web/assets/{kotlin-BRsNgp6x.js → kotlin-BdF0METC.js} +0 -0
  399. /package/dist/web/assets/{kusto-T8X9jUab.js → kusto-BneVP-OU.js} +0 -0
  400. /package/dist/web/assets/{laserwave-DkJMVJ8Z.js → laserwave-C4-UPIyG.js} +0 -0
  401. /package/dist/web/assets/{lean-C65KGVPq.js → lean-BN6Jdymq.js} +0 -0
  402. /package/dist/web/assets/{less-exIPdDlf.js → less-Cx-fdlDC.js} +0 -0
  403. /package/dist/web/assets/{lib-mC1NZfuw.js → lib-CMuBa85c.js} +0 -0
  404. /package/dist/web/assets/{libesm-DSutUtl1.js → libesm-BB74PRsH.js} +0 -0
  405. /package/dist/web/assets/{light-plus-DiHUXAZt.js → light-plus-DFnnn_iL.js} +0 -0
  406. /package/dist/web/assets/{llvm-CJBnEzFM.js → llvm-BGxtW0Nw.js} +0 -0
  407. /package/dist/web/assets/{loader-circle-gSPVxfvH.js → loader-circle-Dpqcv0eS.js} +0 -0
  408. /package/dist/web/assets/{lock-Did-87UV.js → lock-DldbT31x.js} +0 -0
  409. /package/dist/web/assets/{log-DxMyUMuP.js → log-kQb4eJnj.js} +0 -0
  410. /package/dist/web/assets/{logo-CC9NKzca.js → logo-DqAzaq7s.js} +0 -0
  411. /package/dist/web/assets/{luau-Bw10I6zf.js → luau-Dc2cp-zS.js} +0 -0
  412. /package/dist/web/assets/{make-C_6M90m6.js → make-DYg9dwaJ.js} +0 -0
  413. /package/dist/web/assets/{markdown-bR9_R-LF.js → markdown-O4EPpS3K.js} +0 -0
  414. /package/dist/web/assets/{material-theme-BUx2Qujn.js → material-theme-ClP8yfQ2.js} +0 -0
  415. /package/dist/web/assets/{material-theme-darker-CRJrPgKm.js → material-theme-darker-LOK55hGu.js} +0 -0
  416. /package/dist/web/assets/{material-theme-lighter-CUAYppPa.js → material-theme-lighter-j72tzZqi.js} +0 -0
  417. /package/dist/web/assets/{material-theme-ocean-DuINF1fg.js → material-theme-ocean-C19LKClA.js} +0 -0
  418. /package/dist/web/assets/{material-theme-palenight-W6_icGCj.js → material-theme-palenight-DJ5tN2ax.js} +0 -0
  419. /package/dist/web/assets/{matlab-rfqn_b3z.js → matlab-DQNZ_NU8.js} +0 -0
  420. /package/dist/web/assets/{mdx-Bh1B_YOJ.js → mdx-CJayB7XK.js} +0 -0
  421. /package/dist/web/assets/{mermaid-Dxf6Ya2k.js → mermaid-Cb0TRX92.js} +0 -0
  422. /package/dist/web/assets/{min-dark-CivZ2L0h.js → min-dark-CWM8Bo-m.js} +0 -0
  423. /package/dist/web/assets/{min-light-B1Ykqtma.js → min-light-BBR1sjS2.js} +0 -0
  424. /package/dist/web/assets/{mipsasm-DynHaM0d.js → mipsasm-Jc7u7YSS.js} +0 -0
  425. /package/dist/web/assets/{mojo-Clw5PbGH.js → mojo-CTB0cutd.js} +0 -0
  426. /package/dist/web/assets/{monitor-Dv8vn_6O.js → monitor-4vWfqzuN.js} +0 -0
  427. /package/dist/web/assets/{monokai-DFIooFZT.js → monokai-CvM_YNKx.js} +0 -0
  428. /package/dist/web/assets/{moonbit-DnBSZWGM.js → moonbit-CbFEfYYM.js} +0 -0
  429. /package/dist/web/assets/{move-CCcL2PfL.js → move-BT38p0kT.js} +0 -0
  430. /package/dist/web/assets/{narrat-BDarg5Lk.js → narrat-55QZ_kOG.js} +0 -0
  431. /package/dist/web/assets/{nextflow-groovy-DrZOeCNW.js → nextflow-groovy-Bg8peyqg.js} +0 -0
  432. /package/dist/web/assets/{night-owl-BnZZCK7v.js → night-owl-DzS77iPK.js} +0 -0
  433. /package/dist/web/assets/{night-owl-light-CEwBsVHS.js → night-owl-light-DER7fGnx.js} +0 -0
  434. /package/dist/web/assets/{nix-amCzOPMR.js → nix-BSI8YesN.js} +0 -0
  435. /package/dist/web/assets/{nord-BIs2BC6q.js → nord-9bn7iNWo.js} +0 -0
  436. /package/dist/web/assets/{nushell-Y02fo4yw.js → nushell-qDVZn_lw.js} +0 -0
  437. /package/dist/web/assets/{objective-c-7xOZtWW1.js → objective-c-Blf-ATos.js} +0 -0
  438. /package/dist/web/assets/{objective-cpp-eVtjUvVB.js → objective-cpp-Bz8bAq47.js} +0 -0
  439. /package/dist/web/assets/{ocaml-Bi6ZwqG4.js → ocaml-B9heAsc3.js} +0 -0
  440. /package/dist/web/assets/{odin-8xf1Y0S9.js → odin-BaFYnOwO.js} +0 -0
  441. /package/dist/web/assets/{one-dark-pro-hVv-_y_b.js → one-dark-pro-D6B_hSe-.js} +0 -0
  442. /package/dist/web/assets/{one-light-CJJ3MtHt.js → one-light-Ba-f0wyk.js} +0 -0
  443. /package/dist/web/assets/{openscad-B2HcywLk.js → openscad-UvYyL2MK.js} +0 -0
  444. /package/dist/web/assets/{pascal-C7fllV_7.js → pascal-B4-qvEoG.js} +0 -0
  445. /package/dist/web/assets/{pkl-qvLC1IWP.js → pkl-B146nqGx.js} +0 -0
  446. /package/dist/web/assets/{plastic-BT1wHZv2.js → plastic-L38t-Id3.js} +0 -0
  447. /package/dist/web/assets/{play-4MZi1Axp.js → play-CpCAoQRZ.js} +0 -0
  448. /package/dist/web/assets/{plsql-1MsmdmJD.js → plsql-ItOG5Cca.js} +0 -0
  449. /package/dist/web/assets/{plus-BhMZqFsN.js → plus-BR0qewJI.js} +0 -0
  450. /package/dist/web/assets/{po-BigskytD.js → po-imiCTaNX.js} +0 -0
  451. /package/dist/web/assets/{poimandres-DuklniF7.js → poimandres-Bu6sIba9.js} +0 -0
  452. /package/dist/web/assets/{polar-e2pjN_sp.js → polar-CTeGoFxV.js} +0 -0
  453. /package/dist/web/assets/{portal-container-context-Cm5HipFr.js → portal-container-context-a399Hd9F.js} +0 -0
  454. /package/dist/web/assets/{postcss-DtAeYjWw.js → postcss-jvFe6GNE.js} +0 -0
  455. /package/dist/web/assets/{powerquery-Cr2PtehI.js → powerquery-D9Dw1hJp.js} +0 -0
  456. /package/dist/web/assets/{powershell-BxFTGLJ4.js → powershell-CZqvYQtg.js} +0 -0
  457. /package/dist/web/assets/{prisma-COWJiwdZ.js → prisma-B4D2nO_7.js} +0 -0
  458. /package/dist/web/assets/{prolog-DFvGKRx6.js → prolog-CQbyUcCF.js} +0 -0
  459. /package/dist/web/assets/{proto-CcK80lFt.js → proto-Cwpo0cW1.js} +0 -0
  460. /package/dist/web/assets/{puppet-BF60bZ4F.js → puppet-CKxCwBod.js} +0 -0
  461. /package/dist/web/assets/{purescript-zL_69MzU.js → purescript-B-MyXMMp.js} +0 -0
  462. /package/dist/web/assets/{python-CIwKhfb_.js → python-D6QbSR2S.js} +0 -0
  463. /package/dist/web/assets/{qmldir-CXNe04Lo.js → qmldir-BpTSVcw_.js} +0 -0
  464. /package/dist/web/assets/{qss-C8lAWe6G.js → qss-DBc4gbpe.js} +0 -0
  465. /package/dist/web/assets/{r-CL5ZVL3_.js → r-i9jMMi0s.js} +0 -0
  466. /package/dist/web/assets/{racket-BBfh0uh0.js → racket-BWNaxU7C.js} +0 -0
  467. /package/dist/web/assets/{raku-o6E8R5Q3.js → raku-fqTZLn7L.js} +0 -0
  468. /package/dist/web/assets/{react-CBTnT4sY.js → react-X4jUntEf.js} +0 -0
  469. /package/dist/web/assets/{red-GomRF2Xp.js → red-D-JEcuzA.js} +0 -0
  470. /package/dist/web/assets/{refresh-cw-B06yaBrW.js → refresh-cw-B9iv7csb.js} +0 -0
  471. /package/dist/web/assets/{reg-_ffDIvx9.js → reg-BbirlU1S.js} +0 -0
  472. /package/dist/web/assets/{regexp-Bl5sF65W.js → regexp-D8VTFrtg.js} +0 -0
  473. /package/dist/web/assets/{rel-DgMdqDuj.js → rel-ByQGKiNM.js} +0 -0
  474. /package/dist/web/assets/{resolve-theme-CRt_7wpd.js → resolve-theme-Cqb9zWYc.js} +0 -0
  475. /package/dist/web/assets/{riscv-8b3-Ye4X.js → riscv-B5nqCfLE.js} +0 -0
  476. /package/dist/web/assets/{ron-DrmU1KHP.js → ron-DOVh_iZR.js} +0 -0
  477. /package/dist/web/assets/{rose-pine-dawn-DEfhNlFH.js → rose-pine-dawn-B7hkmmWy.js} +0 -0
  478. /package/dist/web/assets/{rose-pine-C_-E2tF1.js → rose-pine-jp51ZUzi.js} +0 -0
  479. /package/dist/web/assets/{rose-pine-moon-BdvX3gdn.js → rose-pine-moon-Ff063yLj.js} +0 -0
  480. /package/dist/web/assets/{rosmsg-B6GhGpd5.js → rosmsg-Cyk7Il8z.js} +0 -0
  481. /package/dist/web/assets/{rotate-ccw-COXu_9oj.js → rotate-ccw-DnuPzJRE.js} +0 -0
  482. /package/dist/web/assets/{rust-DmC97M1-.js → rust-DRNM5epF.js} +0 -0
  483. /package/dist/web/assets/{sass-B0tJOHLM.js → sass-D_cB0-M1.js} +0 -0
  484. /package/dist/web/assets/{save-CtIGOjmx.js → save-DxonD4y1.js} +0 -0
  485. /package/dist/web/assets/{scala-n8zaFOXv.js → scala-Crl-1kKS.js} +0 -0
  486. /package/dist/web/assets/{scheme-BKD9ztBU.js → scheme-DCaWyEJ0.js} +0 -0
  487. /package/dist/web/assets/{sdbl-D8gB5-rS.js → sdbl-BbXNqwtX.js} +0 -0
  488. /package/dist/web/assets/{send-BlyNJAzy.js → send-B-t5Mz26.js} +0 -0
  489. /package/dist/web/assets/{shallow-DYo6goJ4.js → shallow-4zAfs2KW.js} +0 -0
  490. /package/dist/web/assets/{shellscript-BfXlf_Ao.js → shellscript-BAgksBhW.js} +0 -0
  491. /package/dist/web/assets/{shield-check-B0iGUiOK.js → shield-check-CdTiK1j2.js} +0 -0
  492. /package/dist/web/assets/{shield-off-BNLWBhcq.js → shield-off-DuetkXKM.js} +0 -0
  493. /package/dist/web/assets/{slack-dark-CylEddse.js → slack-dark-GB-ElUW_.js} +0 -0
  494. /package/dist/web/assets/{slack-ochin-w8wg8vuC.js → slack-ochin-tU6CFD3S.js} +0 -0
  495. /package/dist/web/assets/{smalltalk-hiAXA64u.js → smalltalk-DSVGUbtL.js} +0 -0
  496. /package/dist/web/assets/{snazzy-light-BwlV3Xty.js → snazzy-light-DZhi3PoS.js} +0 -0
  497. /package/dist/web/assets/{solarized-dark-vmNGdykz.js → solarized-dark-D6AMCco7.js} +0 -0
  498. /package/dist/web/assets/{solarized-light-DGv_0JXq.js → solarized-light-DepuTWSE.js} +0 -0
  499. /package/dist/web/assets/{solidity-Y7QSH0B1.js → solidity-CsxN618l.js} +0 -0
  500. /package/dist/web/assets/{splunk-BtgpLjHi.js → splunk-CF1m0Kkv.js} +0 -0
  501. /package/dist/web/assets/{sql-CRHYhOia.js → sql-DvyMDgrB.js} +0 -0
  502. /package/dist/web/assets/{ssh-config-DOqSs3au.js → ssh-config-a8sDo-Q8.js} +0 -0
  503. /package/dist/web/assets/{stylus-crCAEaBT.js → stylus-DCJ-6AjT.js} +0 -0
  504. /package/dist/web/assets/{swift-eE3rT7TC.js → swift-c-ZFxyPP.js} +0 -0
  505. /package/dist/web/assets/{synthwave-84-BWy14LBX.js → synthwave-84-9NPgBcuv.js} +0 -0
  506. /package/dist/web/assets/{system-verilog-DC0-DZM4.js → system-verilog-DPD02IOo.js} +0 -0
  507. /package/dist/web/assets/{systemd-to5p6N8I.js → systemd-BUr5HRtU.js} +0 -0
  508. /package/dist/web/assets/{table-Bbc783ko.js → table-FLU8ei8b.js} +0 -0
  509. /package/dist/web/assets/{talonscript-DoTcU8wm.js → talonscript-BNBQV5YJ.js} +0 -0
  510. /package/dist/web/assets/{tasl-cNZvUs95.js → tasl-BETjpSyu.js} +0 -0
  511. /package/dist/web/assets/{tcl-mZE8sZH8.js → tcl-Clp_AZiC.js} +0 -0
  512. /package/dist/web/assets/{terraform-CqHPpIfu.js → terraform-B0kZ0lim.js} +0 -0
  513. /package/dist/web/assets/{text-wrap-CBT4Gxtg.js → text-wrap-B05VGRa-.js} +0 -0
  514. /package/dist/web/assets/{tokyo-night-Tp2rTIZd.js → tokyo-night-oOJ0a7Dk.js} +0 -0
  515. /package/dist/web/assets/{toml-CU_vscgn.js → toml-DOPCSumy.js} +0 -0
  516. /package/dist/web/assets/{trash-2-Bk4yYlck.js → trash-2-CTXlTflF.js} +0 -0
  517. /package/dist/web/assets/{triangle-alert-B8EYecpe.js → triangle-alert-BRq0VAfd.js} +0 -0
  518. /package/dist/web/assets/{tsv-ik7iFB9D.js → tsv-D6qUGf84.js} +0 -0
  519. /package/dist/web/assets/{tsx-BMvvMKiv.js → tsx-B6qYhT6O.js} +0 -0
  520. /package/dist/web/assets/{turtle-DBqKCq9o.js → turtle-C0Rjzw73.js} +0 -0
  521. /package/dist/web/assets/{typescript-DXJDmMZZ.js → typescript-BiydShEu.js} +0 -0
  522. /package/dist/web/assets/{typespec-CBseCMtZ.js → typespec-DjmF6Aww.js} +0 -0
  523. /package/dist/web/assets/{typst-4oY25U9y.js → typst-CPuscfcL.js} +0 -0
  524. /package/dist/web/assets/{use-is-mobile-D1weanbj.js → use-is-mobile-b94q8RvF.js} +0 -0
  525. /package/dist/web/assets/{utils-BNRH507E.js → utils-C9OjCrou.js} +0 -0
  526. /package/dist/web/assets/{v-BXaZ_1oy.js → v-DE4vpLLQ.js} +0 -0
  527. /package/dist/web/assets/{vala-BImWJE7z.js → vala-CmUF2pS5.js} +0 -0
  528. /package/dist/web/assets/{vb-CLfj2_sy.js → vb-BvcRoX4b.js} +0 -0
  529. /package/dist/web/assets/{vendor-xterm-_yyu5n32.js → vendor-xterm-K8kpLxdb.js} +0 -0
  530. /package/dist/web/assets/{verilog-BWa8Ed2b.js → verilog-BGIzyH3R.js} +0 -0
  531. /package/dist/web/assets/{vesper-BGj1cg6m.js → vesper-CG7IrHQQ.js} +0 -0
  532. /package/dist/web/assets/{vhdl-mByK7mlx.js → vhdl-DMSumomw.js} +0 -0
  533. /package/dist/web/assets/{viml-CugmlW5g.js → viml-Drt7AEmU.js} +0 -0
  534. /package/dist/web/assets/{vitesse-black-vPdpy9TL.js → vitesse-black-DmsjfN0b.js} +0 -0
  535. /package/dist/web/assets/{vitesse-dark-BuQK3dUh.js → vitesse-dark-Dl55_WeJ.js} +0 -0
  536. /package/dist/web/assets/{vitesse-light-B3nz1XL9.js → vitesse-light-Crbv9aGg.js} +0 -0
  537. /package/dist/web/assets/{vyper-DH_GTIHG.js → vyper-CB7psEJj.js} +0 -0
  538. /package/dist/web/assets/{wasm-DfVbVJlW.js → wasm-BY1tuM5m.js} +0 -0
  539. /package/dist/web/assets/{wasm-C-LF9GjX.js → wasm-Dck8KPgP.js} +0 -0
  540. /package/dist/web/assets/{wenyan-CzQkHyHx.js → wenyan-DhewQ68b.js} +0 -0
  541. /package/dist/web/assets/{wgsl-Du_M1DW9.js → wgsl-DlmiP456.js} +0 -0
  542. /package/dist/web/assets/{wikitext-BWN_w5S7.js → wikitext-cQCnqNgE.js} +0 -0
  543. /package/dist/web/assets/{wit-BR13v5HD.js → wit-S5MaCngB.js} +0 -0
  544. /package/dist/web/assets/{wolfram-BoXxp_Xl.js → wolfram-Bh8n_9zr.js} +0 -0
  545. /package/dist/web/assets/{x-nhriOX9o.js → x-YDu4m2Iq.js} +0 -0
  546. /package/dist/web/assets/{yaml-DpR_EF-d.js → yaml-BoK_17l9.js} +0 -0
  547. /package/dist/web/assets/{zenscript-C-EdUtUd.js → zenscript-DB3ZFwNJ.js} +0 -0
  548. /package/dist/web/assets/{zig-BD4eA5nU.js → zig-Bv1BWmfT.js} +0 -0
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Login session singleton behind the "log in to Cloudflare" popup.
3
+ *
4
+ * One process-per-machine at a time: a second `startLogin` call while one is
5
+ * live (`waiting`/`slow`) just returns the current snapshot instead of
6
+ * spawning a competing `cloudflared tunnel login`. Every terminal state
7
+ * (`success`/`timeout`/`cancelled`/`error`) drops the process ref, so the
8
+ * *next* call after a terminal state always starts a genuinely fresh process
9
+ * with a fresh URL — a killed session's URL is gone for good, there is no
10
+ * "cert appears later" path once the process is dead.
11
+ */
12
+ import { readOriginCertState } from "./cloudflared-cert.ts";
13
+ import { loginArgs } from "./named-tunnel-args.ts";
14
+ import { ensureCloudflared } from "../cloudflared.service.ts";
15
+ import { killProcessTree } from "../windows-process-tree.ts";
16
+ import { broadcastGlobalEvent } from "../../server/ws/global.ts";
17
+ import { verifyCertLive, pinsMatch, renameCertAside, pumpLoginStream } from "./cloudflared-login-helpers.ts";
18
+
19
+ export type LoginState = "idle" | "waiting" | "slow" | "success" | "timeout" | "cancelled" | "error";
20
+ export interface LoginSnapshot { state: LoginState; url: string | null; message: string | null }
21
+
22
+ export const LOGIN_SLOW_MS = 60_000;
23
+ export const LOGIN_TIMEOUT_MS = 300_000;
24
+ const CERT_POLL_MS = 2_000;
25
+
26
+ interface Session {
27
+ state: LoginState;
28
+ url: string | null;
29
+ message: string | null;
30
+ proc: ReturnType<typeof Bun.spawn> | null;
31
+ slowTimer: ReturnType<typeof setTimeout> | null;
32
+ killTimer: ReturnType<typeof setTimeout> | null;
33
+ certPollTimer: ReturnType<typeof setInterval> | null;
34
+ }
35
+
36
+ function freshSession(): Session {
37
+ return { state: "idle", url: null, message: null, proc: null, slowTimer: null, killTimer: null, certPollTimer: null };
38
+ }
39
+
40
+ let session: Session = freshSession();
41
+
42
+ export function getLoginSnapshot(): LoginSnapshot {
43
+ return { state: session.state, url: session.url, message: session.message };
44
+ }
45
+
46
+ function clearTimers(): void {
47
+ if (session.slowTimer) clearTimeout(session.slowTimer);
48
+ if (session.killTimer) clearTimeout(session.killTimer);
49
+ if (session.certPollTimer) clearInterval(session.certPollTimer);
50
+ session.slowTimer = null;
51
+ session.killTimer = null;
52
+ session.certPollTimer = null;
53
+ }
54
+
55
+ /** Move to a terminal state: clear timers, drop the process ref, broadcast. */
56
+ function setTerminal(state: LoginState, message: string | null): void {
57
+ clearTimers();
58
+ session.proc = null;
59
+ session.state = state;
60
+ session.message = message;
61
+ broadcastGlobalEvent({ type: "tunnel:login_state", state, message: message ?? undefined });
62
+ }
63
+
64
+ /** Wraps `pumpLoginStream` with this module's session-singleton hooks. */
65
+ function pumpStream(stream: ReadableStream<Uint8Array>, proc: ReturnType<typeof Bun.spawn>): Promise<void> {
66
+ return pumpLoginStream(stream, {
67
+ isSuperseded: () => session.proc !== proc,
68
+ hasUrl: () => session.url != null,
69
+ onUrl: (url) => {
70
+ session.url = url;
71
+ broadcastGlobalEvent({ type: "tunnel:login_url", url });
72
+ },
73
+ onSuccess: () => setTerminal("success", "logged in"),
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Start (or return the live) login session.
79
+ *
80
+ * The cert-present shortcut is intentionally re-verified on every call — not
81
+ * a bare `existsSync` — because a replaced or revoked cert must never
82
+ * silently pass as "already logged in".
83
+ */
84
+ export async function startLogin(opts: { relogin?: boolean } = {}): Promise<LoginSnapshot> {
85
+ if (session.state === "waiting" || session.state === "slow") {
86
+ return getLoginSnapshot();
87
+ }
88
+
89
+ const relogin = !!opts.relogin;
90
+ if (!relogin) {
91
+ const certState = readOriginCertState();
92
+ if (certState.kind === "parsed") {
93
+ const liveCheck = await verifyCertLive(certState.cert.apiToken);
94
+
95
+ // WHY: a network blip must never discard a working credential. Only an
96
+ // authoritative "Cloudflare said no" (invalid) or a confirmed pin
97
+ // mismatch earns a rename-aside below; "unreachable" means the check
98
+ // itself failed to run, so cert.pem is left untouched and the user
99
+ // gets a clear, retryable error instead of an unwanted fresh login.
100
+ if (liveCheck === "unreachable") {
101
+ setTerminal("error", "không kết nối được Cloudflare để kiểm tra đăng nhập — thử lại");
102
+ return getLoginSnapshot();
103
+ }
104
+
105
+ if (liveCheck === "valid" && pinsMatch(certState.cert)) {
106
+ session = freshSession();
107
+ session.state = "success";
108
+ session.message = "already logged in";
109
+ return getLoginSnapshot();
110
+ }
111
+
112
+ // liveCheck === "invalid" (Cloudflare authoritatively rejected the
113
+ // token), or valid but pinned to a different account/zone: this cert
114
+ // can never pass the shortcut again as-is — move it aside now instead
115
+ // of leaving a bad file to keep silently triggering the same
116
+ // fallthrough on every future login attempt.
117
+ renameCertAside();
118
+ }
119
+ } else {
120
+ // Explicit ?relogin=1 — the user deliberately pressed "Đăng nhập lại",
121
+ // so this renames unconditionally regardless of network reachability.
122
+ renameCertAside();
123
+ }
124
+
125
+ const bin = await ensureCloudflared();
126
+ const proc = Bun.spawn([bin, ...loginArgs()], { stdout: "pipe", stderr: "pipe" });
127
+ session = { state: "waiting", url: null, message: null, proc, slowTimer: null, killTimer: null, certPollTimer: null };
128
+
129
+ session.slowTimer = setTimeout(() => {
130
+ if (session.proc !== proc) return;
131
+ session.state = "slow";
132
+ broadcastGlobalEvent({ type: "tunnel:login_state", state: "slow" });
133
+ }, LOGIN_SLOW_MS);
134
+
135
+ session.killTimer = setTimeout(() => {
136
+ if (session.proc !== proc) return;
137
+ killProcessTree(proc.pid);
138
+ setTerminal("timeout", "login timed out after 5 minutes");
139
+ }, LOGIN_TIMEOUT_MS);
140
+
141
+ session.certPollTimer = setInterval(() => {
142
+ if (session.proc !== proc) return;
143
+ if (readOriginCertState().kind === "parsed") setTerminal("success", "logged in");
144
+ }, CERT_POLL_MS);
145
+
146
+ Promise.all([pumpStream(proc.stdout, proc), pumpStream(proc.stderr, proc)])
147
+ .then(async () => {
148
+ if (session.proc !== proc) return; // already terminal
149
+ const code = await proc.exited;
150
+ if (session.proc !== proc) return;
151
+ if (code === 0) {
152
+ setTerminal("success", "logged in");
153
+ } else {
154
+ setTerminal("error", `cloudflared exited with code ${code}`);
155
+ }
156
+ })
157
+ .catch(() => {});
158
+
159
+ return getLoginSnapshot();
160
+ }
161
+
162
+ /** Kill the live process immediately (if any) and mark the session cancelled. */
163
+ export function cancelLogin(): void {
164
+ if (session.proc) killProcessTree(session.proc.pid);
165
+ setTerminal("cancelled", "cancelled");
166
+ }
167
+
168
+ // Orphaned login process on server crash/restart would otherwise wait forever
169
+ // for a browser callback that lands nowhere.
170
+ process.on("exit", () => {
171
+ if (session.proc) {
172
+ try { killProcessTree(session.proc.pid); } catch {}
173
+ }
174
+ });
175
+
176
+ /**
177
+ * Aggregate for callers that need a single patchable seam (the HTTP routes) —
178
+ * route tests monkey-patch these properties directly rather than reaching for
179
+ * `mock.module`, which replaces the module for every importer process-wide and
180
+ * would poison the direct-function unit tests in this same file's test suite.
181
+ */
182
+ export const cloudflaredLoginService = { getLoginSnapshot, startLogin, cancelLogin };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Hostname shape rules for the named tunnel.
3
+ *
4
+ * Exactly one label above the zone, never the apex, never `www`. Two reasons,
5
+ * not just a rule to copy: `cloudflared route dns` never errors on a hostname
6
+ * outside the zone — it silently appends the zone instead (e.g. asking for
7
+ * `ppm-probe.ppm.sh` under zone `hienle.tech` creates `ppm-probe.ppm.sh.hienle.tech`),
8
+ * so PPM must refuse before calling it; and Cloudflare's free Universal SSL
9
+ * certificate only covers one level of subdomain, so a deeper label parses fine
10
+ * here but serves a TLS error to every visitor.
11
+ */
12
+
13
+ export type HostnameCheck = { ok: true } | { ok: false; reason: string };
14
+
15
+ const LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
16
+ const MAX_HOSTNAME_LENGTH = 253;
17
+
18
+ /** Default proposal shown to the user: `ppm.<zone>`. */
19
+ export function proposeHostname(zone: string): string {
20
+ return `ppm.${zone.trim().toLowerCase()}`;
21
+ }
22
+
23
+ /** Combine a user-typed prefix with the pinned zone. */
24
+ export function buildHostname(prefix: string, zone: string): string {
25
+ return `${prefix.trim().toLowerCase()}.${zone.trim().toLowerCase()}`;
26
+ }
27
+
28
+ export function validateHostname(hostname: string, zone: string): HostnameCheck {
29
+ const host = hostname.trim().toLowerCase();
30
+ const z = zone.trim().toLowerCase();
31
+ if (!host || !z) return { ok: false, reason: "hostname and zone are required" };
32
+ if (host.length > MAX_HOSTNAME_LENGTH) return { ok: false, reason: "hostname exceeds 253 characters" };
33
+
34
+ if (host === z) {
35
+ return { ok: false, reason: "hostname cannot be the zone apex — a PPM token must never rewrite the zone's own record" };
36
+ }
37
+ if (host === `www.${z}`) {
38
+ return { ok: false, reason: "www is reserved" };
39
+ }
40
+ if (!host.endsWith(`.${z}`)) {
41
+ return { ok: false, reason: `hostname must be a subdomain of ${z} — cloudflared silently mis-routes anything else` };
42
+ }
43
+
44
+ // Everything above the zone must be exactly one label — Cloudflare's free
45
+ // certificate only covers one level, and a deeper label serves a TLS error.
46
+ const prefix = host.slice(0, host.length - z.length - 1);
47
+ if (prefix.includes(".")) {
48
+ return { ok: false, reason: "hostname must be exactly one label above the zone" };
49
+ }
50
+
51
+ for (const label of host.split(".")) {
52
+ if (!LABEL.test(label)) {
53
+ return { ok: false, reason: `invalid DNS label: "${label}"` };
54
+ }
55
+ }
56
+
57
+ return { ok: true };
58
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pure parsers for `cloudflared tunnel login` stdout/stderr chunks.
3
+ *
4
+ * cloudflared prints the browser URL and progress lines on stderr, not
5
+ * stdout (verified 2026-09-05, cloudflared 2026.3.0) — callers must feed both
6
+ * streams through these functions, never stdout alone.
7
+ */
8
+
9
+ /** Primary shape: the real dash.cloudflare.com/argotunnel URL cloudflared prints today. */
10
+ const PRIMARY_URL = /https:\/\/dash\.cloudflare\.com\/argotunnel\?[^\s]+/;
11
+
12
+ /** Exact success line cloudflared prints on a successful login, exit code 0. */
13
+ const SUCCESS_LINE = /You have successfully logged in\./;
14
+
15
+ /**
16
+ * Extract the login URL from a stdout/stderr chunk (or accumulated buffer).
17
+ * Falls back to the first `https://` token on any line mentioning
18
+ * "argotunnel" so a cosmetic rename of the URL shape never leaves the flow
19
+ * stuck at `waiting` with no way for the user to open the browser page.
20
+ */
21
+ export function extractLoginUrl(text: string): string | null {
22
+ const primary = text.match(PRIMARY_URL);
23
+ if (primary) return primary[0];
24
+
25
+ for (const line of text.split(/\r?\n/)) {
26
+ if (!/argotunnel/i.test(line)) continue;
27
+ const fallback = line.match(/https:\/\/[^\s]+/);
28
+ if (fallback) return fallback[0];
29
+ }
30
+ return null;
31
+ }
32
+
33
+ /** True once cloudflared has printed its success line. */
34
+ export function isLoginSuccess(text: string): boolean {
35
+ return SUCCESS_LINE.test(text);
36
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * cloudflared argv builders for the named-tunnel flow, plus the two artifact
3
+ * files they depend on. Every builder here guarantees its own artifacts (mirrors
4
+ * `cloudflared.service.ts`'s `getQuickTunnelArgs` → `ensureQuickTunnelConfig`
5
+ * pattern) rather than assuming an earlier phase already created them.
6
+ *
7
+ * The run token never appears in argv, ever — it is written to a 0600 file and
8
+ * passed via `--token-file`, so it can't leak through `ppm status`, a process
9
+ * list, or a crash dump that captures cmdlines.
10
+ */
11
+ import { resolve } from "node:path";
12
+ import { hostname as osHostname } from "node:os";
13
+ import { existsSync, mkdirSync, writeFileSync, chmodSync } from "node:fs";
14
+ import { getPpmDir } from "../ppm-dir.ts";
15
+ import { getOriginCertPath } from "./cloudflared-cert.ts";
16
+
17
+ const namedTunnelConfigPath = () => resolve(getPpmDir(), "cloudflared-named.yml");
18
+ const namedTunnelTokenPath = () => resolve(getPpmDir(), "named-tunnel.token");
19
+ const isWindows = process.platform === "win32";
20
+
21
+ /**
22
+ * Ensure `getPpmDir()` exists without letting a pre-existing directory throw
23
+ * EEXIST (Windows read-only-attribute folders — Desktop/Documents/Downloads —
24
+ * have thrown on a recursive mkdir here before even though the dir was already
25
+ * present and usable).
26
+ */
27
+ function ensurePpmDir(): void {
28
+ if (existsSync(getPpmDir())) return;
29
+ try {
30
+ mkdirSync(getPpmDir(), { recursive: true, mode: 0o700 });
31
+ } catch (e: any) {
32
+ if (e?.code !== "EEXIST") throw e;
33
+ }
34
+ }
35
+
36
+ /** Best-effort chmod — POSIX enforces the mode; Windows has no equivalent bit. */
37
+ function chmodBestEffort(path: string, mode: number): void {
38
+ if (isWindows) return;
39
+ try { chmodSync(path, mode); } catch {}
40
+ }
41
+
42
+ /**
43
+ * Create `~/.ppm/cloudflared-named.yml` if absent; returns its path.
44
+ * A comment-only file still parses but logs `ERR Configuration file ... was
45
+ * empty` on every command (harmless noise, verified live); a *missing* file
46
+ * exits 1. `no-autoupdate: true` is a real, valid key so the file is never
47
+ * comment-only.
48
+ */
49
+ export function ensureNamedTunnelConfig(): string {
50
+ const path = namedTunnelConfigPath();
51
+ if (!existsSync(path)) {
52
+ ensurePpmDir();
53
+ writeFileSync(path, "no-autoupdate: true\n", { mode: 0o600 });
54
+ }
55
+ chmodBestEffort(path, 0o600);
56
+ return path;
57
+ }
58
+
59
+ /** Write the run token to a 0600 file; returns its path. Overwritten on every call. */
60
+ export function writeNamedTunnelToken(token: string): string {
61
+ ensurePpmDir();
62
+ const path = namedTunnelTokenPath();
63
+ writeFileSync(path, token, { mode: 0o600 });
64
+ chmodBestEffort(path, 0o600);
65
+ return path;
66
+ }
67
+
68
+ /** `tunnel login` has no cert yet, so no `--origincert` — that flag would point nowhere. */
69
+ export function loginArgs(): string[] {
70
+ return ["tunnel", "login"];
71
+ }
72
+
73
+ /** Global flags (`--origincert`/`--config`) always precede the subcommand. */
74
+ function managementPrefix(): string[] {
75
+ return ["--origincert", getOriginCertPath(), "--config", ensureNamedTunnelConfig()];
76
+ }
77
+
78
+ export function createTunnelArgs(name: string): string[] {
79
+ return [...managementPrefix(), "tunnel", "create", name];
80
+ }
81
+
82
+ export function tunnelTokenArgs(name: string): string[] {
83
+ return [...managementPrefix(), "tunnel", "token", name];
84
+ }
85
+
86
+ /**
87
+ * `--overwrite-dns` only when the caller has confirmed this is our own tunnel's
88
+ * UUID being re-pointed (e.g. after a reset) — never passed blindly, since it
89
+ * silently steals a CNAME that might belong to something else.
90
+ */
91
+ export function routeDnsArgs(name: string, hostname: string, overwrite: boolean): string[] {
92
+ const flags = overwrite ? ["--overwrite-dns"] : [];
93
+ return [...managementPrefix(), "tunnel", "route", "dns", ...flags, name, hostname];
94
+ }
95
+
96
+ /**
97
+ * Argv for the long-running named-tunnel process. No `--token` literal ever
98
+ * appears here — only a path to a 0600 file cloudflared reads itself.
99
+ */
100
+ export function namedRunArgs(token: string, port: number): string[] {
101
+ const cfg = ensureNamedTunnelConfig();
102
+ const tokenPath = writeNamedTunnelToken(token);
103
+ return ["--config", cfg, "tunnel", "run", "--token-file", tokenPath, "--url", `http://127.0.0.1:${port}`];
104
+ }
105
+
106
+ /** Stable, DNS-safe tunnel name derived from this machine's hostname. */
107
+ export function tunnelNameForHost(): string {
108
+ const sanitized = osHostname().toLowerCase().replace(/[^a-z0-9-]/g, "-");
109
+ return `ppm-${sanitized}`.slice(0, 32);
110
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Runtime resolver: turns the persisted `tunnel` config row into the shape the
3
+ * supervisor and UI actually consume. This is where "incomplete" data degrades
4
+ * to quick — storage (`sanitizeConfig`) never makes that judgment itself, so
5
+ * `/disable`'s documented "keep the config so Retry works" contract survives a
6
+ * config round-trip.
7
+ */
8
+
9
+ export type TunnelMode = "quick" | "named";
10
+
11
+ export interface ResolvedTunnelConfig {
12
+ mode: TunnelMode;
13
+ hostname: string | null;
14
+ tunnelName: string | null;
15
+ token: string | null;
16
+ zoneID: string | null;
17
+ accountID: string | null;
18
+ dismissed: boolean;
19
+ }
20
+
21
+ const QUICK: Omit<ResolvedTunnelConfig, "dismissed"> = {
22
+ mode: "quick", hostname: null, tunnelName: null, token: null, zoneID: null, accountID: null,
23
+ };
24
+
25
+ function nonEmptyString(v: unknown): v is string {
26
+ return typeof v === "string" && v.length > 0;
27
+ }
28
+
29
+ export function resolveTunnelConfig(raw: unknown): ResolvedTunnelConfig {
30
+ let obj: Record<string, unknown> | null = null;
31
+ if (typeof raw === "string") {
32
+ try { obj = JSON.parse(raw); } catch { obj = null; }
33
+ } else if (raw && typeof raw === "object") {
34
+ obj = raw as Record<string, unknown>;
35
+ }
36
+
37
+ const dismissed = obj != null && typeof obj.dismissed === "boolean" ? obj.dismissed : false;
38
+
39
+ // Named mode requires BOTH the stored mode flag AND all four identity fields —
40
+ // checking fields alone would resurrect a tunnel the user explicitly disabled,
41
+ // since /disable intentionally keeps namedTunnel* fields around for Retry.
42
+ const named = obj != null && obj.mode === "named" &&
43
+ nonEmptyString(obj.namedTunnelToken) &&
44
+ nonEmptyString(obj.namedTunnelHostname) &&
45
+ nonEmptyString(obj.zoneID) &&
46
+ nonEmptyString(obj.accountID);
47
+
48
+ if (!named || obj == null) {
49
+ return { ...QUICK, dismissed };
50
+ }
51
+
52
+ return {
53
+ mode: "named",
54
+ hostname: obj.namedTunnelHostname as string,
55
+ tunnelName: nonEmptyString(obj.namedTunnelName) ? obj.namedTunnelName : null,
56
+ token: obj.namedTunnelToken as string,
57
+ zoneID: obj.zoneID as string,
58
+ accountID: obj.accountID as string,
59
+ dismissed,
60
+ };
61
+ }
62
+
63
+ /** `abcdef...` — first 6 chars + ellipsis; never the full secret. */
64
+ export function maskToken(token: string | null): string | null {
65
+ if (token == null) return null;
66
+ return `${token.slice(0, 6)}...`;
67
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Pure decision function for the named-tunnel probe's "restart once, then warn
3
+ * and stop" state machine. Kept separate from `supervisor.ts` (which owns the
4
+ * actual kill/respawn/status-write side effects) so the transition logic is
5
+ * unit-testable without spawning a real cloudflared process or timers.
6
+ *
7
+ * The bug this exists to prevent: resetting `restartAttempted` anywhere other
8
+ * than a confirmed-healthy observation lets a dark hostname (e.g. the CNAME
9
+ * deleted in the dashboard) restart the connector every threshold window
10
+ * forever, because the RESTART itself always "succeeds" (cloudflared happily
11
+ * reconnects to Cloudflare's edge) even though the DNS route it needs is gone —
12
+ * a spawn success is not proof the hostname is reachable, only the probe's own
13
+ * fetch against the public URL is.
14
+ */
15
+
16
+ export interface NamedProbeState {
17
+ /** Consecutive unhealthy probe cycles observed since the last reset. */
18
+ failCount: number;
19
+ /** Whether the one allowed restart-and-hope has already been used since the
20
+ * last confirmed-healthy observation. */
21
+ restartAttempted: boolean;
22
+ }
23
+
24
+ export type NamedProbeAction =
25
+ | { type: "healthy" }
26
+ /** Counting a failure. `warnEarly` marks the tick that should surface a
27
+ * soft "checking the connection" notice without touching the connector. */
28
+ | { type: "watch"; warnEarly: boolean }
29
+ | { type: "restart-once" }
30
+ | { type: "warn-and-stop" };
31
+
32
+ export interface NamedProbeDecision {
33
+ action: NamedProbeAction;
34
+ nextState: NamedProbeState;
35
+ }
36
+
37
+ /**
38
+ * Is the thing answering the public hostname *our* server? `publicId` is the
39
+ * `instanceId` the hostname returned, `localId` the one our loopback server
40
+ * returned; either may be missing.
41
+ *
42
+ * A deleted CNAME does not make the hostname go dark — it falls back to the
43
+ * zone's wildcard record and some unrelated host answers 200 with a body that
44
+ * has no `instanceId`. If we know our own identity and the public answer lacks
45
+ * one (or differs), the hostname is not ours. Only when our own server has no
46
+ * identity (a build that predates `instanceId`) do we accept bare reachability.
47
+ */
48
+ export function publicHostnameIsOurs(publicId: unknown, localId: unknown): boolean {
49
+ if (typeof localId !== "string") return true;
50
+ return typeof publicId === "string" && publicId === localId;
51
+ }
52
+
53
+ /**
54
+ * Decide the next action for one probe tick.
55
+ *
56
+ * - `healthy` → both counters reset to a clean slate (the only place
57
+ * `restartAttempted` ever goes back to `false`).
58
+ * - unhealthy below `threshold` → `watch`. Acting on a dark hostname is
59
+ * deliberately slow (a flaky minute must not kill a working connector), but
60
+ * *saying nothing* for that long is a different decision: `watch` carries
61
+ * `warnEarly` on the tick that crosses `earlyWarnAt`, so the UI can show
62
+ * "checking the connection" while the restart budget is still untouched.
63
+ * - unhealthy at/above `threshold`, first time → `restart-once` (kill +
64
+ * respawn the connector; arms `restartAttempted` so this never repeats
65
+ * until a healthy observation clears it).
66
+ * - unhealthy at/above `threshold`, restart already attempted → `warn-and-stop`
67
+ * (surface the warning; never kill again — the pinned URL stays put).
68
+ */
69
+ export function decideNamedProbeAction(
70
+ healthy: boolean,
71
+ state: NamedProbeState,
72
+ threshold: number,
73
+ earlyWarnAt = 2,
74
+ ): NamedProbeDecision {
75
+ if (healthy) {
76
+ return { action: { type: "healthy" }, nextState: { failCount: 0, restartAttempted: false } };
77
+ }
78
+
79
+ const failCount = state.failCount + 1;
80
+ if (failCount < threshold) {
81
+ // Only on the crossing tick: re-writing the same warning every 30s would
82
+ // rewrite status.json forever for no new information.
83
+ const warnEarly = failCount === earlyWarnAt;
84
+ return {
85
+ action: { type: "watch", warnEarly },
86
+ nextState: { failCount, restartAttempted: state.restartAttempted },
87
+ };
88
+ }
89
+
90
+ if (!state.restartAttempted) {
91
+ return { action: { type: "restart-once" }, nextState: { failCount: 0, restartAttempted: true } };
92
+ }
93
+
94
+ return { action: { type: "warn-and-stop" }, nextState: { failCount: 0, restartAttempted: true } };
95
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Offset-anchored readiness reader for cloudflared's stderr log file.
3
+ *
4
+ * A quick or named tunnel is only "ready" once cloudflared writes a specific
5
+ * line to its log. The caller truncates that log before every spawn, but the
6
+ * truncation is best-effort and silently fails on Windows while a previous
7
+ * detached cloudflared process still holds the file open — so a scan of the
8
+ * WHOLE file can match a line left over from a dead connector and declare it
9
+ * "ready" in well under 200ms. Anchoring every read to a byte offset captured
10
+ * right after the truncate attempt makes that impossible: only bytes appended
11
+ * by THIS process generation are ever considered.
12
+ */
13
+ import { existsSync, readFileSync } from "node:fs";
14
+
15
+ export interface WaitForLogLineOpts {
16
+ /** Only bytes at or after this offset are scanned — excludes any content
17
+ * left behind by a previous process generation. */
18
+ fromByteOffset: number;
19
+ timeoutMs: number;
20
+ /** Poll-time check for whether the watched process has already exited. */
21
+ getExitCode: () => number | null;
22
+ pollIntervalMs?: number;
23
+ }
24
+
25
+ /**
26
+ * Poll `path` until `regex` matches within the bytes appended after
27
+ * `fromByteOffset`, the watched process exits, or `timeoutMs` elapses.
28
+ *
29
+ * Reads the file as a Buffer and slices by byte offset (not string index) so
30
+ * a multi-byte UTF-8 character straddling the offset is never corrupted —
31
+ * `toString("utf8")` re-decodes the whole remaining tail on every poll, so a
32
+ * boundary can only delay a match by one poll interval, never corrupt it.
33
+ */
34
+ export async function waitForLogLine(
35
+ path: string,
36
+ regex: RegExp,
37
+ opts: WaitForLogLineOpts,
38
+ ): Promise<string> {
39
+ const deadline = Date.now() + opts.timeoutMs;
40
+ const pollMs = opts.pollIntervalMs ?? 200;
41
+
42
+ while (Date.now() < deadline) {
43
+ if (existsSync(path)) {
44
+ try {
45
+ const buf = readFileSync(path);
46
+ const tail = buf.subarray(opts.fromByteOffset).toString("utf8");
47
+ const match = tail.match(regex);
48
+ if (match) return match[0];
49
+ } catch {
50
+ // Transient read race (file replaced mid-poll) — retry next tick.
51
+ }
52
+ }
53
+ if (opts.getExitCode() !== null) {
54
+ throw new Error(`cloudflared exited without matching ${regex}`);
55
+ }
56
+ await Bun.sleep(pollMs);
57
+ }
58
+ throw new Error(`readiness timeout (${opts.timeoutMs}ms)`);
59
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Runtime seam between "what's persisted" (named-tunnel-config.ts) and "what
3
+ * to actually spawn" (cloudflared.service.ts / named-tunnel-args.ts). Kept out
4
+ * of supervisor.ts (already large) and out of phase 1b's config/argv modules
5
+ * so neither grows to own the other's concern.
6
+ */
7
+ import { getConfigValue } from "../db.service.ts";
8
+ import { resolveTunnelConfig, type ResolvedTunnelConfig, type TunnelMode } from "./named-tunnel-config.ts";
9
+ import { getQuickTunnelArgs } from "../cloudflared.service.ts";
10
+ import { namedRunArgs } from "./named-tunnel-args.ts";
11
+
12
+ /**
13
+ * Fresh (non-cached) read of the persisted tunnel config.
14
+ *
15
+ * The supervisor runs in its own process with its own `configService`
16
+ * singleton, which never observes writes the server process makes to
17
+ * SQLite — so every caller here must go through `getConfigValue` (a raw DB
18
+ * read), never `configService.get`, or the supervisor would spawn/adopt
19
+ * against a stale mode forever.
20
+ */
21
+ export async function readTunnelConfigFresh(): Promise<ResolvedTunnelConfig> {
22
+ return resolveTunnelConfig(getConfigValue("tunnel"));
23
+ }
24
+
25
+ export interface TunnelSpawnPlan {
26
+ mode: TunnelMode;
27
+ args: string[];
28
+ }
29
+
30
+ /**
31
+ * Pick the argv for the next tunnel spawn attempt from a resolved config.
32
+ * When `config.mode` is not `"named"` (or the token is somehow absent —
33
+ * `resolveTunnelConfig` already guarantees this can't happen for a config row
34
+ * with `mode: "named"`, this is belt-and-suspenders), the output is exactly
35
+ * `getQuickTunnelArgs(port)` — byte-identical to today's quick-only argv.
36
+ */
37
+ export function chooseTunnelSpawn(config: ResolvedTunnelConfig, port: number): TunnelSpawnPlan {
38
+ if (config.mode === "named" && config.token) {
39
+ return { mode: "named", args: namedRunArgs(config.token, port) };
40
+ }
41
+ return { mode: "quick", args: getQuickTunnelArgs(port) };
42
+ }