@hienlh/ppm 0.20.8 → 0.20.10
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.
- package/CHANGELOG.md +15 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/accounts-settings-section-DC2A6FhQ.js +1 -0
- package/dist/web/assets/{ai-resource-editor-CMQfhxXp.js → ai-resource-editor-DDhuy_AR.js} +1 -1
- package/dist/web/assets/ai-settings-section-J9Rbs26g.js +1 -0
- package/dist/web/assets/{ai-settings-section-M07DCjAI.js → ai-settings-section-OrhLykA2.js} +1 -1
- package/dist/web/assets/{angular-html-BtJLNcMw.js → angular-html-D4qjt-75.js} +1 -1
- package/dist/web/assets/{angular-ts-CQiu5F_W.js → angular-ts-DvLn04T8.js} +1 -1
- package/dist/web/assets/{api-client-DwXlVfXP.js → api-client-DCzgxFNY.js} +1 -1
- package/dist/web/assets/api-client-PMwZQ4iC.js +1 -0
- package/dist/web/assets/{api-settings-BQIwZoLm.js → api-settings-t5xLrBkQ.js} +1 -1
- package/dist/web/assets/{api-themes-CmJZLEY1.js → api-themes-CJmyQeMk.js} +1 -1
- package/dist/web/assets/{apl-CKZvgs-w.js → apl-DQOoPzqd.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-BBlJtEm5.js → appearance-settings-section-BQ1dH29t.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-D55g5j-p.js +1 -0
- package/dist/web/assets/arrow-left-y44wEZrw.js +1 -0
- package/dist/web/assets/arrow-right-SQ8KJIvE.js +1 -0
- package/dist/web/assets/{astro-D0b8ssLD.js → astro-C2zFJ1Er.js} +1 -1
- package/dist/web/assets/{audio-preview-DPMXOZ55.js → audio-preview-CAVqEwDi.js} +1 -1
- package/dist/web/assets/{blade-DOIpINLw.js → blade-CBD8sEa1.js} +1 -1
- package/dist/web/assets/{bot-D3-n2i31.js → bot-BNu2OM_S.js} +1 -1
- package/dist/web/assets/{brain-CuAQMSBE.js → brain-BsjvCk4k.js} +1 -1
- package/dist/web/assets/{bsl-CJ7_JlQ8.js → bsl-bs2JpeTQ.js} +1 -1
- package/dist/web/assets/{button-zgoXa9r7.js → button-DHI8IY_N.js} +1 -1
- package/dist/web/assets/{cairo-5CpV2T1P.js → cairo-DT2g4i_6.js} +1 -1
- package/dist/web/assets/{calendar-clock-CDP7AVjA.js → calendar-clock-Zydwzvp7.js} +1 -1
- package/dist/web/assets/chat-tab-D2le8LxY.js +15 -0
- package/dist/web/assets/check-DczxQ5UD.js +1 -0
- package/dist/web/assets/{chevron-down-B9puixxZ.js → chevron-down-BCt_kn-R.js} +1 -1
- package/dist/web/assets/chevron-right-Lt-y9H_e.js +1 -0
- package/dist/web/assets/{chevron-up-BPAINgoK.js → chevron-up-CRl1AF4q.js} +1 -1
- package/dist/web/assets/circle-D4vp8Yky.js +1 -0
- package/dist/web/assets/circle-question-mark-BGbDcz7E.js +1 -0
- package/dist/web/assets/clock-BBIE-uf3.js +1 -0
- package/dist/web/assets/{cobol-BreMVrtc.js → cobol-B2rp6LA1.js} +1 -1
- package/dist/web/assets/code-CvgQViOi.js +1 -0
- package/dist/web/assets/code-editor-D-8oqMBM.js +7 -0
- package/dist/web/assets/codex-daily-guard-h4ZpEemV.js +1 -0
- package/dist/web/assets/{coffee-D7DoKh5b.js → coffee-D5ShQC08.js} +1 -1
- package/dist/web/assets/{conflict-editor-C-Nv8YYj.js → conflict-editor-B0Mj8pYR.js} +1 -1
- package/dist/web/assets/{context-menu-DM9CgxGh.js → context-menu-I07Ld1Yr.js} +1 -1
- package/dist/web/assets/{copy-CXuIH4VC.js → copy-Bqr2VxN5.js} +1 -1
- package/dist/web/assets/{cpp-BnWeWAoE.js → cpp-BmKOH-E0.js} +1 -1
- package/dist/web/assets/{createLucideIcon-D6fVXe3s.js → createLucideIcon-CLMdC3Kl.js} +1 -1
- package/dist/web/assets/{crystal-D2pJbFUn.js → crystal-B7u_ZTpu.js} +1 -1
- package/dist/web/assets/{csv-preview-ou3KFzIH.js → csv-preview-Ds2oCW6U.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-dnWnblYo.js → data-grid-overlay-editor-DJWgclot.js} +1 -1
- package/dist/web/assets/{data-grid-types-BfGeMDy0.js → data-grid-types-Uu77aFvI.js} +1 -1
- package/dist/web/assets/{database-Dz0W7OH7.js → database-BHxcoKlT.js} +1 -1
- package/dist/web/assets/{database-viewer-Ckqg_-SS.js → database-viewer-CiwQ6spt.js} +1 -1
- package/dist/web/assets/{diff-viewer-CMzFnBCD.js → diff-viewer-BomFSnpH.js} +1 -1
- package/dist/web/assets/{dist-CWMPvPem.js → dist-BTdRgQig.js} +1 -1
- package/dist/web/assets/{docx-preview-B7Aospmh.js → docx-preview-PsyMM8SN.js} +1 -1
- package/dist/web/assets/{download-D70Q4Ba6.js → download-hiDsGuxx.js} +1 -1
- package/dist/web/assets/{edge-aqGMtbY3.js → edge--MpXROh5.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-BvgPvuhH.js → edit-diff-preview-ESj6hMoD.js} +3 -3
- package/dist/web/assets/{elixir-CsYMBLc5.js → elixir-DL8mOfzH.js} +1 -1
- package/dist/web/assets/{elm-BU8C2gFp.js → elm-eVlzIFEZ.js} +1 -1
- package/dist/web/assets/{erb-Z_E49ab8.js → erb-BgvaH9l0.js} +1 -1
- package/dist/web/assets/{erlang-BRqOjXH9.js → erlang-CEf8Sfhs.js} +1 -1
- package/dist/web/assets/{esm-BHyWbWKE.js → esm-C5xqy163.js} +2 -2
- package/dist/web/assets/{explorer-body-CVx4qaIF.js → explorer-body-CExMoOiW.js} +2 -2
- package/dist/web/assets/explorer-window-content-Hy9kB6Q7.js +1 -0
- package/dist/web/assets/{extension-manager-section-CtcpVMWs.js → extension-manager-section-DMb56aut.js} +1 -1
- package/dist/web/assets/{extension-webview-DZ_QRZSM.js → extension-webview-CQB0Uvdo.js} +1 -1
- package/dist/web/assets/{eye-dfZn7evX.js → eye-DYS5JBeU.js} +1 -1
- package/dist/web/assets/{eye-off-CmtfyRUD.js → eye-off-YWCuob9F.js} +1 -1
- package/dist/web/assets/{file-exclamation-point-D5K2aaLi.js → file-exclamation-point-DpdJqj9-.js} +1 -1
- package/dist/web/assets/{files-settings-section-D7v-6nTa.js → files-settings-section-CVHPO3N9.js} +1 -1
- package/dist/web/assets/{flask-conical-Dix4qNDj.js → flask-conical-BUxpYe-g.js} +1 -1
- package/dist/web/assets/{folder-symlink-BavsIzoj.js → folder-symlink-DKTEop0L.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-CWbxmDGR.js → fortran-fixed-form-yAUsSjab.js} +1 -1
- package/dist/web/assets/{fsharp-DKMYbq6I.js → fsharp-BEWvY_ZR.js} +1 -1
- package/dist/web/assets/{gdresource-B3yFau4V.js → gdresource-CYZFZ057.js} +1 -1
- package/dist/web/assets/{general-settings-section-BW_h8pdA.js → general-settings-section-CWYR9F5y.js} +1 -1
- package/dist/web/assets/{git-commit-BW0p3Ekk.js → git-commit-DedchUJ6.js} +1 -1
- package/dist/web/assets/{git-log-panel-BQZkJDu0.js → git-log-panel-DYLF-XSq.js} +1 -1
- package/dist/web/assets/{git-rebase-DrvmQCS7.js → git-rebase-DPvHNzQr.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-At-P8hlA.js +1 -0
- package/dist/web/assets/{glide-data-grid-JKEslqGe.js → glide-data-grid-BxFN-Z6F.js} +8 -8
- package/dist/web/assets/{glimmer-js-BY1XApJJ.js → glimmer-js-B4hPYBMX.js} +1 -1
- package/dist/web/assets/{glimmer-ts-DPZtxF8N.js → glimmer-ts-C0WfcQnO.js} +1 -1
- package/dist/web/assets/{glsl-DZ8G_Hvf.js → glsl-DHW88hTv.js} +1 -1
- package/dist/web/assets/{graphql-Ck06uCZy.js → graphql-CEvXbo6e.js} +1 -1
- package/dist/web/assets/group-chat-tab-Ch6OGMKj.js +1 -0
- package/dist/web/assets/{hack-pLogDwAs.js → hack-lKfhn1vw.js} +1 -1
- package/dist/web/assets/{haml-CBqeCQ2A.js → haml-AjKlANaB.js} +1 -1
- package/dist/web/assets/{hand-CIPALZsE.js → hand-BomFk_WG.js} +1 -1
- package/dist/web/assets/{handlebars-B66JmVtp.js → handlebars-B8fZzj2G.js} +1 -1
- package/dist/web/assets/{html-Dk4wmfwC.js → html-H_S3FJMj.js} +1 -1
- package/dist/web/assets/{html-derivative-CJWqfN51.js → html-derivative-VZmoMdQD.js} +1 -1
- package/dist/web/assets/{http-CexhotTh.js → http-DBxROFKc.js} +1 -1
- package/dist/web/assets/{hurl-BScKFk3Z.js → hurl-Hf7XWQHN.js} +1 -1
- package/dist/web/assets/{hxml-DAle7vtu.js → hxml-BRhRKwSo.js} +1 -1
- package/dist/web/assets/{image-preview-V5SglTWk.js → image-preview-DjT5Xb2L.js} +1 -1
- package/dist/web/assets/index-BfDJvjH9.js +52 -0
- package/dist/web/assets/index-Di9nVG3y.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-btSsuixb.js +1 -0
- package/dist/web/assets/{jinja-yHpyD80t.js → jinja-D3jMH0jG.js} +1 -1
- package/dist/web/assets/{jira-watcher-section-VyzVbAnw.js → jira-watcher-section-DZvWeUAW.js} +1 -1
- package/dist/web/assets/{jison-BY6WLJVu.js → jison-CZtpkLiY.js} +1 -1
- package/dist/web/assets/{julia-Dd_iYQDT.js → julia-DwFjOpos.js} +1 -1
- package/dist/web/assets/{just-BTuUKpxF.js → just-BEfj8dHN.js} +1 -1
- package/dist/web/assets/{key-round-oIll4vo-.js → key-round-BhkPzOjZ.js} +1 -1
- package/dist/web/assets/keybindings-store-CNqxSJxv.js +1 -0
- package/dist/web/assets/{keyboard-BLwfiRkT.js → keyboard-IQMXPNIE.js} +1 -1
- package/dist/web/assets/{keyboard-shortcuts-section-DOJi75mV.js → keyboard-shortcuts-section-DAFNxA49.js} +1 -1
- package/dist/web/assets/{latex-Dt3OUlMZ.js → latex-C6Rb_zGG.js} +1 -1
- package/dist/web/assets/{lib-BAsciSLw.js → lib-CFTK00ux.js} +1 -1
- package/dist/web/assets/{liquid-BxPJU2ix.js → liquid-DTVs9cD3.js} +1 -1
- package/dist/web/assets/loader-circle-Bm-Dq_wA.js +1 -0
- package/dist/web/assets/{lua-DEGIvn7d.js → lua-C1zfiqhG.js} +1 -1
- package/dist/web/assets/markdown-renderer-BSiaxWjE.js +1 -0
- package/dist/web/assets/markdown-renderer-CMNnYOPG.js +3 -0
- package/dist/web/assets/{marko-BDxwBJur.js → marko-_hrXozl2.js} +1 -1
- package/dist/web/assets/{mdc-B8aXPTg7.js → mdc-AX9XWu8K.js} +1 -1
- package/dist/web/assets/{media-url-TYMlO0M5.js → media-url-D43IHXnP.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-Ch1e_JBq.js → mobile-bottom-sheet-GSto0_0m.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-BMg4Q9Bm.js +1 -0
- package/dist/web/assets/{monitor-CG69bSMW.js → monitor-DEoVYSPl.js} +1 -1
- package/dist/web/assets/{nextflow-DBVZnnT_.js → nextflow-xJ5dkaQ2.js} +1 -1
- package/dist/web/assets/{nginx-Crpyd-Do.js → nginx-BfbjvmIV.js} +1 -1
- package/dist/web/assets/{nim-BSqTBYDj.js → nim-KrUnNSwZ.js} +1 -1
- package/dist/web/assets/notification-store-CRlOB9I9.js +1 -0
- package/dist/web/assets/{notifications-settings-section-CeRvkXOM.js → notifications-settings-section-Cci_OOHx.js} +1 -1
- package/dist/web/assets/{number-overlay-editor-DldrUNs4.js → number-overlay-editor-CGZ1ObrN.js} +1 -1
- package/dist/web/assets/{overview-panel-DA0QB1-5.js → overview-panel-Ni1Wqr3E.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-B20_sIFd.js +1 -0
- package/dist/web/assets/{panel-store-D42k25jy.js → panel-store-BcgZsiXU.js} +1 -1
- package/dist/web/assets/{pdf-preview-Cq33D5ej.js → pdf-preview-C28MEOND.js} +1 -1
- package/dist/web/assets/{perl-BU0kbB-K.js → perl-DAexWIeo.js} +1 -1
- package/dist/web/assets/{php-D9n1ikHN.js → php-DXc7GdU9.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-nzfJdXCC.js +1 -0
- package/dist/web/assets/portal-container-context-DO44JpXO.js +1 -0
- package/dist/web/assets/{postgres-viewer-C__Z0C0s.js → postgres-viewer-DmbVhmJ8.js} +3 -3
- package/dist/web/assets/power-BMdSjXYW.js +1 -0
- package/dist/web/assets/{ppmbot-settings-section-Cma4VU7p.js → ppmbot-settings-section-Cef8FSS6.js} +1 -1
- package/dist/web/assets/{process-table-DH_HXtGc.js → process-table-BfixzY3r.js} +1 -1
- package/dist/web/assets/{project-store-C83MMnlt.js → project-store-DCDLF-x3.js} +1 -1
- package/dist/web/assets/{proxy-settings-section-xrTsFlTF.js → proxy-settings-section-BlLWfinY.js} +1 -1
- package/dist/web/assets/{pug-BOpaczDr.js → pug-CHds8FDl.js} +1 -1
- package/dist/web/assets/{qml-B-cQXhrg.js → qml-DBt6oNnU.js} +1 -1
- package/dist/web/assets/{query-audit-section-Drk97gb8.js → query-audit-section-qnSL15x8.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-CS4sHKD5.js +1 -0
- package/dist/web/assets/{razor-DFB0pNCh.js → razor-DVDe2z8Z.js} +1 -1
- package/dist/web/assets/{react-DqIU0LFM.js → react-Bf5xrFLG.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CG6h4OL2.js +2 -0
- package/dist/web/assets/{remote-desktop-mobile-view-Gk8UCVIx.js → remote-desktop-mobile-view-D__2WLV5.js} +1 -1
- package/dist/web/assets/{remote-desktop-readiness-gate-6reSZvad.js → remote-desktop-readiness-gate-rL48PCUH.js} +1 -1
- package/dist/web/assets/{remote-desktop-window-content-BW2KqONI.js → remote-desktop-window-content-DlGUCbxq.js} +1 -1
- package/dist/web/assets/{rst-DAXedsgm.js → rst-s3rP0H8p.js} +1 -1
- package/dist/web/assets/{ruby-BCO4polC.js → ruby-sRcfbjlr.js} +1 -1
- package/dist/web/assets/{run-in-terminal-DoTOtgQS.js → run-in-terminal-Yt_lq4T9.js} +1 -1
- package/dist/web/assets/{sas-DfB5dcFC.js → sas-CuyZeQJw.js} +1 -1
- package/dist/web/assets/{save-B1y4KIK9.js → save-CIuK3QI4.js} +1 -1
- package/dist/web/assets/{schedules-settings-section-DcKEz-S7.js → schedules-settings-section-BUqf3KTd.js} +1 -1
- package/dist/web/assets/{scss-BknIVgn7.js → scss-B9m4FneT.js} +1 -1
- package/dist/web/assets/{send-B9VUQlEK.js → send-DQz3yIWM.js} +1 -1
- package/dist/web/assets/{send-to-chat-Kl-0dNwN.js → send-to-chat-01eMNs3j.js} +1 -1
- package/dist/web/assets/separator-CE0YEyaB.js +1 -0
- package/dist/web/assets/settings-body-Baw2komX.js +2 -0
- package/dist/web/assets/{settings-store-_s4xFcFq.js → settings-store-CuQlVCIe.js} +2 -2
- package/dist/web/assets/settings-tab-DCW-3C38.js +1 -0
- package/dist/web/assets/settings-window-content-CVxOGqPV.js +1 -0
- package/dist/web/assets/{shaderlab-CPu31TpY.js → shaderlab-BuCltaXx.js} +1 -1
- package/dist/web/assets/{shellsession-CFX4c_TM.js → shellsession-DG_WIFRW.js} +1 -1
- package/dist/web/assets/{shield-check-BJSX7cAS.js → shield-check-46EViZ6-.js} +1 -1
- package/dist/web/assets/{shield-off-E1cQwXdc.js → shield-off-Dx5mw3le.js} +1 -1
- package/dist/web/assets/{soy-rz9hilgm.js → soy-CKNCwmqR.js} +1 -1
- package/dist/web/assets/{sparkles-blTKn0vi.js → sparkles-Bay_CedB.js} +1 -1
- package/dist/web/assets/{sparql-Bo8ZDeqE.js → sparql-BEH92-9e.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BoYxc5vd.js → sql-query-editor-BTMEy88p.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-O5lF3MMj.js → sqlite-viewer-BWLSC3VJ.js} +1 -1
- package/dist/web/assets/{stata-B5J-QMyE.js → stata-Bt5IUWCl.js} +1 -1
- package/dist/web/assets/{streaming-store-QQvg1cS-.js → streaming-store-Dw3ZR1E4.js} +1 -1
- package/dist/web/assets/{surrealql-Caw1ADnG.js → surrealql-B5M94PT2.js} +1 -1
- package/dist/web/assets/{svelte-D3oMVcxz.js → svelte-BqLoF5fB.js} +1 -1
- package/dist/web/assets/{system-monitor-body-C2mVJ7PV.js → system-monitor-body-BqPyB0CY.js} +2 -2
- package/dist/web/assets/system-monitor-tab-BXRvCThe.js +1 -0
- package/dist/web/assets/system-monitor-window-content-CvvwXkmW.js +1 -0
- package/dist/web/assets/{tab-host-window-content-C7F6D8hJ.js → tab-host-window-content-23IR3qzu.js} +1 -1
- package/dist/web/assets/{tab-store-B2ip0-Mv.js → tab-store-Dsk4jnlN.js} +1 -1
- package/dist/web/assets/{table-8HT8BG30.js → table-BbD_HNPU.js} +1 -1
- package/dist/web/assets/team-member-sheet-BXJtrQAB.js +2 -0
- package/dist/web/assets/{team-member-window-content-BwOTsc9r.js → team-member-window-content-CBWnzwZ1.js} +1 -1
- package/dist/web/assets/{templ-BAdNyIOL.js → templ-BxGWIwYz.js} +1 -1
- package/dist/web/assets/{terminal-tab-DlZW3MCn.js → terminal-tab-uNw7Yvwg.js} +3 -3
- package/dist/web/assets/{tex-IQ8mELOR.js → tex-B9CPrNBA.js} +1 -1
- package/dist/web/assets/{text-wrap-DafY0-Pa.js → text-wrap-97GXZlav.js} +1 -1
- package/dist/web/assets/{tool-cards-yiwO861p.js → tool-cards-CjirOQfx.js} +6 -6
- package/dist/web/assets/treemap-KZPCXAKY-BBrhTPZk.js +1 -0
- package/dist/web/assets/{ts-tags-D1DDO2jl.js → ts-tags-CObhnP_s.js} +1 -1
- package/dist/web/assets/{twig-C8Fd5RvV.js → twig-ZcDaz0E8.js} +1 -1
- package/dist/web/assets/{use-blob-url-D358Rpyp.js → use-blob-url-D-NnFGAr.js} +1 -1
- package/dist/web/assets/{use-coarse-long-press-BsBpxWup.js → use-coarse-long-press-CynaAB7m.js} +1 -1
- package/dist/web/assets/{use-inline-blame-D2pZjDoA.js → use-inline-blame-BLPCADZ8.js} +1 -1
- package/dist/web/assets/{use-is-mobile-Bi42QhIi.js → use-is-mobile-BsqeOLv4.js} +1 -1
- package/dist/web/assets/use-monaco-theme-D2ETCHji.js +1 -0
- package/dist/web/assets/use-open-team-member-BlUqTp-l.js +1 -0
- package/dist/web/assets/{use-remote-desktop-display-choice-BnVT4dhX.js → use-remote-desktop-display-choice-B4O11KIj.js} +1 -1
- package/dist/web/assets/{use-visual-viewport-CNdG4QHH.js → use-visual-viewport-hdC_hRtB.js} +1 -1
- package/dist/web/assets/{use-websocket-DQg9BQcq.js → use-websocket-CUKjQFAl.js} +1 -1
- package/dist/web/assets/vendor-markdown-3-bej77C.js +291 -0
- package/dist/web/assets/{vendor-mermaid-CfY1-PkA.js → vendor-mermaid-BoRFiriK.js} +1 -1
- package/dist/web/assets/{vendor-ui-BBdkypKW.js → vendor-ui-D1NQnrtd.js} +1 -1
- package/dist/web/assets/{video-preview-Dc4YbBqm.js → video-preview-BlD1DNP8.js} +1 -1
- package/dist/web/assets/{vue-EvccXlkP.js → vue-TgfQfAF8.js} +1 -1
- package/dist/web/assets/{vue-html-Dg0xUJCh.js → vue-html-DbAh9aHW.js} +1 -1
- package/dist/web/assets/{vue-vine-BdrMg72k.js → vue-vine-DQ8US6vO.js} +1 -1
- package/dist/web/assets/{window-pip-registry-BWxaVLj5.js → window-pip-registry-DfPfSFQg.js} +1 -1
- package/dist/web/assets/{window-store-CfxP5yor.js → window-store-BSXqIkwB.js} +1 -1
- package/dist/web/assets/ws-auth-ZB8jvzhM.js +1 -0
- package/dist/web/assets/x-TEI-uJYo.js +1 -0
- package/dist/web/assets/{xml-MmDclzxK.js → xml-CXzUNYMl.js} +1 -1
- package/dist/web/assets/{xsl-DQEFs6Dd.js → xsl-CdnFww1s.js} +1 -1
- package/dist/web/index.html +43 -43
- package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
- package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
- package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
- package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
- package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/scripts/check-ppm-dir-usage.sh +0 -0
- package/scripts/install.sh +0 -0
- package/scripts/release.sh +0 -0
- package/src/providers/codex-app-server/codex-event-mapper.ts +28 -1
- package/src/providers/codex-app-server/codex-provider.ts +38 -5
- package/src/providers/codex-app-server/codex-usage-parser.ts +3 -1
- package/src/server/routes/codex-accounts.ts +9 -5
- package/src/services/codex-account-login.ts +33 -5
- package/src/services/codex-account-portability.ts +3 -2
- package/src/services/codex-account.service.ts +48 -7
- package/src/services/codex-login-callback.ts +18 -0
- package/src/services/db.service.ts +14 -0
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/windows-process-tree.ts +351 -351
- package/src/shared/codex-daily-guard.ts +27 -0
- package/src/shared/codex-plan-label.ts +17 -0
- package/src/web/components/chat/codex-usage-panel.tsx +22 -2
- package/src/web/components/settings/accounts/account-card.tsx +43 -2
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +43 -2
- package/src/web/components/settings/accounts/use-codex-accounts.ts +14 -2
- package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +1 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-content.tsx +8 -2
- package/src/web/components/tunnels/named-tunnel/named-tunnel-step-reducer.ts +14 -2
- package/dist/web/assets/accounts-settings-section-CRXY4Bsc.js +0 -1
- package/dist/web/assets/ai-settings-section-446NZWhI.js +0 -1
- package/dist/web/assets/api-client-CYZ79uUS.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-DfR8k8Bc.js +0 -1
- package/dist/web/assets/arrow-left-DpXaakMC.js +0 -1
- package/dist/web/assets/chat-tab-Dn45anqr.js +0 -15
- package/dist/web/assets/check-BQKbhtoA.js +0 -1
- package/dist/web/assets/chevron-right-DK_HbYZC.js +0 -1
- package/dist/web/assets/circle-OKk7s0DX.js +0 -1
- package/dist/web/assets/circle-question-mark-qcWYO1P_.js +0 -1
- package/dist/web/assets/clock-BmPiGrSF.js +0 -1
- package/dist/web/assets/code-CRiIHSiv.js +0 -1
- package/dist/web/assets/code-editor-CKASeDbu.js +0 -7
- package/dist/web/assets/explorer-window-content-CqKVMkgW.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-CPd78aaT.js +0 -1
- package/dist/web/assets/group-chat-tab-CTAhtVCr.js +0 -1
- package/dist/web/assets/index-B9Wbjl0o.css +0 -2
- package/dist/web/assets/index-DVNJ2W5R.js +0 -52
- package/dist/web/assets/info-3K5VOQVL-BciNds6R.js +0 -1
- package/dist/web/assets/keybindings-store-B5dEz0n1.js +0 -1
- package/dist/web/assets/loader-circle-DxI3O9_f.js +0 -1
- package/dist/web/assets/markdown-renderer-BGPo364Y.js +0 -1
- package/dist/web/assets/markdown-renderer-DtQIHtLs.js +0 -3
- package/dist/web/assets/mobile-explorer-sheet-C1q_DhrI.js +0 -1
- package/dist/web/assets/notification-store-DvUtkAXs.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-ClD3l2Bs.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-PU6kD0rW.js +0 -1
- package/dist/web/assets/portal-container-context-DeLx1cOI.js +0 -1
- package/dist/web/assets/power-CvtnQHU4.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-4LzjL0Zt.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-6JdUr0Bj.js +0 -2
- package/dist/web/assets/separator-DvCsdlws.js +0 -1
- package/dist/web/assets/settings-body-CcKls51a.js +0 -2
- package/dist/web/assets/settings-tab-ChAk8nh2.js +0 -1
- package/dist/web/assets/settings-window-content-sA1K0cPW.js +0 -1
- package/dist/web/assets/system-monitor-tab-tXkg3jpV.js +0 -1
- package/dist/web/assets/system-monitor-window-content-BaKoFDEz.js +0 -1
- package/dist/web/assets/team-member-sheet-BA70_jmM.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-DiumLNMg.js +0 -1
- package/dist/web/assets/use-accounts-data-B9t4BQaI.js +0 -1
- package/dist/web/assets/use-monaco-theme-DTPfPPvF.js +0 -1
- package/dist/web/assets/use-open-team-member-DGEx9xB0.js +0 -1
- package/dist/web/assets/vendor-markdown-CuWCHIVb.js +0 -291
- package/dist/web/assets/ws-auth-FRzMmfQx.js +0 -1
- package/dist/web/assets/x-Bdaog6Az.js +0 -1
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- /package/dist/web/assets/{abap-D-o-bvtI.js → abap-Dbc91hEB.js} +0 -0
- /package/dist/web/assets/{actionscript-3-D2tIzAm8.js → actionscript-3-C14d4O5M.js} +0 -0
- /package/dist/web/assets/{ada-DxatBcxS.js → ada-n8mPGtZF.js} +0 -0
- /package/dist/web/assets/{andromeeda-D0LK9YJ3.js → andromeeda-DAKL0TFq.js} +0 -0
- /package/dist/web/assets/{apache-B7uMPNiW.js → apache-BDCV8YqE.js} +0 -0
- /package/dist/web/assets/{apex-B7GiXrAr.js → apex-BphlFNA_.js} +0 -0
- /package/dist/web/assets/{applescript-D_SIFkKe.js → applescript-F2pJar76.js} +0 -0
- /package/dist/web/assets/{apply-theme-BVXAUYoN.js → apply-theme-Abd1TNqE.js} +0 -0
- /package/dist/web/assets/{ara-C3iECgdg.js → ara-B32t5JRb.js} +0 -0
- /package/dist/web/assets/{asciidoc-gc8z_MMY.js → asciidoc-DenFyKu-.js} +0 -0
- /package/dist/web/assets/{asm-27qeoPOI.js → asm-D5mJz41u.js} +0 -0
- /package/dist/web/assets/{aurora-x-C5J9fWe1.js → aurora-x-CUyAXiXM.js} +0 -0
- /package/dist/web/assets/{awk-B7GBzF92.js → awk-CUwaf-l-.js} +0 -0
- /package/dist/web/assets/{ayu-dark-XlnQhuLL.js → ayu-dark-Cgg8W7cK.js} +0 -0
- /package/dist/web/assets/{ayu-light-DKLLilkU.js → ayu-light-B1c04Bhg.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-Dv-XOprJ.js → ayu-mirage-CdWbuzp5.js} +0 -0
- /package/dist/web/assets/{ballerina-DACRT-sT.js → ballerina-B2-GPRG0.js} +0 -0
- /package/dist/web/assets/{bat-BlQCq2XE.js → bat-Nss7Yr-0.js} +0 -0
- /package/dist/web/assets/{beancount-DYDztRI0.js → beancount-CgaWuvpQ.js} +0 -0
- /package/dist/web/assets/{berry-BE5YKqvx.js → berry-DCFF4Zj1.js} +0 -0
- /package/dist/web/assets/{bibtex-CAm7mgEm.js → bibtex-BPNI-Gig.js} +0 -0
- /package/dist/web/assets/{bicep-BKgAbfVa.js → bicep-qCj6DX1x.js} +0 -0
- /package/dist/web/assets/{bird2-yrBNbW1G.js → bird2-DYDjG-B_.js} +0 -0
- /package/dist/web/assets/{c-txZFr4RM.js → c-CZV8SiOL.js} +0 -0
- /package/dist/web/assets/{c3-D_DrzBUd.js → c3-BG7R2A4x.js} +0 -0
- /package/dist/web/assets/{cadence-CUFCEgG9.js → cadence-BuiQVST4.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-_yqa69dV.js → can-open-in-ppm-DU5MH6XF.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-Dn32MuhA.js → catppuccin-frappe-C-nwrEbb.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Dewo7yDf.js → catppuccin-latte-nRLBO6vg.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-D8WOWZeo.js → catppuccin-macchiato-42eAAqCw.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-b0md48XM.js → catppuccin-mocha-4lH0_4tX.js} +0 -0
- /package/dist/web/assets/{clarity-Ct3UqLBj.js → clarity-BCPLN5zJ.js} +0 -0
- /package/dist/web/assets/{clojure-CwP5aPEo.js → clojure-Btb509Z6.js} +0 -0
- /package/dist/web/assets/{cmake-D5RF49e5.js → cmake-CGLZgJL3.js} +0 -0
- /package/dist/web/assets/{codeowners-Cl5897L_.js → codeowners-Dgqmdm5J.js} +0 -0
- /package/dist/web/assets/{codeql-BKh1RCg0.js → codeql-DDUO6ZHS.js} +0 -0
- /package/dist/web/assets/{common-lisp-BhHuD6t0.js → common-lisp-DlhZ-mM8.js} +0 -0
- /package/dist/web/assets/{coq-Dco3qwD8.js → coq-CVz-5qYC.js} +0 -0
- /package/dist/web/assets/{csharp-Dpjw9ZA9.js → csharp-CXL6GcvM.js} +0 -0
- /package/dist/web/assets/{css-CPe4cabH.js → css-CthwUm0E.js} +0 -0
- /package/dist/web/assets/{csv-BAcTN8Kt.js → csv-Bsal3rDr.js} +0 -0
- /package/dist/web/assets/{csv-parser-DbxGKdMG.js → csv-parser-iow1WWML.js} +0 -0
- /package/dist/web/assets/{cue-Cr6y60TA.js → cue-D2bSqa4C.js} +0 -0
- /package/dist/web/assets/{cypher-DWtqXXFP.js → cypher-u-EM8HmU.js} +0 -0
- /package/dist/web/assets/{d-BASiTZk4.js → d-BFVkgfjO.js} +0 -0
- /package/dist/web/assets/{dark-plus-56kmnrcl.js → dark-plus-BXlM9uFB.js} +0 -0
- /package/dist/web/assets/{dart-C5mZnjoE.js → dart-Hxx4mUdp.js} +0 -0
- /package/dist/web/assets/{dax-B4I2e7d8.js → dax-DQwsaFe_.js} +0 -0
- /package/dist/web/assets/{desktop-DekGg0BT.js → desktop-CAHGHZLk.js} +0 -0
- /package/dist/web/assets/{diff-CWnJBd73.js → diff-CAbIXu6l.js} +0 -0
- /package/dist/web/assets/{dist-BKOM_AoT.js → dist-C_bG2Tku.js} +0 -0
- /package/dist/web/assets/{docker-DevchDxK.js → docker-51FhFKmM.js} +0 -0
- /package/dist/web/assets/{dotenv-DCvtdaGJ.js → dotenv-C4fc3fLK.js} +0 -0
- /package/dist/web/assets/{dracula-8U6Vkk3l.js → dracula-CTtuacPO.js} +0 -0
- /package/dist/web/assets/{dracula-soft-Bfeew5Wg.js → dracula-soft-B-95hu1J.js} +0 -0
- /package/dist/web/assets/{dream-maker-DDTJVuoy.js → dream-maker-Di3hAOzX.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-CEHJqI4m.js → emacs-lisp-C6btr6QV.js} +0 -0
- /package/dist/web/assets/{everforest-dark-CHHLt7cq.js → everforest-dark-CDQGzEiq.js} +0 -0
- /package/dist/web/assets/{everforest-light-TcTbK1sM.js → everforest-light-DRZC8v3w.js} +0 -0
- /package/dist/web/assets/{fennel-Bh4vsA1A.js → fennel-BZz92X8f.js} +0 -0
- /package/dist/web/assets/{fish-D0T0fILG.js → fish-qpLXUfGf.js} +0 -0
- /package/dist/web/assets/{fluent-CgXDXdyy.js → fluent-B3F6P-xc.js} +0 -0
- /package/dist/web/assets/{format-bytes-Bc6SqF7M.js → format-bytes-B9Dbme9a.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-CUg3Xhz4.js → fortran-free-form-DjGQrmKa.js} +0 -0
- /package/dist/web/assets/{gdscript-Cx056p_k.js → gdscript-DToF1duE.js} +0 -0
- /package/dist/web/assets/{gdshader-Dj1qP4I5.js → gdshader-FZCS76-j.js} +0 -0
- /package/dist/web/assets/{genie-SBt15wn7.js → genie-CN3-FS9S.js} +0 -0
- /package/dist/web/assets/{gherkin-bTJiHIrB.js → gherkin-DT66zHzt.js} +0 -0
- /package/dist/web/assets/{github-dark-BOPhyugs.js → github-dark-5S2AJM2m.js} +0 -0
- /package/dist/web/assets/{github-dark-default-Cktqe6NF.js → github-dark-default-DNEUWmc8.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-CeWfII_B.js → github-dark-dimmed-BVgm_raB.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-CTx8LpdV.js → github-dark-high-contrast-Dai8qNkr.js} +0 -0
- /package/dist/web/assets/{github-light-DVsO5Un1.js → github-light-C49nlhDa.js} +0 -0
- /package/dist/web/assets/{github-light-default-BiyPxicr.js → github-light-default-BLQcyxQl.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-BPlnke0a.js → github-light-high-contrast-BH3u_hMd.js} +0 -0
- /package/dist/web/assets/{gleam-CWSxvD0C.js → gleam-G2907CEQ.js} +0 -0
- /package/dist/web/assets/{gn-D7NUVJuv.js → gn-fxgN7J9Q.js} +0 -0
- /package/dist/web/assets/{gnuplot-c5uXmJKc.js → gnuplot-a1TK_67n.js} +0 -0
- /package/dist/web/assets/{go-CRsHi4Cw.js → go-DLqnNJpz.js} +0 -0
- /package/dist/web/assets/{groovy-DpV0RA5r.js → groovy-D8U-plxc.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-DD9fguUN.js → gruvbox-dark-hard-DRYdA7rg.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-BvcwpYJ-.js → gruvbox-dark-medium-CJgayBQH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-48dCxX9M.js → gruvbox-dark-soft-spQNOlQ2.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-CjJ994Ip.js → gruvbox-light-hard-FoElS0Wo.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-DQJQZ_rV.js → gruvbox-light-medium-9E1Brisc.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-AqsC9mKw.js → gruvbox-light-soft-Coyp7RRB.js} +0 -0
- /package/dist/web/assets/{haskell-B5V7yvmh.js → haskell-D1twJpgj.js} +0 -0
- /package/dist/web/assets/{haxe-LWTKfPKr.js → haxe-CppquubK.js} +0 -0
- /package/dist/web/assets/{hcl-QmNZdAtI.js → hcl-BWfTkyhR.js} +0 -0
- /package/dist/web/assets/{hjson-CboJsAzK.js → hjson-fgd7F6t5.js} +0 -0
- /package/dist/web/assets/{hlsl-Bd-DO_WL.js → hlsl-Ua1j-4aZ.js} +0 -0
- /package/dist/web/assets/{horizon-CU8Bi_ss.js → horizon-CTFgrxGb.js} +0 -0
- /package/dist/web/assets/{horizon-bright-iSQ3_3jP.js → horizon-bright-C4eTVZPB.js} +0 -0
- /package/dist/web/assets/{houston-CTXv3Puz.js → houston-BeYbWPdk.js} +0 -0
- /package/dist/web/assets/{hy-Cd4hTidD.js → hy-BposFX9Q.js} +0 -0
- /package/dist/web/assets/{image-gallery-J8h8IY0c.js → image-gallery-COea0nSk.js} +0 -0
- /package/dist/web/assets/{imba-BipCHEY2.js → imba-D11-b73t.js} +0 -0
- /package/dist/web/assets/{ini-Dd1KkMrB.js → ini-BCYCXf0w.js} +0 -0
- /package/dist/web/assets/{java-rGr0OQD8.js → java-BqKIPPzY.js} +0 -0
- /package/dist/web/assets/{javascript-DHhCH2TN.js → javascript-CxvTx_wu.js} +0 -0
- /package/dist/web/assets/{json-CMMLBCUf.js → json-DiknJGdj.js} +0 -0
- /package/dist/web/assets/{json5-mPOwTOsB.js → json5--8nFeehk.js} +0 -0
- /package/dist/web/assets/{jsonc-Bie0E6D3.js → jsonc-BFcq-Nx-.js} +0 -0
- /package/dist/web/assets/{jsonl-CpqHmtC1.js → jsonl-DKItgfTA.js} +0 -0
- /package/dist/web/assets/{jsonnet-D21Ms51e.js → jsonnet-sNz5wf7H.js} +0 -0
- /package/dist/web/assets/{jssm-BXnl1nur.js → jssm-BALAIF_E.js} +0 -0
- /package/dist/web/assets/{jsx-Chnii_vB.js → jsx-fXHHDCVl.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-DhxR0UjL.js → kanagawa-dragon-nywk9qzg.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-fupRg5wp.js → kanagawa-lotus-BmYPLC4f.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-DSWbRS9M.js → kanagawa-wave-624mOWgc.js} +0 -0
- /package/dist/web/assets/{kdl-DirGHqUy.js → kdl-DT8Argim.js} +0 -0
- /package/dist/web/assets/{kotlin-DkhUVMDC.js → kotlin-BvUjvPz2.js} +0 -0
- /package/dist/web/assets/{kusto-DU7OpovF.js → kusto-B0PONVdx.js} +0 -0
- /package/dist/web/assets/{laserwave-iLKb1ZCT.js → laserwave-ByV7LuzT.js} +0 -0
- /package/dist/web/assets/{lean-Cuvh_QAP.js → lean-DQtq2qQC.js} +0 -0
- /package/dist/web/assets/{less-B5tQZOdI.js → less-DZeD4ccP.js} +0 -0
- /package/dist/web/assets/{libesm-CdttTIAd.js → libesm-CcPYXCKp.js} +0 -0
- /package/dist/web/assets/{light-plus-DiHU2KL5.js → light-plus-BCaKDxvd.js} +0 -0
- /package/dist/web/assets/{llvm-sCBTKCKN.js → llvm-Dzok661y.js} +0 -0
- /package/dist/web/assets/{log-DtyR34Ie.js → log-C32HpwgI.js} +0 -0
- /package/dist/web/assets/{logo-CP91aQyG.js → logo-Dtjk3XHO.js} +0 -0
- /package/dist/web/assets/{luau-nfGo2ulP.js → luau-BMbN7IqN.js} +0 -0
- /package/dist/web/assets/{make-XbDn9GHe.js → make-DIVSnx7D.js} +0 -0
- /package/dist/web/assets/{markdown-BB1_3xLr.js → markdown-B1JzcsJb.js} +0 -0
- /package/dist/web/assets/{material-theme-CIx_sxAy.js → material-theme-XMfEph9O.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-DsQeueDD.js → material-theme-darker-CRGzh4Ox.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-x_lMi74j.js → material-theme-lighter-D6esgP3h.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-Bkgh25P8.js → material-theme-ocean-CGbfRrFG.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-CoOjdbti.js → material-theme-palenight-DFW4xdPI.js} +0 -0
- /package/dist/web/assets/{matlab-D6xZas_8.js → matlab-Zpc8hvmI.js} +0 -0
- /package/dist/web/assets/{mdx-Cl5_YNoz.js → mdx-DLlDpnjI.js} +0 -0
- /package/dist/web/assets/{mermaid-8Eow4jz_.js → mermaid-q_sEDHYr.js} +0 -0
- /package/dist/web/assets/{min-dark-D4DhjgRE.js → min-dark-DUklXai3.js} +0 -0
- /package/dist/web/assets/{min-light-DzAckd0t.js → min-light-Ps7CV3R0.js} +0 -0
- /package/dist/web/assets/{mipsasm-zI_zu0tj.js → mipsasm-anKs0TGD.js} +0 -0
- /package/dist/web/assets/{mojo-DQnGGPHf.js → mojo-CWTvit9D.js} +0 -0
- /package/dist/web/assets/{monokai-CrFoD2VD.js → monokai-DOSMe3B9.js} +0 -0
- /package/dist/web/assets/{moonbit-DdphIGs6.js → moonbit-zOAryA05.js} +0 -0
- /package/dist/web/assets/{move-BUlkn0xW.js → move-CA6YZdSC.js} +0 -0
- /package/dist/web/assets/{narrat-CbOBdtCn.js → narrat-CyMxkfZJ.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CeVLUTuQ.js → nextflow-groovy-D5beSS3L.js} +0 -0
- /package/dist/web/assets/{night-owl-Bm4LhUR1.js → night-owl-3ALu1K6e.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DtcBiMEf.js → night-owl-light-_NLbQQrl.js} +0 -0
- /package/dist/web/assets/{nix-DrdwQ70g.js → nix-C_KqthNc.js} +0 -0
- /package/dist/web/assets/{nord-B0Head1v.js → nord-VG8J_Wfy.js} +0 -0
- /package/dist/web/assets/{nushell-CmUdltKn.js → nushell-Dx7K7YNI.js} +0 -0
- /package/dist/web/assets/{objective-c-BGDR33XN.js → objective-c-DrEbGERB.js} +0 -0
- /package/dist/web/assets/{objective-cpp-Buc1Zhd0.js → objective-cpp-DpiXqKhj.js} +0 -0
- /package/dist/web/assets/{ocaml-xdzl9rRD.js → ocaml-G6x51MAm.js} +0 -0
- /package/dist/web/assets/{odin-DiUFngnd.js → odin-tK6CU-OU.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-BURxmIp3.js → one-dark-pro-581te-yF.js} +0 -0
- /package/dist/web/assets/{one-light-BMRMInAj.js → one-light-DpYva-U1.js} +0 -0
- /package/dist/web/assets/{openscad-DAgLA5J3.js → openscad-C7LYrrI4.js} +0 -0
- /package/dist/web/assets/{pascal-CoDZxcRB.js → pascal-ChqM3eJD.js} +0 -0
- /package/dist/web/assets/{pkl-DzKM6BuM.js → pkl-BlIRJsyQ.js} +0 -0
- /package/dist/web/assets/{plastic-vF15LmNS.js → plastic-DxceXlOD.js} +0 -0
- /package/dist/web/assets/{plsql-C1v07teA.js → plsql-CVikvjWK.js} +0 -0
- /package/dist/web/assets/{po-CLLC8BuA.js → po-BN9bpeJD.js} +0 -0
- /package/dist/web/assets/{poimandres-Uq0xysxM.js → poimandres-NeQA7ZSh.js} +0 -0
- /package/dist/web/assets/{polar-2-luY1Pc.js → polar-DtRx-uzO.js} +0 -0
- /package/dist/web/assets/{postcss-lbFhe0rz.js → postcss-EDnOs84S.js} +0 -0
- /package/dist/web/assets/{powerquery-RL8O9Wie.js → powerquery-mc-bbl3v.js} +0 -0
- /package/dist/web/assets/{powershell-upFWhb-b.js → powershell-ZqZF93a-.js} +0 -0
- /package/dist/web/assets/{prisma-DBtYaWFk.js → prisma-vhORN1Sx.js} +0 -0
- /package/dist/web/assets/{prolog-D8jSMykJ.js → prolog-DfIbN_m8.js} +0 -0
- /package/dist/web/assets/{proto-BM4eadF7.js → proto-BHcnh-Db.js} +0 -0
- /package/dist/web/assets/{puppet-BQDQ3Snu.js → puppet-oLpQOx2h.js} +0 -0
- /package/dist/web/assets/{purescript-Cj2aTX4s.js → purescript-HbM4Dt8M.js} +0 -0
- /package/dist/web/assets/{python-BYpqq6u4.js → python-Dlxo2z6Q.js} +0 -0
- /package/dist/web/assets/{qmldir-4uiTcwAu.js → qmldir-B5ox9idu.js} +0 -0
- /package/dist/web/assets/{qss-D5xB-Mqo.js → qss-CyegwBrl.js} +0 -0
- /package/dist/web/assets/{r-P6Ujy8rf.js → r-CxE2X3lg.js} +0 -0
- /package/dist/web/assets/{racket-COKgCFuM.js → racket-CpguQMOj.js} +0 -0
- /package/dist/web/assets/{raku-z14Q9i7K.js → raku-DDf8ASYE.js} +0 -0
- /package/dist/web/assets/{red-ObAvgvQ5.js → red-C634f6x3.js} +0 -0
- /package/dist/web/assets/{reg-Qv4f0JFA.js → reg-4gnm7BOP.js} +0 -0
- /package/dist/web/assets/{regexp-CEOVGIzy.js → regexp-Cs-hPAru.js} +0 -0
- /package/dist/web/assets/{rel-cWOyTUwd.js → rel-CrGcWbwM.js} +0 -0
- /package/dist/web/assets/{resolve-theme-CMp5xxCW.js → resolve-theme-Dm8ehbOv.js} +0 -0
- /package/dist/web/assets/{riscv-BZDwx-lv.js → riscv-B2P26ROS.js} +0 -0
- /package/dist/web/assets/{ron-BpjosPS0.js → ron-DDHGmvxW.js} +0 -0
- /package/dist/web/assets/{rose-pine-DhxfJWcm.js → rose-pine-CUYRoYal.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-BbGt9Wy_.js → rose-pine-dawn-C9JfuUh8.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-dj4Zxgik.js → rose-pine-moon-CrYHzRJm.js} +0 -0
- /package/dist/web/assets/{rosmsg-EciOaHo2.js → rosmsg-iqzz1U38.js} +0 -0
- /package/dist/web/assets/{rust-C_eH59O_.js → rust-DVeWF3Is.js} +0 -0
- /package/dist/web/assets/{sass-Dos3R5lL.js → sass-CbVwBbUd.js} +0 -0
- /package/dist/web/assets/{scala-8lVKsTvf.js → scala-gZhcvPGv.js} +0 -0
- /package/dist/web/assets/{scheme-Bd3VdaZj.js → scheme-Z-DWgvmB.js} +0 -0
- /package/dist/web/assets/{sdbl-C4Yrjlgh.js → sdbl-wn_BtpSz.js} +0 -0
- /package/dist/web/assets/{shellscript-OFZbPKZH.js → shellscript-C09f889h.js} +0 -0
- /package/dist/web/assets/{slack-dark-aL6vlxZs.js → slack-dark-D63Fbr3l.js} +0 -0
- /package/dist/web/assets/{slack-ochin-BKt1E7sL.js → slack-ochin--Yu-v0r6.js} +0 -0
- /package/dist/web/assets/{smalltalk-D6qVBL1U.js → smalltalk-LQDcL_tW.js} +0 -0
- /package/dist/web/assets/{snazzy-light-BrWerT0t.js → snazzy-light-bo9fX83t.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CzxTJgVQ.js → solarized-dark-zSs85XH6.js} +0 -0
- /package/dist/web/assets/{solarized-light-BecaDAnG.js → solarized-light-B6Q4CXBt.js} +0 -0
- /package/dist/web/assets/{solidity-C9t7pZ84.js → solidity-uUJPOjGx.js} +0 -0
- /package/dist/web/assets/{splunk-CtxfFKtF.js → splunk-C6oWgmrC.js} +0 -0
- /package/dist/web/assets/{sql-7FE_Duz0.js → sql-DyUvXbLi.js} +0 -0
- /package/dist/web/assets/{ssh-config-3Fr37ACC.js → ssh-config-62Vrd_7v.js} +0 -0
- /package/dist/web/assets/{stylus-BP4mE1sO.js → stylus-CmLQe7Fq.js} +0 -0
- /package/dist/web/assets/{swift-0uqTFouD.js → swift-DJwuT1eZ.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DQaNM3DI.js → synthwave-84-CEeyTLD7.js} +0 -0
- /package/dist/web/assets/{system-verilog-DUIVrZHZ.js → system-verilog-DMqtAclw.js} +0 -0
- /package/dist/web/assets/{systemd-CtNo_WIh.js → systemd-XnScP_8M.js} +0 -0
- /package/dist/web/assets/{talonscript-B0HXaCVT.js → talonscript-CDoODzml.js} +0 -0
- /package/dist/web/assets/{tasl-Cb7RAl11.js → tasl-DycI0-Tf.js} +0 -0
- /package/dist/web/assets/{tcl-B79aC6l5.js → tcl-Dt8iP0sw.js} +0 -0
- /package/dist/web/assets/{terraform-75jJDjpW.js → terraform-DXzABgqQ.js} +0 -0
- /package/dist/web/assets/{tokyo-night-Cz9Uh9qb.js → tokyo-night-DHB1Yc-3.js} +0 -0
- /package/dist/web/assets/{toml-CD6y9A-z.js → toml-BkejsZF3.js} +0 -0
- /package/dist/web/assets/{tsv-CXJMbBrb.js → tsv-ClmhsiiR.js} +0 -0
- /package/dist/web/assets/{tsx-BuYN0I2t.js → tsx-Cp-c_JHF.js} +0 -0
- /package/dist/web/assets/{turtle-DWH-Rjse.js → turtle-BbwC417u.js} +0 -0
- /package/dist/web/assets/{typescript-BPd-hsrR.js → typescript-DbwnrRKJ.js} +0 -0
- /package/dist/web/assets/{typespec-B0wvVykx.js → typespec-DLL0LoZj.js} +0 -0
- /package/dist/web/assets/{typst-DWG2c48-.js → typst-BmEouVT1.js} +0 -0
- /package/dist/web/assets/{utils-IrnQujwR.js → utils-CwNUra6_.js} +0 -0
- /package/dist/web/assets/{v-Ch6E4Egd.js → v-C5rFgF81.js} +0 -0
- /package/dist/web/assets/{vala-CGVKwbPx.js → vala-rBXMujLw.js} +0 -0
- /package/dist/web/assets/{vb-BIEbSxyT.js → vb-mxG_YZv2.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-YQlzIWv2.js → vendor-xterm-BtjgHRUe.js} +0 -0
- /package/dist/web/assets/{verilog-A-3pYPad.js → verilog-uQ-oJRKp.js} +0 -0
- /package/dist/web/assets/{vesper-CK1naZAV.js → vesper-SO5Hw_2X.js} +0 -0
- /package/dist/web/assets/{vhdl-CVawmgMg.js → vhdl-8IeO85hx.js} +0 -0
- /package/dist/web/assets/{viml-CiWjaqBY.js → viml-De-Hm57y.js} +0 -0
- /package/dist/web/assets/{vitesse-black-PYXW4-BO.js → vitesse-black-BVm23GJE.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-BU5s4AuG.js → vitesse-dark-CR0XeT-h.js} +0 -0
- /package/dist/web/assets/{vitesse-light-DgkIT-N7.js → vitesse-light-CXIFICUA.js} +0 -0
- /package/dist/web/assets/{vyper-D8cRDPp3.js → vyper-dUuvAUFJ.js} +0 -0
- /package/dist/web/assets/{wasm-ClFJgzmT.js → wasm-D5Vd7qV1.js} +0 -0
- /package/dist/web/assets/{wasm-C02wlRbP.js → wasm-DbLMmiW0.js} +0 -0
- /package/dist/web/assets/{wenyan-B8plxIr8.js → wenyan-BafBYCBu.js} +0 -0
- /package/dist/web/assets/{wgsl-CVujtm3V.js → wgsl-DY5sHamz.js} +0 -0
- /package/dist/web/assets/{wikitext-CmcG9B69.js → wikitext-QkQQVra5.js} +0 -0
- /package/dist/web/assets/{wit--gl2Jium.js → wit-BZjaDTy9.js} +0 -0
- /package/dist/web/assets/{wolfram-6T_1D-NS.js → wolfram-vrjPFD7R.js} +0 -0
- /package/dist/web/assets/{yaml-CIVV9uA1.js → yaml-D1as76NB.js} +0 -0
- /package/dist/web/assets/{zenscript-CoT4yNdA.js → zenscript-D31myxQh.js} +0 -0
- /package/dist/web/assets/{zig-BWs2Qo3G.js → zig-BbLb6ieN.js} +0 -0
|
@@ -16,6 +16,7 @@ import { configService } from "./config.service.ts";
|
|
|
16
16
|
import { encrypt, decrypt } from "../lib/account-crypto.ts";
|
|
17
17
|
import { getOrFetchUsage } from "./provider-usage/usage-registry.ts";
|
|
18
18
|
import { isCodexAccountUsageLimited } from "./codex-account-cooldown.ts";
|
|
19
|
+
import { dailyGuardMessage, dailyGuardState } from "../shared/codex-daily-guard.ts";
|
|
19
20
|
import type { UsageInfo } from "../providers/provider.interface.ts";
|
|
20
21
|
|
|
21
22
|
export type CodexStrategy = "round-robin" | "fill-first" | "lowest-usage";
|
|
@@ -32,6 +33,7 @@ export interface CodexAccount {
|
|
|
32
33
|
home: string;
|
|
33
34
|
planType?: string | null;
|
|
34
35
|
status: CodexAccountStatus;
|
|
36
|
+
dailyGuardEnabled: boolean;
|
|
35
37
|
addedAt: string;
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -44,6 +46,7 @@ interface Row {
|
|
|
44
46
|
id: string; label: string | null; type: string; home: string;
|
|
45
47
|
plan_type: string | null; creds_enc: string | null; added_at: string;
|
|
46
48
|
status?: string | null;
|
|
49
|
+
daily_guard_enabled?: number | null;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function rowToAccount(r: Row): CodexAccount {
|
|
@@ -56,6 +59,7 @@ function rowToAccount(r: Row): CodexAccount {
|
|
|
56
59
|
// A row written before the column existed reads as null; treat that as enabled, which
|
|
57
60
|
// is what it effectively was.
|
|
58
61
|
status: r.status === "disabled" ? "disabled" : "active",
|
|
62
|
+
dailyGuardEnabled: r.daily_guard_enabled !== 0,
|
|
59
63
|
addedAt: r.added_at,
|
|
60
64
|
};
|
|
61
65
|
}
|
|
@@ -87,7 +91,7 @@ export function getCodexAccountCreds(id: string): CodexCreds | null {
|
|
|
87
91
|
* verified label/planType and the creds to persist (encrypted). Idempotent dir create.
|
|
88
92
|
*/
|
|
89
93
|
export function createCodexAccount(input: {
|
|
90
|
-
label: string; type: CodexAccountType; planType?: string | null; creds?: CodexCreds; id?: string;
|
|
94
|
+
label: string; type: CodexAccountType; planType?: string | null; creds?: CodexCreds; id?: string; dailyGuardEnabled?: boolean;
|
|
91
95
|
}): CodexAccount {
|
|
92
96
|
const id = input.id ?? randomUUID();
|
|
93
97
|
const home = codexAccountHome(id);
|
|
@@ -98,8 +102,8 @@ export function createCodexAccount(input: {
|
|
|
98
102
|
const credsEnc = input.creds ? encrypt(JSON.stringify(input.creds)) : null;
|
|
99
103
|
try {
|
|
100
104
|
getDb().query(
|
|
101
|
-
"INSERT INTO codex_accounts (id, label, type, home, plan_type, creds_enc) VALUES (?, ?, ?, ?, ?, ?)",
|
|
102
|
-
).run(id, input.label, input.type, home, input.planType ?? null, credsEnc);
|
|
105
|
+
"INSERT INTO codex_accounts (id, label, type, home, plan_type, creds_enc, daily_guard_enabled) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
106
|
+
).run(id, input.label, input.type, home, input.planType ?? null, credsEnc, input.dailyGuardEnabled === false ? 0 : 1);
|
|
103
107
|
} catch (e) {
|
|
104
108
|
// Keep the invariant row⟺home: drop the dir if the row didn't land.
|
|
105
109
|
try { rmSync(home, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
@@ -136,6 +140,15 @@ export function setCodexAccountStatus(id: string, status: CodexAccountStatus): C
|
|
|
136
140
|
return getCodexAccount(id);
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
/** Enable or disable the seven-day quota pacing guard for one account. */
|
|
144
|
+
export function setCodexDailyGuard(id: string, enabled: boolean): CodexAccount | null {
|
|
145
|
+
if (!getCodexAccount(id)) return null;
|
|
146
|
+
getDb().query("UPDATE codex_accounts SET daily_guard_enabled = ? WHERE id = ?").run(enabled ? 1 : 0, id);
|
|
147
|
+
return getCodexAccount(id);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export class CodexDailyGuardError extends Error {}
|
|
151
|
+
|
|
139
152
|
/** Remove the account row and its CODEX_HOME dir. */
|
|
140
153
|
export function removeCodexAccount(id: string): void {
|
|
141
154
|
const acct = getCodexAccount(id);
|
|
@@ -279,15 +292,43 @@ export async function resolveCodexAccountForSession(sessionId?: string): Promise
|
|
|
279
292
|
// would do nothing for exactly the conversations already using it. An account parked for
|
|
280
293
|
// an exhausted quota lets go for a different reason — it would refuse the turn, and
|
|
281
294
|
// spending one to rediscover that is worse than starting on an account that can answer.
|
|
282
|
-
if (sticky) {
|
|
283
|
-
const a = getCodexAccount(sticky);
|
|
284
|
-
if (a && a.status !== "disabled" && !isCodexAccountUsageLimited(a.id)) return a;
|
|
285
|
-
}
|
|
286
295
|
// Usage is only worth fetching when it can change the answer, and with at most one
|
|
287
296
|
// account able to serve it cannot. Parked accounts count as unable for the same reason
|
|
288
297
|
// they are skipped below, so a pool of two where one is out of quota resolves without a
|
|
289
298
|
// network read at all.
|
|
290
299
|
const usable = listCodexAccounts().filter((a) => a.status !== "disabled" && !isCodexAccountUsageLimited(a.id));
|
|
300
|
+
const guarded = usable.filter((a) => a.dailyGuardEnabled);
|
|
301
|
+
if (guarded.length > 0) {
|
|
302
|
+
const usages = await getAllCodexUsages();
|
|
303
|
+
const blocked = guarded.flatMap((a) => {
|
|
304
|
+
// Pacing is for plans that only expose the weekly bucket. A Plus account's separate
|
|
305
|
+
// five-hour window is already the useful short-term control and must not gain this row.
|
|
306
|
+
const usage = usages[a.id];
|
|
307
|
+
const state = usage?.session == null ? dailyGuardState(usage?.weekly) : null;
|
|
308
|
+
return state?.blocked ? [a.id] : [];
|
|
309
|
+
});
|
|
310
|
+
if (blocked.length > 0) {
|
|
311
|
+
const stickyAccount = sticky ? getCodexAccount(sticky) : null;
|
|
312
|
+
if (stickyAccount && !blocked.includes(stickyAccount.id)
|
|
313
|
+
&& stickyAccount.status !== "disabled" && !isCodexAccountUsageLimited(stickyAccount.id)) return stickyAccount;
|
|
314
|
+
if (blocked.length === usable.length && sessionId) {
|
|
315
|
+
const account = getCodexAccount(blocked[0]!);
|
|
316
|
+
const usage = account ? usages[account.id] : undefined;
|
|
317
|
+
const state = usage?.session == null ? dailyGuardState(usage?.weekly) : null;
|
|
318
|
+
throw new CodexDailyGuardError(state ? dailyGuardMessage(state) : "Daily guard reached for every available Codex account.");
|
|
319
|
+
}
|
|
320
|
+
return selectCodexAccount({ usageOf: (id) => codexUsageLevel(usages[id]), exclude: blocked });
|
|
321
|
+
}
|
|
322
|
+
if (sticky) {
|
|
323
|
+
const a = getCodexAccount(sticky);
|
|
324
|
+
if (a && a.status !== "disabled" && !isCodexAccountUsageLimited(a.id)) return a;
|
|
325
|
+
}
|
|
326
|
+
return selectCodexAccount({ usageOf: (id) => codexUsageLevel(usages[id]) });
|
|
327
|
+
}
|
|
328
|
+
if (sticky) {
|
|
329
|
+
const a = getCodexAccount(sticky);
|
|
330
|
+
if (a && a.status !== "disabled" && !isCodexAccountUsageLimited(a.id)) return a;
|
|
331
|
+
}
|
|
291
332
|
if (usable.length <= 1) return selectCodexAccount();
|
|
292
333
|
// Usage is read for every strategy, not just lowest-usage: it is also what lets the
|
|
293
334
|
// selector skip an account with no five-hour room left. Reading it only for lowest-usage
|
|
@@ -55,3 +55,21 @@ export function buildCodexCallback(callbackUrl: string, login: BrowserLoginCallb
|
|
|
55
55
|
expected.searchParams.set("state", state!);
|
|
56
56
|
return expected;
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Codex accepts the authorization callback, then redirects to its own loopback
|
|
61
|
+
* success endpoint with the exchanged id token. Follow exactly that endpoint
|
|
62
|
+
* while keeping the TCP connection on 127.0.0.1.
|
|
63
|
+
*/
|
|
64
|
+
export function buildCodexSuccessCallback(location: string, login: BrowserLoginCallback): URL {
|
|
65
|
+
let redirect: URL;
|
|
66
|
+
try { redirect = new URL(location); } catch { throw new Error("Codex returned an invalid callback redirect."); }
|
|
67
|
+
const expected = new URL(login.redirectUri);
|
|
68
|
+
if (redirect.protocol !== "http:" || redirect.hostname !== "localhost" || redirect.port !== expected.port
|
|
69
|
+
|| redirect.pathname !== "/success" || redirect.username || redirect.password || redirect.hash
|
|
70
|
+
|| redirect.searchParams.getAll("id_token").length !== 1) {
|
|
71
|
+
throw new Error("Codex returned an unsupported callback redirect.");
|
|
72
|
+
}
|
|
73
|
+
redirect.hostname = "127.0.0.1";
|
|
74
|
+
return redirect;
|
|
75
|
+
}
|
|
@@ -1121,6 +1121,20 @@ export function runMigrations(database: Database): void {
|
|
|
1121
1121
|
try { database.exec(`ALTER TABLE codex_accounts ADD COLUMN status TEXT NOT NULL DEFAULT 'active'`); } catch { /* exists */ }
|
|
1122
1122
|
database.exec(`PRAGMA user_version = 47;`);
|
|
1123
1123
|
}
|
|
1124
|
+
|
|
1125
|
+
if (current < 48) {
|
|
1126
|
+
// Optional per-account pacing for weekly-only Codex plans. Disabled by default so an
|
|
1127
|
+
// upgrade never changes how an existing account is selected or used.
|
|
1128
|
+
try { database.exec(`ALTER TABLE codex_accounts ADD COLUMN daily_guard_enabled INTEGER NOT NULL DEFAULT 0`); } catch { /* exists */ }
|
|
1129
|
+
database.exec(`PRAGMA user_version = 48;`);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (current < 49) {
|
|
1133
|
+
// Daily guard was introduced as an opt-in during development. Ship it enabled so every
|
|
1134
|
+
// weekly-only account starts paced; Plus accounts simply do not surface or use it.
|
|
1135
|
+
database.exec(`UPDATE codex_accounts SET daily_guard_enabled = 1`);
|
|
1136
|
+
database.exec(`PRAGMA user_version = 49;`);
|
|
1137
|
+
}
|
|
1124
1138
|
}
|
|
1125
1139
|
|
|
1126
1140
|
// ---------------------------------------------------------------------------
|
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Edge forwarder — owns the public port and pipes raw TCP to the server's
|
|
3
|
-
* current loopback port.
|
|
4
|
-
*
|
|
5
|
-
* ─── CRITICAL INVARIANT: THIS PROCESS MUST NEVER SPAWN A CHILD ───
|
|
6
|
-
*
|
|
7
|
-
* On Windows a child spawned with fd stdio inherits every inheritable handle,
|
|
8
|
-
* including a listening socket. When such a descendant is orphaned it keeps the
|
|
9
|
-
* socket open, so the port stays in LISTEN under a dead PID and can never be
|
|
10
|
-
* rebound — a "zombie port". The server hits this constantly because it spawns
|
|
11
|
-
* chat/tool/MCP subprocesses; those inherit its listener and wedge its port.
|
|
12
|
-
*
|
|
13
|
-
* The edge exists precisely because it spawns nothing, so its socket cannot be
|
|
14
|
-
* inherited and its port cannot zombie. cloudflared can therefore stay pinned
|
|
15
|
-
* to it forever and the public URL stops rotating. Adding any child-process
|
|
16
|
-
* call to this file reintroduces the exact bug the edge was built to remove.
|
|
17
|
-
*
|
|
18
|
-
* Raw TCP, never HTTP: WebSocket upgrades and SSE streams pass through
|
|
19
|
-
* untouched, and forwarded requests keep the headers cloudflared set.
|
|
20
|
-
*/
|
|
21
|
-
import net from "node:net";
|
|
22
|
-
import { resolveTargetPort, _resetTargetCache } from "./edge-target-resolver.ts";
|
|
23
|
-
|
|
24
|
-
/** Delay between attempts while waiting for the server to come back. */
|
|
25
|
-
const CONNECT_RETRY_MS = 250;
|
|
26
|
-
/**
|
|
27
|
-
* How long a client connection waits for a reachable server before giving up.
|
|
28
|
-
* During an upgrade the server is briefly absent; refusing instantly would
|
|
29
|
-
* surface as a broken page rather than a slow one.
|
|
30
|
-
*/
|
|
31
|
-
const CONNECT_WINDOW_MS = 5000;
|
|
32
|
-
|
|
33
|
-
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
|
34
|
-
|
|
35
|
-
/** Resolve once the socket is connected; reject on the first connect error. */
|
|
36
|
-
function connectUpstream(port: number): Promise<net.Socket> {
|
|
37
|
-
return new Promise((resolvePromise, reject) => {
|
|
38
|
-
const upstream = net.connect({
|
|
39
|
-
port,
|
|
40
|
-
host: "127.0.0.1", // never taken from status.json — loopback only
|
|
41
|
-
allowHalfOpen: true,
|
|
42
|
-
});
|
|
43
|
-
const onError = (err: Error) => {
|
|
44
|
-
upstream.destroy();
|
|
45
|
-
reject(err);
|
|
46
|
-
};
|
|
47
|
-
upstream.once("error", onError);
|
|
48
|
-
upstream.once("connect", () => {
|
|
49
|
-
upstream.removeListener("error", onError);
|
|
50
|
-
resolvePromise(upstream);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Largest amount of client data held while waiting for the server. Bounds the
|
|
57
|
-
* memory a slow upload can pin during an upgrade window.
|
|
58
|
-
*/
|
|
59
|
-
const MAX_PENDING_BYTES = 8 * 1024 * 1024;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Pipe one client connection to the server.
|
|
63
|
-
*
|
|
64
|
-
* Resolving the upstream is async, so the first bytes usually arrive before
|
|
65
|
-
* there is anywhere to send them. They must be captured by a `data` listener
|
|
66
|
-
* attached synchronously on this very tick and replayed once the upstream
|
|
67
|
-
* exists.
|
|
68
|
-
*
|
|
69
|
-
* `socket.pause()` is NOT a substitute — verified against Bun 1.3.13: bytes
|
|
70
|
-
* that arrive while paused are lost, and a later `pipe()`/`resume()` does not
|
|
71
|
-
* bring them back. A socket with no `data` listener drops them outright too.
|
|
72
|
-
* Both variants silently swallowed the first request in testing.
|
|
73
|
-
*/
|
|
74
|
-
async function handleConnection(
|
|
75
|
-
client: net.Socket,
|
|
76
|
-
connectWindowMs: number,
|
|
77
|
-
): Promise<void> {
|
|
78
|
-
const pending: Buffer[] = [];
|
|
79
|
-
let pendingBytes = 0;
|
|
80
|
-
let clientEnded = false;
|
|
81
|
-
const onEarlyData = (chunk: Buffer) => {
|
|
82
|
-
pendingBytes += chunk.length;
|
|
83
|
-
if (pendingBytes > MAX_PENDING_BYTES) {
|
|
84
|
-
client.destroy();
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
pending.push(chunk);
|
|
88
|
-
};
|
|
89
|
-
client.on("data", onEarlyData);
|
|
90
|
-
client.once("end", () => { clientEnded = true; });
|
|
91
|
-
|
|
92
|
-
let upstream: net.Socket | null = null;
|
|
93
|
-
let clientGone = false;
|
|
94
|
-
|
|
95
|
-
// A socket error with no listener is an unhandled 'error' event, which would
|
|
96
|
-
// take the whole edge process — and the public port — down with it.
|
|
97
|
-
const teardown = () => {
|
|
98
|
-
upstream?.destroy();
|
|
99
|
-
client.destroy();
|
|
100
|
-
};
|
|
101
|
-
client.on("error", teardown);
|
|
102
|
-
client.once("close", () => { clientGone = true; });
|
|
103
|
-
|
|
104
|
-
const deadline = Date.now() + connectWindowMs;
|
|
105
|
-
while (!clientGone && Date.now() < deadline) {
|
|
106
|
-
const port = resolveTargetPort();
|
|
107
|
-
if (port !== null) {
|
|
108
|
-
try {
|
|
109
|
-
upstream = await connectUpstream(port);
|
|
110
|
-
break;
|
|
111
|
-
} catch {
|
|
112
|
-
// Server not up yet (or moved mid-restart) — re-resolve and retry.
|
|
113
|
-
_resetTargetCache();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
await sleep(CONNECT_RETRY_MS);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (clientGone) return;
|
|
120
|
-
if (!upstream) {
|
|
121
|
-
client.destroy();
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
upstream.on("error", teardown);
|
|
126
|
-
|
|
127
|
-
// Replay what arrived during the connect, then hand both directions to the
|
|
128
|
-
// stream machinery. Removing the listener and piping happen in the same tick,
|
|
129
|
-
// so no chunk can slip through the gap.
|
|
130
|
-
client.off("data", onEarlyData);
|
|
131
|
-
for (const chunk of pending) upstream.write(chunk);
|
|
132
|
-
pending.length = 0;
|
|
133
|
-
|
|
134
|
-
client.pipe(upstream);
|
|
135
|
-
upstream.pipe(client);
|
|
136
|
-
|
|
137
|
-
// The client may have half-closed while we were still connecting.
|
|
138
|
-
if (clientEnded) upstream.end();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export interface EdgeForwarderOptions {
|
|
142
|
-
publicPort: number;
|
|
143
|
-
host?: string;
|
|
144
|
-
/** How long a client waits for a reachable server. Defaults to 5s. */
|
|
145
|
-
connectWindowMs?: number;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Bind the public port and start forwarding. Resolves once listening so the
|
|
150
|
-
* caller can fail fast when the port is unavailable.
|
|
151
|
-
*/
|
|
152
|
-
export function startEdgeForwarder(
|
|
153
|
-
opts: EdgeForwarderOptions,
|
|
154
|
-
): Promise<net.Server> {
|
|
155
|
-
const host = opts.host ?? "0.0.0.0";
|
|
156
|
-
const connectWindowMs = opts.connectWindowMs ?? CONNECT_WINDOW_MS;
|
|
157
|
-
return new Promise((resolvePromise, reject) => {
|
|
158
|
-
// allowHalfOpen keeps the other direction alive when one side sends FIN —
|
|
159
|
-
// long-lived chat WS and SSE streams depend on it.
|
|
160
|
-
const server = net.createServer({ allowHalfOpen: true }, (client) => {
|
|
161
|
-
void handleConnection(client, connectWindowMs);
|
|
162
|
-
});
|
|
163
|
-
server.once("error", reject);
|
|
164
|
-
server.listen(opts.publicPort, host, () => {
|
|
165
|
-
server.removeListener("error", reject);
|
|
166
|
-
resolvePromise(server);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ─── Process entry ─────────────────────────────────────────────────────
|
|
172
|
-
// Mirrors the `__serve__` guard in src/server/index.ts: the supervisor
|
|
173
|
-
// re-invokes the binary as `<bin> __edge__ <publicPort> <host>`.
|
|
174
|
-
if (process.argv.includes("__edge__")) {
|
|
175
|
-
const idx = process.argv.indexOf("__edge__");
|
|
176
|
-
const publicPort = parseInt(process.argv[idx + 1] ?? "", 10);
|
|
177
|
-
const host = process.argv[idx + 2] ?? "0.0.0.0";
|
|
178
|
-
|
|
179
|
-
if (!Number.isInteger(publicPort) || publicPort <= 0 || publicPort > 65535) {
|
|
180
|
-
process.stderr.write(`[edge] Invalid public port: ${process.argv[idx + 1]}\n`);
|
|
181
|
-
process.exit(2);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
await startEdgeForwarder({ publicPort, host });
|
|
186
|
-
process.stderr.write(`[edge] Listening on ${host}:${publicPort}\n`);
|
|
187
|
-
} catch (err) {
|
|
188
|
-
process.stderr.write(`[edge] Failed to bind ${host}:${publicPort}: ${err}\n`);
|
|
189
|
-
process.exit(1);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Edge forwarder — owns the public port and pipes raw TCP to the server's
|
|
3
|
+
* current loopback port.
|
|
4
|
+
*
|
|
5
|
+
* ─── CRITICAL INVARIANT: THIS PROCESS MUST NEVER SPAWN A CHILD ───
|
|
6
|
+
*
|
|
7
|
+
* On Windows a child spawned with fd stdio inherits every inheritable handle,
|
|
8
|
+
* including a listening socket. When such a descendant is orphaned it keeps the
|
|
9
|
+
* socket open, so the port stays in LISTEN under a dead PID and can never be
|
|
10
|
+
* rebound — a "zombie port". The server hits this constantly because it spawns
|
|
11
|
+
* chat/tool/MCP subprocesses; those inherit its listener and wedge its port.
|
|
12
|
+
*
|
|
13
|
+
* The edge exists precisely because it spawns nothing, so its socket cannot be
|
|
14
|
+
* inherited and its port cannot zombie. cloudflared can therefore stay pinned
|
|
15
|
+
* to it forever and the public URL stops rotating. Adding any child-process
|
|
16
|
+
* call to this file reintroduces the exact bug the edge was built to remove.
|
|
17
|
+
*
|
|
18
|
+
* Raw TCP, never HTTP: WebSocket upgrades and SSE streams pass through
|
|
19
|
+
* untouched, and forwarded requests keep the headers cloudflared set.
|
|
20
|
+
*/
|
|
21
|
+
import net from "node:net";
|
|
22
|
+
import { resolveTargetPort, _resetTargetCache } from "./edge-target-resolver.ts";
|
|
23
|
+
|
|
24
|
+
/** Delay between attempts while waiting for the server to come back. */
|
|
25
|
+
const CONNECT_RETRY_MS = 250;
|
|
26
|
+
/**
|
|
27
|
+
* How long a client connection waits for a reachable server before giving up.
|
|
28
|
+
* During an upgrade the server is briefly absent; refusing instantly would
|
|
29
|
+
* surface as a broken page rather than a slow one.
|
|
30
|
+
*/
|
|
31
|
+
const CONNECT_WINDOW_MS = 5000;
|
|
32
|
+
|
|
33
|
+
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
|
34
|
+
|
|
35
|
+
/** Resolve once the socket is connected; reject on the first connect error. */
|
|
36
|
+
function connectUpstream(port: number): Promise<net.Socket> {
|
|
37
|
+
return new Promise((resolvePromise, reject) => {
|
|
38
|
+
const upstream = net.connect({
|
|
39
|
+
port,
|
|
40
|
+
host: "127.0.0.1", // never taken from status.json — loopback only
|
|
41
|
+
allowHalfOpen: true,
|
|
42
|
+
});
|
|
43
|
+
const onError = (err: Error) => {
|
|
44
|
+
upstream.destroy();
|
|
45
|
+
reject(err);
|
|
46
|
+
};
|
|
47
|
+
upstream.once("error", onError);
|
|
48
|
+
upstream.once("connect", () => {
|
|
49
|
+
upstream.removeListener("error", onError);
|
|
50
|
+
resolvePromise(upstream);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Largest amount of client data held while waiting for the server. Bounds the
|
|
57
|
+
* memory a slow upload can pin during an upgrade window.
|
|
58
|
+
*/
|
|
59
|
+
const MAX_PENDING_BYTES = 8 * 1024 * 1024;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Pipe one client connection to the server.
|
|
63
|
+
*
|
|
64
|
+
* Resolving the upstream is async, so the first bytes usually arrive before
|
|
65
|
+
* there is anywhere to send them. They must be captured by a `data` listener
|
|
66
|
+
* attached synchronously on this very tick and replayed once the upstream
|
|
67
|
+
* exists.
|
|
68
|
+
*
|
|
69
|
+
* `socket.pause()` is NOT a substitute — verified against Bun 1.3.13: bytes
|
|
70
|
+
* that arrive while paused are lost, and a later `pipe()`/`resume()` does not
|
|
71
|
+
* bring them back. A socket with no `data` listener drops them outright too.
|
|
72
|
+
* Both variants silently swallowed the first request in testing.
|
|
73
|
+
*/
|
|
74
|
+
async function handleConnection(
|
|
75
|
+
client: net.Socket,
|
|
76
|
+
connectWindowMs: number,
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
const pending: Buffer[] = [];
|
|
79
|
+
let pendingBytes = 0;
|
|
80
|
+
let clientEnded = false;
|
|
81
|
+
const onEarlyData = (chunk: Buffer) => {
|
|
82
|
+
pendingBytes += chunk.length;
|
|
83
|
+
if (pendingBytes > MAX_PENDING_BYTES) {
|
|
84
|
+
client.destroy();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
pending.push(chunk);
|
|
88
|
+
};
|
|
89
|
+
client.on("data", onEarlyData);
|
|
90
|
+
client.once("end", () => { clientEnded = true; });
|
|
91
|
+
|
|
92
|
+
let upstream: net.Socket | null = null;
|
|
93
|
+
let clientGone = false;
|
|
94
|
+
|
|
95
|
+
// A socket error with no listener is an unhandled 'error' event, which would
|
|
96
|
+
// take the whole edge process — and the public port — down with it.
|
|
97
|
+
const teardown = () => {
|
|
98
|
+
upstream?.destroy();
|
|
99
|
+
client.destroy();
|
|
100
|
+
};
|
|
101
|
+
client.on("error", teardown);
|
|
102
|
+
client.once("close", () => { clientGone = true; });
|
|
103
|
+
|
|
104
|
+
const deadline = Date.now() + connectWindowMs;
|
|
105
|
+
while (!clientGone && Date.now() < deadline) {
|
|
106
|
+
const port = resolveTargetPort();
|
|
107
|
+
if (port !== null) {
|
|
108
|
+
try {
|
|
109
|
+
upstream = await connectUpstream(port);
|
|
110
|
+
break;
|
|
111
|
+
} catch {
|
|
112
|
+
// Server not up yet (or moved mid-restart) — re-resolve and retry.
|
|
113
|
+
_resetTargetCache();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
await sleep(CONNECT_RETRY_MS);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (clientGone) return;
|
|
120
|
+
if (!upstream) {
|
|
121
|
+
client.destroy();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
upstream.on("error", teardown);
|
|
126
|
+
|
|
127
|
+
// Replay what arrived during the connect, then hand both directions to the
|
|
128
|
+
// stream machinery. Removing the listener and piping happen in the same tick,
|
|
129
|
+
// so no chunk can slip through the gap.
|
|
130
|
+
client.off("data", onEarlyData);
|
|
131
|
+
for (const chunk of pending) upstream.write(chunk);
|
|
132
|
+
pending.length = 0;
|
|
133
|
+
|
|
134
|
+
client.pipe(upstream);
|
|
135
|
+
upstream.pipe(client);
|
|
136
|
+
|
|
137
|
+
// The client may have half-closed while we were still connecting.
|
|
138
|
+
if (clientEnded) upstream.end();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface EdgeForwarderOptions {
|
|
142
|
+
publicPort: number;
|
|
143
|
+
host?: string;
|
|
144
|
+
/** How long a client waits for a reachable server. Defaults to 5s. */
|
|
145
|
+
connectWindowMs?: number;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Bind the public port and start forwarding. Resolves once listening so the
|
|
150
|
+
* caller can fail fast when the port is unavailable.
|
|
151
|
+
*/
|
|
152
|
+
export function startEdgeForwarder(
|
|
153
|
+
opts: EdgeForwarderOptions,
|
|
154
|
+
): Promise<net.Server> {
|
|
155
|
+
const host = opts.host ?? "0.0.0.0";
|
|
156
|
+
const connectWindowMs = opts.connectWindowMs ?? CONNECT_WINDOW_MS;
|
|
157
|
+
return new Promise((resolvePromise, reject) => {
|
|
158
|
+
// allowHalfOpen keeps the other direction alive when one side sends FIN —
|
|
159
|
+
// long-lived chat WS and SSE streams depend on it.
|
|
160
|
+
const server = net.createServer({ allowHalfOpen: true }, (client) => {
|
|
161
|
+
void handleConnection(client, connectWindowMs);
|
|
162
|
+
});
|
|
163
|
+
server.once("error", reject);
|
|
164
|
+
server.listen(opts.publicPort, host, () => {
|
|
165
|
+
server.removeListener("error", reject);
|
|
166
|
+
resolvePromise(server);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ─── Process entry ─────────────────────────────────────────────────────
|
|
172
|
+
// Mirrors the `__serve__` guard in src/server/index.ts: the supervisor
|
|
173
|
+
// re-invokes the binary as `<bin> __edge__ <publicPort> <host>`.
|
|
174
|
+
if (process.argv.includes("__edge__")) {
|
|
175
|
+
const idx = process.argv.indexOf("__edge__");
|
|
176
|
+
const publicPort = parseInt(process.argv[idx + 1] ?? "", 10);
|
|
177
|
+
const host = process.argv[idx + 2] ?? "0.0.0.0";
|
|
178
|
+
|
|
179
|
+
if (!Number.isInteger(publicPort) || publicPort <= 0 || publicPort > 65535) {
|
|
180
|
+
process.stderr.write(`[edge] Invalid public port: ${process.argv[idx + 1]}\n`);
|
|
181
|
+
process.exit(2);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
await startEdgeForwarder({ publicPort, host });
|
|
186
|
+
process.stderr.write(`[edge] Listening on ${host}:${publicPort}\n`);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
process.stderr.write(`[edge] Failed to bind ${host}:${publicPort}: ${err}\n`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
}
|