bloby-bot 0.30.0 → 0.32.0
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/dist-bloby/assets/angular-html-DxXh-QMA.js +1 -0
- package/dist-bloby/assets/{angular-ts-BJPoZ_vo.js → angular-ts-BNEmshfa.js} +1 -1
- package/dist-bloby/assets/{apl-CyVuPSCb.js → apl-CD5excG6.js} +1 -1
- package/dist-bloby/assets/{astro-CKc3-gwH.js → astro-BsuvMd51.js} +1 -1
- package/dist-bloby/assets/{blade-DMAsVBaV.js → blade-BzCfsa5s.js} +1 -1
- package/dist-bloby/assets/{bloby-CqtSjokc.js → bloby-B1w9ReAR.js} +19 -19
- package/dist-bloby/assets/{bsl-B1qbqNES.js → bsl-BODK--Fo.js} +1 -1
- package/dist-bloby/assets/c-QpHxjkb9.js +1 -0
- package/dist-bloby/assets/{cairo-BDj8wWhy.js → cairo-BwpHIzLA.js} +1 -1
- package/dist-bloby/assets/{cobol-hBjMZW-R.js → cobol-Dvyhsqyz.js} +1 -1
- package/dist-bloby/assets/{coffee-B4OtR3w-.js → coffee-CyaHgmLy.js} +1 -1
- package/dist-bloby/assets/cpp-DlbkFQj0.js +1 -0
- package/dist-bloby/assets/{crystal-x3k4USY-.js → crystal-CR4Yni1K.js} +1 -1
- package/dist-bloby/assets/css-jgrsA6xW.js +1 -0
- package/dist-bloby/assets/{edge-B-9TrlZC.js → edge-CeStCG6d.js} +1 -1
- package/dist-bloby/assets/{elixir-CXCzbj1r.js → elixir-CNfWtFyr.js} +1 -1
- package/dist-bloby/assets/{elm-BdRiwmde.js → elm-WhyRrsYH.js} +1 -1
- package/dist-bloby/assets/{erb-C9tvRzx3.js → erb-BvJkfco6.js} +1 -1
- package/dist-bloby/assets/{erlang-Bc4hQuqa.js → erlang-CjZU-VwD.js} +1 -1
- package/dist-bloby/assets/{fortran-fixed-form-B02FOYI-.js → fortran-fixed-form-CLgNuKMV.js} +1 -1
- package/dist-bloby/assets/{fsharp-DhdR18vN.js → fsharp-kVgJ9XJy.js} +1 -1
- package/dist-bloby/assets/{gdresource-DgnrMPIx.js → gdresource-DDsMuL8p.js} +1 -1
- package/dist-bloby/assets/{git-commit-DGJi7qBD.js → git-commit-BKhxSJdF.js} +1 -1
- package/dist-bloby/assets/{git-rebase-HwDSB2qJ.js → git-rebase-C1GyNmcX.js} +1 -1
- package/dist-bloby/assets/{glimmer-js-B6LF_BMd.js → glimmer-js-Cl3u7vjy.js} +1 -1
- package/dist-bloby/assets/{glimmer-ts-Cn42BUKe.js → glimmer-ts-CtPlRgiA.js} +1 -1
- package/dist-bloby/assets/globals-B1T5ANQV.js +18 -0
- package/dist-bloby/assets/globals-CcIc79IH.css +2 -0
- package/dist-bloby/assets/glsl-Bz5r7Lln.js +1 -0
- package/dist-bloby/assets/graphql-IV9ZCUty.js +1 -0
- package/dist-bloby/assets/{hack-DDEqRjBe.js → hack-XsNdYtzr.js} +1 -1
- package/dist-bloby/assets/haml-BDRqXh7d.js +1 -0
- package/dist-bloby/assets/{handlebars-g9Qe0ao2.js → handlebars-Rv2-mTii.js} +1 -1
- package/dist-bloby/assets/highlighted-body-OFNGDK62-CHkKxiLr.js +1 -0
- package/dist-bloby/assets/html-BkYSbpwH.js +1 -0
- package/dist-bloby/assets/{html-derivative-D-XvNBA6.js → html-derivative-CNiypDIO.js} +1 -1
- package/dist-bloby/assets/{http-qlhghEti.js → http-Vgn8hmbu.js} +1 -1
- package/dist-bloby/assets/{hurl-CHIKfBKk.js → hurl-C_EA75yu.js} +1 -1
- package/dist-bloby/assets/{hxml-adC65L_J.js → hxml-YehGxZ3T.js} +1 -1
- package/dist-bloby/assets/java-div3J5pm.js +1 -0
- package/dist-bloby/assets/javascript-D7sYfeLa.js +1 -0
- package/dist-bloby/assets/{jinja-BHZt0_Dn.js → jinja-BovBDArb.js} +1 -1
- package/dist-bloby/assets/{jison-TqJYWKkW.js → jison-C7UZOdoh.js} +1 -1
- package/dist-bloby/assets/json-DsAnzN7U.js +1 -0
- package/dist-bloby/assets/jsx-CftCCFil.js +1 -0
- package/dist-bloby/assets/jsx-runtime-DsY8nUeV.js +1 -0
- package/dist-bloby/assets/{julia-CW07fy07.js → julia-D8hM3XBr.js} +1 -1
- package/dist-bloby/assets/{just-DBcWo9WY.js → just-CHnwfRRG.js} +1 -1
- package/dist-bloby/assets/{latex-D6lXiPTF.js → latex-Ccu-ZO0T.js} +1 -1
- package/dist-bloby/assets/{liquid-DhYYAQ41.js → liquid-BRbNyfzr.js} +1 -1
- package/dist-bloby/assets/lua-BcwT4KiU.js +1 -0
- package/dist-bloby/assets/{marko-xtrIBdcL.js → marko-Both7s0f.js} +1 -1
- package/dist-bloby/assets/{mdc-DyZVNnwP.js → mdc-7TpRllSI.js} +1 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-LsCge3XG.js +1 -0
- package/dist-bloby/assets/{nextflow-JEyYUlIq.js → nextflow-C2lnptGp.js} +1 -1
- package/dist-bloby/assets/{nginx-CGgm1VOJ.js → nginx-1MGd6YK-.js} +1 -1
- package/dist-bloby/assets/{nim-Br7S817Z.js → nim-CXWhMB6N.js} +1 -1
- package/dist-bloby/assets/onboard-DdL-0meC.js +1 -0
- package/dist-bloby/assets/{perl-DqDX-7VG.js → perl-s-whHxj8.js} +1 -1
- package/dist-bloby/assets/{php-DYSqNNGJ.js → php-KdIqqcNq.js} +1 -1
- package/dist-bloby/assets/{pug-Bob3gNio.js → pug-Cj_1QUAx.js} +1 -1
- package/dist-bloby/assets/{qml-CsMafcqN.js → qml-BQHwZF2t.js} +1 -1
- package/dist-bloby/assets/r-BW3neTZ6.js +1 -0
- package/dist-bloby/assets/{razor-B4PzhaZX.js → razor-D4oLdRr2.js} +1 -1
- package/dist-bloby/assets/regexp-CK2Vecnb.js +1 -0
- package/dist-bloby/assets/rolldown-runtime-C-57s9n3.js +1 -0
- package/dist-bloby/assets/{rst-BXuz-2b8.js → rst-kaCCXG10.js} +1 -1
- package/dist-bloby/assets/{ruby-CXP5_4kq.js → ruby-DIAu88GV.js} +1 -1
- package/dist-bloby/assets/{sas-Cov9PzAD.js → sas-DW2U5bKI.js} +1 -1
- package/dist-bloby/assets/scss-CpUwMEPb.js +1 -0
- package/dist-bloby/assets/{shaderlab-DZ3Lsiak.js → shaderlab-CCgEvKkt.js} +1 -1
- package/dist-bloby/assets/shellscript-BhywzMlr.js +1 -0
- package/dist-bloby/assets/{shellsession-BHLVblBB.js → shellsession-vB5Hy6UU.js} +1 -1
- package/dist-bloby/assets/{soy-e0u3-wIA.js → soy-BNDHXm4e.js} +1 -1
- package/dist-bloby/assets/{sparql-B9c85a_o.js → sparql-DH0hFmAi.js} +1 -1
- package/dist-bloby/assets/sql-D395ukne.js +1 -0
- package/dist-bloby/assets/{stata-B1mLEMrz.js → stata-BHXdpuN3.js} +1 -1
- package/dist-bloby/assets/{surrealql-BTKo2XFY.js → surrealql-eiBkI2Jy.js} +1 -1
- package/dist-bloby/assets/{svelte-B7URZ-wm.js → svelte-DcqzCcP6.js} +1 -1
- package/dist-bloby/assets/{templ-DVRYIgGq.js → templ-DpMCsFaT.js} +1 -1
- package/dist-bloby/assets/{tex-CdJ24HJj.js → tex-B71AZ6Vb.js} +1 -1
- package/dist-bloby/assets/{ts-tags-CCSbelDn.js → ts-tags-CRuJWBGV.js} +1 -1
- package/dist-bloby/assets/tsx-CEFbrBOd.js +1 -0
- package/dist-bloby/assets/{twig-Dn4ruiVl.js → twig-CuSIh_aH.js} +1 -1
- package/dist-bloby/assets/typescript-CV9iMaP7.js +1 -0
- package/dist-bloby/assets/{vue-D19cWHwY.js → vue-YbgnWnT2.js} +1 -1
- package/dist-bloby/assets/{vue-html-_j-KC7Cs.js → vue-html-CXsio3-X.js} +1 -1
- package/dist-bloby/assets/{vue-vine-BC03MN6c.js → vue-vine-C8pVogU0.js} +1 -1
- package/dist-bloby/assets/xml-Zmzpltp0.js +1 -0
- package/dist-bloby/assets/{xsl-DR-zOeBm.js → xsl-CqzL2w2F.js} +1 -1
- package/dist-bloby/assets/yaml-Dc_auW1I.js +1 -0
- package/dist-bloby/bloby.html +5 -4
- package/dist-bloby/onboard.html +5 -4
- package/package.json +1 -1
- package/supervisor/chat/OnboardWizard.tsx +278 -56
- package/supervisor/index.ts +1 -1
- package/worker/codex-auth.ts +363 -99
- package/worker/index.ts +30 -4
- package/dist-bloby/assets/angular-html-olSuI25H.js +0 -1
- package/dist-bloby/assets/c-BvB8CVo8.js +0 -1
- package/dist-bloby/assets/cpp-BblbpnyR.js +0 -1
- package/dist-bloby/assets/css-zY4NE9yA.js +0 -1
- package/dist-bloby/assets/globals-LpXKrQgt.css +0 -2
- package/dist-bloby/assets/globals-zKQhzQOX.js +0 -18
- package/dist-bloby/assets/glsl-CEMf-THb.js +0 -1
- package/dist-bloby/assets/graphql-dBCd2Czl.js +0 -1
- package/dist-bloby/assets/haml-Ck5pVAEG.js +0 -1
- package/dist-bloby/assets/highlighted-body-OFNGDK62-B0W8hCx-.js +0 -1
- package/dist-bloby/assets/html-CzX0w7K_.js +0 -1
- package/dist-bloby/assets/java-BqKEu7zh.js +0 -1
- package/dist-bloby/assets/javascript-CzjRtS1s.js +0 -1
- package/dist-bloby/assets/json-CdFmZMJc.js +0 -1
- package/dist-bloby/assets/jsx-BL6Wh6Qw.js +0 -1
- package/dist-bloby/assets/jsx-runtime-C0W9Wf2W.js +0 -1
- package/dist-bloby/assets/lua-B4ezzssg.js +0 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-Dr8I7wwH.js +0 -1
- package/dist-bloby/assets/onboard-C1yXK8uT.js +0 -1
- package/dist-bloby/assets/r-CGji9_vM.js +0 -1
- package/dist-bloby/assets/regexp-CvWG4lI-.js +0 -1
- package/dist-bloby/assets/scss-Efq7Dmbs.js +0 -1
- package/dist-bloby/assets/shellscript-BbEstezf.js +0 -1
- package/dist-bloby/assets/sql-CB6kO6Km.js +0 -1
- package/dist-bloby/assets/tsx-DrzBggF8.js +0 -1
- package/dist-bloby/assets/typescript-COZIw7xM.js +0 -1
- package/dist-bloby/assets/xml-BlDEvPia.js +0 -1
- package/dist-bloby/assets/yaml-iUXljnLs.js +0 -1
- /package/dist-bloby/assets/{abap-smLpETzL.js → abap--vzi7Rxy.js} +0 -0
- /package/dist-bloby/assets/{actionscript-3-o-aRvjY5.js → actionscript-3-CV21uODD.js} +0 -0
- /package/dist-bloby/assets/{ada-D5RRX1i4.js → ada-DpXSEmbw.js} +0 -0
- /package/dist-bloby/assets/{andromeeda-N4z3YzmR.js → andromeeda-C1V0Cb0M.js} +0 -0
- /package/dist-bloby/assets/{apache-DttKlSqg.js → apache-CRmVjs8c.js} +0 -0
- /package/dist-bloby/assets/{apex-DL7j-a2n.js → apex-DIIc4r7E.js} +0 -0
- /package/dist-bloby/assets/{applescript-DCbL_2FX.js → applescript-DMX6NGuU.js} +0 -0
- /package/dist-bloby/assets/{ara-DqheWJCe.js → ara-3SArX2Zn.js} +0 -0
- /package/dist-bloby/assets/{asciidoc-BH2sf2K4.js → asciidoc-CnVFjb7X.js} +0 -0
- /package/dist-bloby/assets/{asm-rfjOMz3U.js → asm-Cb-CgaBD.js} +0 -0
- /package/dist-bloby/assets/{aurora-x-CND-FqEb.js → aurora-x-CjvoFyi0.js} +0 -0
- /package/dist-bloby/assets/{awk-CMV5n9Z7.js → awk-BYjsWVhV.js} +0 -0
- /package/dist-bloby/assets/{ayu-dark-on7xzq_B.js → ayu-dark-C4UVdT_g.js} +0 -0
- /package/dist-bloby/assets/{ayu-light-DnGeGGc2.js → ayu-light-CFJ-dST-.js} +0 -0
- /package/dist-bloby/assets/{ayu-mirage-DG3LlYC_.js → ayu-mirage-BxM9D2Mi.js} +0 -0
- /package/dist-bloby/assets/{ballerina-BjMqJjlr.js → ballerina-BsKCUtAm.js} +0 -0
- /package/dist-bloby/assets/{bat-BaVbo_qw.js → bat-CJlQOahT.js} +0 -0
- /package/dist-bloby/assets/{beancount-DBt5Mbc_.js → beancount-Cyf6Xlzd.js} +0 -0
- /package/dist-bloby/assets/{berry-Cyjuxiss.js → berry-DHYmFnza.js} +0 -0
- /package/dist-bloby/assets/{bibtex-BV_0nsPq.js → bibtex-BUB9btZd.js} +0 -0
- /package/dist-bloby/assets/{bicep-C2gEwu4J.js → bicep-CNVX4dQj.js} +0 -0
- /package/dist-bloby/assets/{bird2-BRyaEJd0.js → bird2-LZP25z1s.js} +0 -0
- /package/dist-bloby/assets/{c3-DTTbp5N2.js → c3-BI41OB2W.js} +0 -0
- /package/dist-bloby/assets/{cadence-CPz83cmI.js → cadence-BDnzkZFt.js} +0 -0
- /package/dist-bloby/assets/{catppuccin-frappe-Dr22sraq.js → catppuccin-frappe-DpT1lCYX.js} +0 -0
- /package/dist-bloby/assets/{catppuccin-latte-C57EeX8c.js → catppuccin-latte-qMMse1WJ.js} +0 -0
- /package/dist-bloby/assets/{catppuccin-macchiato-CpheI4uD.js → catppuccin-macchiato-DMu0Ac9B.js} +0 -0
- /package/dist-bloby/assets/{catppuccin-mocha-D8Lmdks_.js → catppuccin-mocha-DicTaD9V.js} +0 -0
- /package/dist-bloby/assets/{clarity-CFJ2Yc3q.js → clarity-CPz-yzAn.js} +0 -0
- /package/dist-bloby/assets/{clojure-6R01QgJC.js → clojure-BxJLFKTj.js} +0 -0
- /package/dist-bloby/assets/{cmake-D5rSbMir.js → cmake-BmC4o4J9.js} +0 -0
- /package/dist-bloby/assets/{codeowners-_3A-ClkN.js → codeowners-BPHDuybI.js} +0 -0
- /package/dist-bloby/assets/{codeql-DlIhJTR7.js → codeql-DYWyWzRY.js} +0 -0
- /package/dist-bloby/assets/{common-lisp-BvQzz173.js → common-lisp-CsDdrwfa.js} +0 -0
- /package/dist-bloby/assets/{coq-DTNXReIC.js → coq-BZNwxllS.js} +0 -0
- /package/dist-bloby/assets/{csharp-BDKQY1K9.js → csharp-BLhQzhUA.js} +0 -0
- /package/dist-bloby/assets/{csv-DNUpVBxl.js → csv-DPc9UZFt.js} +0 -0
- /package/dist-bloby/assets/{cue-DDdBc2s3.js → cue-Bat8Mt8Y.js} +0 -0
- /package/dist-bloby/assets/{cypher-CguaznO2.js → cypher-CTnWkM4Y.js} +0 -0
- /package/dist-bloby/assets/{d-CHcoyjv3.js → d-CccbtpLU.js} +0 -0
- /package/dist-bloby/assets/{dark-plus-CqeW_0kH.js → dark-plus-CKh7uIvz.js} +0 -0
- /package/dist-bloby/assets/{dart-RM3aRphk.js → dart-SbRHwU1n.js} +0 -0
- /package/dist-bloby/assets/{dax-nbnY1d79.js → dax-vVKSTwd9.js} +0 -0
- /package/dist-bloby/assets/{desktop-BD76cvxT.js → desktop-rdWGepy4.js} +0 -0
- /package/dist-bloby/assets/{diff-CdkWtnkL.js → diff-G5H-0DNT.js} +0 -0
- /package/dist-bloby/assets/{docker-ZyPHc6zB.js → docker-CC20slQp.js} +0 -0
- /package/dist-bloby/assets/{dotenv-BdJZEwA6.js → dotenv-C36c6TdP.js} +0 -0
- /package/dist-bloby/assets/{dracula-CtqCPLGa.js → dracula-nNMQZYa7.js} +0 -0
- /package/dist-bloby/assets/{dracula-soft-DmBpwRAy.js → dracula-soft-BPmUsSlJ.js} +0 -0
- /package/dist-bloby/assets/{dream-maker-BJL4qlg3.js → dream-maker-DleGc9Hy.js} +0 -0
- /package/dist-bloby/assets/{emacs-lisp-_LyYa2Ky.js → emacs-lisp-D_QlcMHs.js} +0 -0
- /package/dist-bloby/assets/{everforest-dark-CrbyKk4n.js → everforest-dark-FkVvIMUl.js} +0 -0
- /package/dist-bloby/assets/{everforest-light-DRbSh8Tm.js → everforest-light-d3V1wTAd.js} +0 -0
- /package/dist-bloby/assets/{fennel-CC2BkRsS.js → fennel-BEssPROc.js} +0 -0
- /package/dist-bloby/assets/{fish-D2ZCzqcE.js → fish-Cz5yLEyJ.js} +0 -0
- /package/dist-bloby/assets/{fluent-DKAm3m7q.js → fluent-TGO8KajN.js} +0 -0
- /package/dist-bloby/assets/{fortran-free-form-BPTf0lbT.js → fortran-free-form-CHQXX5JB.js} +0 -0
- /package/dist-bloby/assets/{gdscript-CsadCSaZ.js → gdscript-DBkVGsC6.js} +0 -0
- /package/dist-bloby/assets/{gdshader-PfnN_8tR.js → gdshader-CWQhZP7Q.js} +0 -0
- /package/dist-bloby/assets/{genie-Bj-orPAV.js → genie-7iw14YxB.js} +0 -0
- /package/dist-bloby/assets/{gherkin-COVWpJ-Q.js → gherkin-D4AlAQSH.js} +0 -0
- /package/dist-bloby/assets/{github-dark-ipGuFGYC.js → github-dark-CpBni1SQ.js} +0 -0
- /package/dist-bloby/assets/{github-dark-default-DX3IG_X0.js → github-dark-default-Cr5Q59Ad.js} +0 -0
- /package/dist-bloby/assets/{github-dark-dimmed-CH6p_7ez.js → github-dark-dimmed-WEORr92a.js} +0 -0
- /package/dist-bloby/assets/{github-dark-high-contrast-Bg2sSao5.js → github-dark-high-contrast-uM2plAzl.js} +0 -0
- /package/dist-bloby/assets/{github-light-BxjqOQl0.js → github-light-BROm54vS.js} +0 -0
- /package/dist-bloby/assets/{github-light-default-DwpDd1IQ.js → github-light-default-jSwgX00f.js} +0 -0
- /package/dist-bloby/assets/{github-light-high-contrast-C0QeixPf.js → github-light-high-contrast-Bp9ESXtp.js} +0 -0
- /package/dist-bloby/assets/{gleam-BF2NigGj.js → gleam-D1LXnIj0.js} +0 -0
- /package/dist-bloby/assets/{gn-CMIt9roj.js → gn-CReOiE5m.js} +0 -0
- /package/dist-bloby/assets/{gnuplot-DgWlRTEj.js → gnuplot-DufViamc.js} +0 -0
- /package/dist-bloby/assets/{go-DLnOLj8q.js → go-DC_Zm44P.js} +0 -0
- /package/dist-bloby/assets/{groovy-B9qLWIkE.js → groovy-DEGDVBi0.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-dark-hard-BIMX9ePb.js → gruvbox-dark-hard-C-zANgxR.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-dark-medium-DxuwyVzM.js → gruvbox-dark-medium-DY7Z6TBK.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-dark-soft-ba2fjht0.js → gruvbox-dark-soft-Bpj6owGh.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-light-hard-DAJK2PqC.js → gruvbox-light-hard-DVwTvHam.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-light-medium-WRifDAJD.js → gruvbox-light-medium-98PeoD5Y.js} +0 -0
- /package/dist-bloby/assets/{gruvbox-light-soft-B0dBOoVB.js → gruvbox-light-soft-BHI2PZTB.js} +0 -0
- /package/dist-bloby/assets/{haskell-BaGpmm_c.js → haskell-B-K-GoPf.js} +0 -0
- /package/dist-bloby/assets/{haxe-DfXTCEOz.js → haxe-md5t_Y_E.js} +0 -0
- /package/dist-bloby/assets/{hcl-CbCtpSbi.js → hcl-qSvp9jTg.js} +0 -0
- /package/dist-bloby/assets/{hjson-_4-w-pHU.js → hjson-BNeV6JDA.js} +0 -0
- /package/dist-bloby/assets/{hlsl-DpuYn7pp.js → hlsl-CFf5czm3.js} +0 -0
- /package/dist-bloby/assets/{horizon-C5RtD1fY.js → horizon-C4a2pCDo.js} +0 -0
- /package/dist-bloby/assets/{horizon-bright-pEOice34.js → horizon-bright-Bgpx-0aF.js} +0 -0
- /package/dist-bloby/assets/{houston-A0zg9vNP.js → houston-BZHNDhe5.js} +0 -0
- /package/dist-bloby/assets/{hy-t9zDXBje.js → hy-hI-CUgFt.js} +0 -0
- /package/dist-bloby/assets/{imba-Bxu-TDfw.js → imba-Dr5pZl3x.js} +0 -0
- /package/dist-bloby/assets/{ini-D-v34c8N.js → ini-KxzJ-qxg.js} +0 -0
- /package/dist-bloby/assets/{json5-D0XL1D5m.js → json5-SRM7tKmT.js} +0 -0
- /package/dist-bloby/assets/{jsonc-BBgf3TX3.js → jsonc-Cix1XnqC.js} +0 -0
- /package/dist-bloby/assets/{jsonl-KrKLbtB7.js → jsonl-BzKwo-fD.js} +0 -0
- /package/dist-bloby/assets/{jsonnet-B2ZwWMOt.js → jsonnet-DaiLv8or.js} +0 -0
- /package/dist-bloby/assets/{jssm-ByRpI9-B.js → jssm-B1pV58QJ.js} +0 -0
- /package/dist-bloby/assets/{kanagawa-dragon-CtPmcCMp.js → kanagawa-dragon-BihvT_N-.js} +0 -0
- /package/dist-bloby/assets/{kanagawa-lotus-DpOXEGCa.js → kanagawa-lotus-DQN_bzSt.js} +0 -0
- /package/dist-bloby/assets/{kanagawa-wave-CLVCyc-n.js → kanagawa-wave-Bvz_F3hD.js} +0 -0
- /package/dist-bloby/assets/{kdl-6FPPEH4H.js → kdl-DupMG4Bk.js} +0 -0
- /package/dist-bloby/assets/{kotlin-D4L3Nd2D.js → kotlin-rOGI_fXV.js} +0 -0
- /package/dist-bloby/assets/{kusto-D-mmc07O.js → kusto-CHXnQR8L.js} +0 -0
- /package/dist-bloby/assets/{laserwave-7fEj4XGb.js → laserwave-CPMyzJF3.js} +0 -0
- /package/dist-bloby/assets/{lean-BMVMuP2E.js → lean-B76KugVy.js} +0 -0
- /package/dist-bloby/assets/{less-C95PyOu0.js → less-DwUMKQAG.js} +0 -0
- /package/dist-bloby/assets/{light-plus-DHI2dh3p.js → light-plus-C6sdUQiS.js} +0 -0
- /package/dist-bloby/assets/{llvm-Dy3qORTl.js → llvm-DumY6MCH.js} +0 -0
- /package/dist-bloby/assets/{log-BQop7fzg.js → log-DdP6k-FU.js} +0 -0
- /package/dist-bloby/assets/{logo-DKtnYmrp.js → logo-Cx0gX691.js} +0 -0
- /package/dist-bloby/assets/{luau-Dha4KG0q.js → luau-CI4wJBxI.js} +0 -0
- /package/dist-bloby/assets/{make-DfmS6buu.js → make-BlyBJiAs.js} +0 -0
- /package/dist-bloby/assets/{markdown-BaI9LyM4.js → markdown-BFgBvytj.js} +0 -0
- /package/dist-bloby/assets/{material-theme-Dm6ETY8i.js → material-theme-CyGvAAeY.js} +0 -0
- /package/dist-bloby/assets/{material-theme-darker-BeyjmM5Z.js → material-theme-darker-DJAOSarR.js} +0 -0
- /package/dist-bloby/assets/{material-theme-lighter-CCOYYzKL.js → material-theme-lighter-Cb7t96j2.js} +0 -0
- /package/dist-bloby/assets/{material-theme-ocean-CUtPiiX3.js → material-theme-ocean-EZZ55_HD.js} +0 -0
- /package/dist-bloby/assets/{material-theme-palenight-2L4zMwIM.js → material-theme-palenight-DtmMSfya.js} +0 -0
- /package/dist-bloby/assets/{matlab-BT79Cq_j.js → matlab-BFLobVcp.js} +0 -0
- /package/dist-bloby/assets/{mdx-CxGBwLNt.js → mdx-Baux4qlv.js} +0 -0
- /package/dist-bloby/assets/{mermaid-DLf3axBN.js → mermaid-DHr7T0Rt.js} +0 -0
- /package/dist-bloby/assets/{min-dark-B8TUPGHg.js → min-dark-C9N1U4-e.js} +0 -0
- /package/dist-bloby/assets/{min-light-BDOoBxcA.js → min-light-Ce9oxBvH.js} +0 -0
- /package/dist-bloby/assets/{mipsasm-DXuU_0cI.js → mipsasm-Cgb1v7yV.js} +0 -0
- /package/dist-bloby/assets/{mojo-1Omp2pIo.js → mojo-BnTBKscO.js} +0 -0
- /package/dist-bloby/assets/{monokai-E_VBmXGZ.js → monokai-BGD_YBH-.js} +0 -0
- /package/dist-bloby/assets/{moonbit-DZzq699o.js → moonbit-HXw0ZM4h.js} +0 -0
- /package/dist-bloby/assets/{move-DxDAOJVd.js → move-DG2efXqI.js} +0 -0
- /package/dist-bloby/assets/{narrat-CxDcPPb9.js → narrat-BSasSB5t.js} +0 -0
- /package/dist-bloby/assets/{nextflow-groovy-wvmJO4hi.js → nextflow-groovy-DXLl8k8E.js} +0 -0
- /package/dist-bloby/assets/{night-owl-DefhalNX.js → night-owl-DxqNTXDa.js} +0 -0
- /package/dist-bloby/assets/{night-owl-light-byb3AbEn.js → night-owl-light-MPn8GCyh.js} +0 -0
- /package/dist-bloby/assets/{nix-DsFTDHWT.js → nix-BpnttlWr.js} +0 -0
- /package/dist-bloby/assets/{nord-D5rQzHT-.js → nord-Mt6M_qHE.js} +0 -0
- /package/dist-bloby/assets/{nushell-BQ_rO0AM.js → nushell-CS7Mvg-G.js} +0 -0
- /package/dist-bloby/assets/{objective-c-BMq6JT_m.js → objective-c-U4EuJXJs.js} +0 -0
- /package/dist-bloby/assets/{objective-cpp-DRwojuGv.js → objective-cpp-CE_PrXRW.js} +0 -0
- /package/dist-bloby/assets/{ocaml-e4_gKO6E.js → ocaml-ZsxDKzyv.js} +0 -0
- /package/dist-bloby/assets/{odin-mdTPwYOg.js → odin-CDoDiNYU.js} +0 -0
- /package/dist-bloby/assets/{one-dark-pro-DxXww9jg.js → one-dark-pro-B9P_I1yh.js} +0 -0
- /package/dist-bloby/assets/{one-light-D9c03w7t.js → one-light-Cv3j6GXq.js} +0 -0
- /package/dist-bloby/assets/{openscad-D2aTdNfr.js → openscad-CfJwW9dY.js} +0 -0
- /package/dist-bloby/assets/{pascal-D4n_G8vj.js → pascal-CjE0UTC7.js} +0 -0
- /package/dist-bloby/assets/{pkl-DcjhAp0L.js → pkl-BN6EkHr9.js} +0 -0
- /package/dist-bloby/assets/{plastic-uOsw7z1x.js → plastic-BCnZnfMk.js} +0 -0
- /package/dist-bloby/assets/{plsql-BSy3Ag0J.js → plsql-1LW-CqWM.js} +0 -0
- /package/dist-bloby/assets/{po-Be96RYkA.js → po-Cf5hRC9x.js} +0 -0
- /package/dist-bloby/assets/{poimandres-CyO4HORD.js → poimandres-B_zC30Vt.js} +0 -0
- /package/dist-bloby/assets/{polar-BmhMKWum.js → polar-S6fWkEw8.js} +0 -0
- /package/dist-bloby/assets/{postcss-BTQso3H9.js → postcss-cZXfRCsF.js} +0 -0
- /package/dist-bloby/assets/{powerquery-DVyQv3M2.js → powerquery-CoRQQdNP.js} +0 -0
- /package/dist-bloby/assets/{powershell-BmtCGJVD.js → powershell-B2VxwRch.js} +0 -0
- /package/dist-bloby/assets/{prisma-CCFA9rEj.js → prisma-sLrt38jj.js} +0 -0
- /package/dist-bloby/assets/{prolog-DWGEEo78.js → prolog-CL99toUJ.js} +0 -0
- /package/dist-bloby/assets/{proto-C3eop1kM.js → proto-CtiBQJNn.js} +0 -0
- /package/dist-bloby/assets/{puppet-C0_7Nv5A.js → puppet-BlbpxWq2.js} +0 -0
- /package/dist-bloby/assets/{purescript-Bv-B8yRw.js → purescript-DPcVkoDV.js} +0 -0
- /package/dist-bloby/assets/{python-CKg5r0C3.js → python-BLpCXkJ6.js} +0 -0
- /package/dist-bloby/assets/{qmldir-Cqfb4Lox.js → qmldir-BcwbwUc8.js} +0 -0
- /package/dist-bloby/assets/{qss-Csho9BH8.js → qss-erDfnnzG.js} +0 -0
- /package/dist-bloby/assets/{racket-D8-uWeQH.js → racket-Dch6VQku.js} +0 -0
- /package/dist-bloby/assets/{raku-Cj4JSa8p.js → raku-Db8mfsiE.js} +0 -0
- /package/dist-bloby/assets/{red-z4H4llUY.js → red-DWyyM82l.js} +0 -0
- /package/dist-bloby/assets/{reg-DXGFiJSl.js → reg-3F9yjO5J.js} +0 -0
- /package/dist-bloby/assets/{rel-CunnVTBK.js → rel-CQq8nxxL.js} +0 -0
- /package/dist-bloby/assets/{riscv-C8BcOCkS.js → riscv-CsUwotvK.js} +0 -0
- /package/dist-bloby/assets/{ron-DiDyR9oa.js → ron-BwlS4rWu.js} +0 -0
- /package/dist-bloby/assets/{rose-pine-BADquuIH.js → rose-pine-DEj8gOox.js} +0 -0
- /package/dist-bloby/assets/{rose-pine-dawn-BLcEeBoh.js → rose-pine-dawn-DjarqQ2I.js} +0 -0
- /package/dist-bloby/assets/{rose-pine-moon-BK_tLY1Y.js → rose-pine-moon-D7ffkR_D.js} +0 -0
- /package/dist-bloby/assets/{rosmsg-CHmL1Uyj.js → rosmsg-BmwwVMq5.js} +0 -0
- /package/dist-bloby/assets/{rust-DjJFInu3.js → rust-DsIgDjpj.js} +0 -0
- /package/dist-bloby/assets/{sass-D3xZ5o-v.js → sass-CkIFK_bT.js} +0 -0
- /package/dist-bloby/assets/{scala-B0IRml5w.js → scala-C0TSxhxD.js} +0 -0
- /package/dist-bloby/assets/{scheme-BhwcV3Av.js → scheme-e-5nJ58U.js} +0 -0
- /package/dist-bloby/assets/{sdbl-BmWYR-pI.js → sdbl-DOe8Nral.js} +0 -0
- /package/dist-bloby/assets/{slack-dark-DOnVms5P.js → slack-dark-CClHvLju.js} +0 -0
- /package/dist-bloby/assets/{slack-ochin-DcRTft4q.js → slack-ochin-DwCpSVBI.js} +0 -0
- /package/dist-bloby/assets/{smalltalk-DVQuUMII.js → smalltalk-fjkC4HKG.js} +0 -0
- /package/dist-bloby/assets/{snazzy-light-x9CLJ1W9.js → snazzy-light-2nD216w0.js} +0 -0
- /package/dist-bloby/assets/{solarized-dark-BB1sh-pe.js → solarized-dark-BkxMSETv.js} +0 -0
- /package/dist-bloby/assets/{solarized-light-9-RPS998.js → solarized-light-BScqQ1C4.js} +0 -0
- /package/dist-bloby/assets/{solidity-gQ4WXILB.js → solidity-DbOxJfAY.js} +0 -0
- /package/dist-bloby/assets/{splunk-OB48_RcD.js → splunk-BW0l10cw.js} +0 -0
- /package/dist-bloby/assets/{ssh-config-DA9YMRGV.js → ssh-config-XN7RWvZy.js} +0 -0
- /package/dist-bloby/assets/{stylus-sKwvsUaC.js → stylus-D69is74S.js} +0 -0
- /package/dist-bloby/assets/{swift-C72NbAtg.js → swift-CqNHAbQB.js} +0 -0
- /package/dist-bloby/assets/{synthwave-84-eJ9uRN_S.js → synthwave-84-Ct3Np89a.js} +0 -0
- /package/dist-bloby/assets/{system-verilog-CnWMF7Nq.js → system-verilog-CHbvBf8h.js} +0 -0
- /package/dist-bloby/assets/{systemd-DMzItW5N.js → systemd-BBC3Z_R4.js} +0 -0
- /package/dist-bloby/assets/{talonscript-DopQCWDL.js → talonscript-DhYQB2ic.js} +0 -0
- /package/dist-bloby/assets/{tasl-C28SYKbq.js → tasl-CNtai3BH.js} +0 -0
- /package/dist-bloby/assets/{tcl-DHq7zmoF.js → tcl-DFzyQSXW.js} +0 -0
- /package/dist-bloby/assets/{terraform-CogS1YKX.js → terraform-BijD6Khb.js} +0 -0
- /package/dist-bloby/assets/{tokyo-night-B9N7LyrF.js → tokyo-night-Dd5BGAxh.js} +0 -0
- /package/dist-bloby/assets/{toml-BH_iPsgK.js → toml-DZofdujH.js} +0 -0
- /package/dist-bloby/assets/{tsv-BIkdBZX1.js → tsv-DOp6g7sz.js} +0 -0
- /package/dist-bloby/assets/{turtle-CqNXyJWZ.js → turtle-BKcRDROw.js} +0 -0
- /package/dist-bloby/assets/{typespec-CQ9LYD_e.js → typespec-Mmt3-2Cw.js} +0 -0
- /package/dist-bloby/assets/{typst-T-Fsk-Sv.js → typst-CndOdNo_.js} +0 -0
- /package/dist-bloby/assets/{v-BhMEOw9x.js → v-DjlZIA0C.js} +0 -0
- /package/dist-bloby/assets/{vala-DzajMnwt.js → vala-C5Nm5NXo.js} +0 -0
- /package/dist-bloby/assets/{vb-7Xr8dEYW.js → vb-zZeWbE2_.js} +0 -0
- /package/dist-bloby/assets/{verilog-AvXtwZir.js → verilog-CyZIVfoz.js} +0 -0
- /package/dist-bloby/assets/{vesper-CtgQQ2sf.js → vesper-B0BMGbco.js} +0 -0
- /package/dist-bloby/assets/{vhdl-BHu0zg1P.js → vhdl-DH1mJdjZ.js} +0 -0
- /package/dist-bloby/assets/{viml-Di0QpLfC.js → viml-e-oP1x-l.js} +0 -0
- /package/dist-bloby/assets/{vitesse-black-jXdfyqgD.js → vitesse-black-BRAUsA4Q.js} +0 -0
- /package/dist-bloby/assets/{vitesse-dark-B88PxG1r.js → vitesse-dark-Dyg71HnT.js} +0 -0
- /package/dist-bloby/assets/{vitesse-light-BXxZh2iV.js → vitesse-light-BJKZKqvd.js} +0 -0
- /package/dist-bloby/assets/{vyper-C3R5yXgx.js → vyper-BRPzCrki.js} +0 -0
- /package/dist-bloby/assets/{wasm-Chsuwt1A.js → wasm-DYMpDie-.js} +0 -0
- /package/dist-bloby/assets/{wasm-CEUrWlVz.js → wasm-Drz0Uqci.js} +0 -0
- /package/dist-bloby/assets/{wenyan-BonVcr2i.js → wenyan-BiJ0NePu.js} +0 -0
- /package/dist-bloby/assets/{wgsl-D59WYmNq.js → wgsl-CNe_V6SG.js} +0 -0
- /package/dist-bloby/assets/{wikitext-ariTI2Wk.js → wikitext-DZrjZKWn.js} +0 -0
- /package/dist-bloby/assets/{wit-EA4fa3Dt.js → wit-BUTESHa8.js} +0 -0
- /package/dist-bloby/assets/{wolfram-DDp7LhyU.js → wolfram-COEZldPx.js} +0 -0
- /package/dist-bloby/assets/{zenscript-4WaROUyc.js → zenscript-DThCxjUC.js} +0 -0
- /package/dist-bloby/assets/{zig-CJoLJGwV.js → zig-Bu6QWpR2.js} +0 -0
package/worker/codex-auth.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Codex OAuth PKCE flow for ChatGPT Plus/Pro subscription authentication.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Paste-back flow (no local HTTP callback) — the dashboard is typically
|
|
5
|
+
* served from a Pi via Cloudflare tunnel, so a browser-side `localhost:1455`
|
|
6
|
+
* callback can't reach the host running this code. We send the user through
|
|
7
|
+
* OpenAI's auth page; their browser redirects to the (unreachable) callback
|
|
8
|
+
* URL but its URL bar contains the `code`. The user pastes that URL or code
|
|
9
|
+
* back into the wizard, which POSTs it here for token exchange.
|
|
10
|
+
*
|
|
5
11
|
* Credentials are stored in ~/.codex/auth.json in the same shape Codex CLI
|
|
6
12
|
* itself writes, so a spawned `codex app-server` process can use them directly.
|
|
7
13
|
*
|
|
@@ -20,7 +26,6 @@
|
|
|
20
26
|
*/
|
|
21
27
|
|
|
22
28
|
import crypto from 'crypto';
|
|
23
|
-
import http from 'http';
|
|
24
29
|
import fs from 'fs';
|
|
25
30
|
import path from 'path';
|
|
26
31
|
import os from 'os';
|
|
@@ -32,7 +37,6 @@ const OAUTH_CONFIG = {
|
|
|
32
37
|
REDIRECT_URI: 'http://localhost:1455/auth/callback',
|
|
33
38
|
CLIENT_ID: 'app_EMoamEEZ73f0CkXaXp7hrann',
|
|
34
39
|
SCOPES: 'openid profile email offline_access',
|
|
35
|
-
PORT: 1455,
|
|
36
40
|
};
|
|
37
41
|
|
|
38
42
|
const AUTH_DIR = path.join(os.homedir(), '.codex');
|
|
@@ -44,7 +48,6 @@ const REFRESH_LEEWAY_MS = 5 * 60 * 1000;
|
|
|
44
48
|
|
|
45
49
|
let codeVerifier: string | null = null;
|
|
46
50
|
let oauthState: string | null = null;
|
|
47
|
-
let callbackServer: http.Server | null = null;
|
|
48
51
|
|
|
49
52
|
interface AuthDotJson {
|
|
50
53
|
OPENAI_API_KEY: string | null;
|
|
@@ -87,7 +90,7 @@ function decodeJwt(token: string): Record<string, any> | null {
|
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
/** Read the JWT `exp` claim as a Unix epoch (
|
|
93
|
+
/** Read the JWT `exp` claim as a Unix epoch (ms). Null if missing/invalid. */
|
|
91
94
|
function jwtExpiryMs(token: string): number | null {
|
|
92
95
|
const payload = decodeJwt(token);
|
|
93
96
|
if (!payload || typeof payload.exp !== 'number') return null;
|
|
@@ -104,7 +107,6 @@ function extractAccountId(idToken: string): string | undefined {
|
|
|
104
107
|
/** One-shot migration from the old `codedeck-auth.json` layout (pre-codex-native). */
|
|
105
108
|
function migrateLegacyFile(): void {
|
|
106
109
|
if (fs.existsSync(AUTH_FILE)) {
|
|
107
|
-
// If auth.json already has chatgpt tokens, nothing to do.
|
|
108
110
|
const existing = readAuthFile();
|
|
109
111
|
if (existing?.tokens?.refresh_token) return;
|
|
110
112
|
}
|
|
@@ -156,46 +158,6 @@ function storeTokens(tokens: { access_token: string; refresh_token?: string; id_
|
|
|
156
158
|
writeAuthFile(next);
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
async function exchangeCode(code: string): Promise<{ success: boolean; error?: string }> {
|
|
160
|
-
if (!codeVerifier) {
|
|
161
|
-
return { success: false, error: 'No code verifier — OAuth flow was not started.' };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const payload = new URLSearchParams({
|
|
166
|
-
grant_type: 'authorization_code',
|
|
167
|
-
client_id: OAUTH_CONFIG.CLIENT_ID,
|
|
168
|
-
code,
|
|
169
|
-
redirect_uri: OAUTH_CONFIG.REDIRECT_URI,
|
|
170
|
-
code_verifier: codeVerifier,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {
|
|
174
|
-
method: 'POST',
|
|
175
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
176
|
-
body: payload.toString(),
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
if (!response.ok) {
|
|
180
|
-
return { success: false, error: `Authentication failed (${response.status}). Please try again.` };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const tokens = await response.json();
|
|
184
|
-
if (!tokens.access_token) {
|
|
185
|
-
return { success: false, error: 'OAuth response missing access_token.' };
|
|
186
|
-
}
|
|
187
|
-
storeTokens(tokens);
|
|
188
|
-
codeVerifier = null;
|
|
189
|
-
oauthState = null;
|
|
190
|
-
log.ok('Codex credentials stored');
|
|
191
|
-
// Clean up the legacy file on first successful new auth.
|
|
192
|
-
try { fs.unlinkSync(LEGACY_AUTH_FILE); } catch {}
|
|
193
|
-
return { success: true };
|
|
194
|
-
} catch (err: any) {
|
|
195
|
-
return { success: false, error: err.message };
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
161
|
async function refreshTokens(refreshToken: string): Promise<boolean> {
|
|
200
162
|
try {
|
|
201
163
|
log.ok('Codex: refreshing access token...');
|
|
@@ -226,69 +188,124 @@ async function refreshTokens(refreshToken: string): Promise<boolean> {
|
|
|
226
188
|
}
|
|
227
189
|
}
|
|
228
190
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Parse what the user pasted — accepts:
|
|
193
|
+
* - the full callback URL (`http://localhost:1455/auth/callback?code=...&state=...`)
|
|
194
|
+
* - just the query string (`?code=...&state=...` or `code=...&state=...`)
|
|
195
|
+
* - just the raw code (`ac_XXX...`)
|
|
196
|
+
*/
|
|
197
|
+
function parsePastedInput(input: string): { code: string; state?: string } | { error: string } {
|
|
198
|
+
const trimmed = input.trim();
|
|
199
|
+
if (!trimmed) return { error: 'Paste the URL or code from your browser.' };
|
|
200
|
+
|
|
201
|
+
// Full URL or just a path
|
|
202
|
+
if (/^https?:\/\//i.test(trimmed) || trimmed.startsWith('/')) {
|
|
203
|
+
try {
|
|
204
|
+
const url = new URL(trimmed.startsWith('/') ? `http://x${trimmed}` : trimmed);
|
|
205
|
+
const code = url.searchParams.get('code');
|
|
206
|
+
if (!code) return { error: 'URL is missing the code parameter.' };
|
|
207
|
+
return { code, state: url.searchParams.get('state') || undefined };
|
|
208
|
+
} catch {
|
|
209
|
+
return { error: 'Could not parse the pasted URL.' };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
234
212
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
213
|
+
// Bare query string
|
|
214
|
+
if (trimmed.includes('=') && (trimmed.includes('&') || trimmed.startsWith('?'))) {
|
|
215
|
+
try {
|
|
216
|
+
const qs = trimmed.startsWith('?') ? trimmed.slice(1) : trimmed;
|
|
217
|
+
const params = new URLSearchParams(qs);
|
|
218
|
+
const code = params.get('code');
|
|
219
|
+
if (!code) return { error: 'Query string is missing the code parameter.' };
|
|
220
|
+
return { code, state: params.get('state') || undefined };
|
|
221
|
+
} catch {
|
|
222
|
+
return { error: 'Could not parse the pasted query string.' };
|
|
223
|
+
}
|
|
224
|
+
}
|
|
238
225
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
res.end();
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
226
|
+
// Treat as raw code
|
|
227
|
+
return { code: trimmed };
|
|
228
|
+
}
|
|
245
229
|
|
|
246
|
-
|
|
247
|
-
const code = url.searchParams.get('code');
|
|
248
|
-
const returnedState = url.searchParams.get('state');
|
|
249
|
-
const error = url.searchParams.get('error');
|
|
230
|
+
/* ── Public API ── */
|
|
250
231
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
232
|
+
export function startCodexOAuth(): { success: boolean; authUrl?: string; error?: string } {
|
|
233
|
+
codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
234
|
+
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
|
|
235
|
+
oauthState = crypto.randomUUID();
|
|
236
|
+
|
|
237
|
+
const params = new URLSearchParams({
|
|
238
|
+
response_type: 'code',
|
|
239
|
+
client_id: OAUTH_CONFIG.CLIENT_ID,
|
|
240
|
+
redirect_uri: OAUTH_CONFIG.REDIRECT_URI,
|
|
241
|
+
scope: OAUTH_CONFIG.SCOPES,
|
|
242
|
+
code_challenge: codeChallenge,
|
|
243
|
+
code_challenge_method: 'S256',
|
|
244
|
+
state: oauthState,
|
|
245
|
+
id_token_add_organizations: 'true',
|
|
246
|
+
codex_cli_simplified_flow: 'true',
|
|
247
|
+
});
|
|
256
248
|
|
|
257
|
-
|
|
249
|
+
log.ok('Codex OAuth flow started (paste-back mode)');
|
|
250
|
+
return { success: true, authUrl: `${OAUTH_CONFIG.AUTHORIZE_URL}?${params.toString()}` };
|
|
251
|
+
}
|
|
258
252
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
253
|
+
export async function exchangeCodexCode(input: string): Promise<{ success: boolean; error?: string }> {
|
|
254
|
+
if (!codeVerifier || !oauthState) {
|
|
255
|
+
return { success: false, error: 'Authentication wasn\'t started. Click "Authenticate" first.' };
|
|
256
|
+
}
|
|
262
257
|
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
const parsed = parsePastedInput(input);
|
|
259
|
+
if ('error' in parsed) return { success: false, error: parsed.error };
|
|
265
260
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
state: oauthState!,
|
|
274
|
-
id_token_add_organizations: 'true',
|
|
275
|
-
codex_cli_simplified_flow: 'true',
|
|
276
|
-
});
|
|
261
|
+
if (parsed.state && parsed.state !== oauthState) {
|
|
262
|
+
log.warn(`Codex OAuth: state mismatch (got=${parsed.state}, expected=${oauthState})`);
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
error: 'State mismatch — start the flow again from the wizard.',
|
|
266
|
+
};
|
|
267
|
+
}
|
|
277
268
|
|
|
278
|
-
|
|
269
|
+
try {
|
|
270
|
+
const payload = new URLSearchParams({
|
|
271
|
+
grant_type: 'authorization_code',
|
|
272
|
+
client_id: OAUTH_CONFIG.CLIENT_ID,
|
|
273
|
+
code: parsed.code,
|
|
274
|
+
redirect_uri: OAUTH_CONFIG.REDIRECT_URI,
|
|
275
|
+
code_verifier: codeVerifier,
|
|
279
276
|
});
|
|
280
277
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
resolve({ success: false, error });
|
|
278
|
+
const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
281
|
+
body: payload.toString(),
|
|
286
282
|
});
|
|
287
|
-
|
|
283
|
+
|
|
284
|
+
if (!response.ok) {
|
|
285
|
+
const body = await response.text().catch(() => '');
|
|
286
|
+
log.warn(`Codex OAuth exchange failed (${response.status}): ${body.slice(0, 200)}`);
|
|
287
|
+
return {
|
|
288
|
+
success: false,
|
|
289
|
+
error: `Authentication failed (${response.status}). Codes are single-use — start over and paste a fresh one.`,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const tokens = await response.json();
|
|
294
|
+
if (!tokens.access_token) {
|
|
295
|
+
return { success: false, error: 'OAuth response missing access_token.' };
|
|
296
|
+
}
|
|
297
|
+
storeTokens(tokens);
|
|
298
|
+
codeVerifier = null;
|
|
299
|
+
oauthState = null;
|
|
300
|
+
try { fs.unlinkSync(LEGACY_AUTH_FILE); } catch {}
|
|
301
|
+
log.ok('Codex credentials stored');
|
|
302
|
+
return { success: true };
|
|
303
|
+
} catch (err: any) {
|
|
304
|
+
return { success: false, error: err.message };
|
|
305
|
+
}
|
|
288
306
|
}
|
|
289
307
|
|
|
290
308
|
export function cancelCodexOAuth(): void {
|
|
291
|
-
stopCallbackServer();
|
|
292
309
|
codeVerifier = null;
|
|
293
310
|
oauthState = null;
|
|
294
311
|
}
|
|
@@ -353,11 +370,258 @@ export function readCodexAccessToken(): string | null {
|
|
|
353
370
|
return token;
|
|
354
371
|
}
|
|
355
372
|
|
|
356
|
-
/*
|
|
373
|
+
/* ────────────────────────────────────────────────────────────────────────────
|
|
374
|
+
* Device-code flow — preferred for headless / remote dashboards.
|
|
375
|
+
*
|
|
376
|
+
* 1. POST {AUTH_BASE}/api/accounts/deviceauth/usercode body {client_id}
|
|
377
|
+
* → { device_auth_id, user_code, interval }
|
|
378
|
+
* 2. Poll POST {AUTH_BASE}/api/accounts/deviceauth/token body {device_auth_id, user_code}
|
|
379
|
+
* 403/404 = pending, 2xx = { authorization_code, code_challenge, code_verifier }
|
|
380
|
+
* 3. POST {AUTH_BASE}/oauth/token body {grant_type, client_id, code, code_verifier,
|
|
381
|
+
* redirect_uri="{AUTH_BASE}/deviceauth/callback"} → standard token response
|
|
382
|
+
*
|
|
383
|
+
* The user opens DEVICE_VERIFICATION_URL and types user_code there. We poll
|
|
384
|
+
* in the background; the wizard polls /api/auth/codex/device/status for the
|
|
385
|
+
* current state.
|
|
386
|
+
* ──────────────────────────────────────────────────────────────────────────── */
|
|
387
|
+
|
|
388
|
+
const AUTH_BASE = 'https://auth.openai.com';
|
|
389
|
+
const DEVICE_USER_CODE_URL = `${AUTH_BASE}/api/accounts/deviceauth/usercode`;
|
|
390
|
+
const DEVICE_POLL_URL = `${AUTH_BASE}/api/accounts/deviceauth/token`;
|
|
391
|
+
const DEVICE_REDIRECT_URI = `${AUTH_BASE}/deviceauth/callback`;
|
|
392
|
+
const DEVICE_VERIFICATION_URL = `${AUTH_BASE}/codex/device`;
|
|
393
|
+
const DEVICE_TIMEOUT_MS = 15 * 60 * 1000;
|
|
394
|
+
const DEVICE_DEFAULT_INTERVAL_SEC = 5;
|
|
395
|
+
|
|
396
|
+
interface DeviceLoginState {
|
|
397
|
+
/** Bumped on each `startDeviceCodeLogin` so a stale poll loop can self-cancel. */
|
|
398
|
+
generation: number;
|
|
399
|
+
state: 'idle' | 'pending' | 'success' | 'error';
|
|
400
|
+
userCode?: string;
|
|
401
|
+
verificationUrl?: string;
|
|
402
|
+
expiresAt?: number; // epoch ms
|
|
403
|
+
error?: string;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
let deviceLogin: DeviceLoginState = { generation: 0, state: 'idle' };
|
|
407
|
+
|
|
408
|
+
export function getDeviceCodeStatus(): {
|
|
409
|
+
state: DeviceLoginState['state'];
|
|
410
|
+
userCode?: string;
|
|
411
|
+
verificationUrl?: string;
|
|
412
|
+
expiresInSec?: number;
|
|
413
|
+
error?: string;
|
|
414
|
+
} {
|
|
415
|
+
const expiresInSec = deviceLogin.expiresAt
|
|
416
|
+
? Math.max(0, Math.round((deviceLogin.expiresAt - Date.now()) / 1000))
|
|
417
|
+
: undefined;
|
|
418
|
+
return {
|
|
419
|
+
state: deviceLogin.state,
|
|
420
|
+
userCode: deviceLogin.userCode,
|
|
421
|
+
verificationUrl: deviceLogin.verificationUrl,
|
|
422
|
+
expiresInSec,
|
|
423
|
+
error: deviceLogin.error,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export function cancelDeviceCodeLogin(): void {
|
|
428
|
+
// Bumping the generation makes any in-flight poll loop a no-op on its next tick.
|
|
429
|
+
deviceLogin = { generation: deviceLogin.generation + 1, state: 'idle' };
|
|
430
|
+
log.ok('Codex device-code login cancelled');
|
|
431
|
+
}
|
|
357
432
|
|
|
358
|
-
function
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
433
|
+
export async function startDeviceCodeLogin(): Promise<{
|
|
434
|
+
success: boolean;
|
|
435
|
+
userCode?: string;
|
|
436
|
+
verificationUrl?: string;
|
|
437
|
+
error?: string;
|
|
438
|
+
}> {
|
|
439
|
+
// Cancel any existing in-flight login before starting a new one.
|
|
440
|
+
const generation = deviceLogin.generation + 1;
|
|
441
|
+
deviceLogin = { generation, state: 'pending' };
|
|
442
|
+
|
|
443
|
+
try {
|
|
444
|
+
const res = await fetch(DEVICE_USER_CODE_URL, {
|
|
445
|
+
method: 'POST',
|
|
446
|
+
headers: {
|
|
447
|
+
'Content-Type': 'application/json',
|
|
448
|
+
'User-Agent': 'bloby-bot',
|
|
449
|
+
},
|
|
450
|
+
body: JSON.stringify({ client_id: OAUTH_CONFIG.CLIENT_ID }),
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
if (!res.ok) {
|
|
454
|
+
const body = await res.text().catch(() => '');
|
|
455
|
+
const error = `Failed to request device code (${res.status}). ${body.slice(0, 200)}`;
|
|
456
|
+
deviceLogin = { generation, state: 'error', error };
|
|
457
|
+
log.warn(`Codex device-code start failed: ${error}`);
|
|
458
|
+
return { success: false, error };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const data = await res.json();
|
|
462
|
+
const userCode: string = data.user_code || data.usercode;
|
|
463
|
+
const deviceAuthId: string = data.device_auth_id;
|
|
464
|
+
const intervalSec: number = Number(data.interval) || DEVICE_DEFAULT_INTERVAL_SEC;
|
|
465
|
+
if (!userCode || !deviceAuthId) {
|
|
466
|
+
const error = 'Device code response missing user_code or device_auth_id.';
|
|
467
|
+
deviceLogin = { generation, state: 'error', error };
|
|
468
|
+
return { success: false, error };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
deviceLogin = {
|
|
472
|
+
generation,
|
|
473
|
+
state: 'pending',
|
|
474
|
+
userCode,
|
|
475
|
+
verificationUrl: DEVICE_VERIFICATION_URL,
|
|
476
|
+
expiresAt: Date.now() + DEVICE_TIMEOUT_MS,
|
|
477
|
+
};
|
|
478
|
+
log.ok(`Codex device-code login started (code=${userCode}, poll every ${intervalSec}s)`);
|
|
479
|
+
|
|
480
|
+
// Fire-and-forget background poll.
|
|
481
|
+
void pollDeviceCode(generation, deviceAuthId, userCode, intervalSec);
|
|
482
|
+
|
|
483
|
+
return { success: true, userCode, verificationUrl: DEVICE_VERIFICATION_URL };
|
|
484
|
+
} catch (err: any) {
|
|
485
|
+
const error = err?.message || String(err);
|
|
486
|
+
deviceLogin = { generation, state: 'error', error };
|
|
487
|
+
log.warn(`Codex device-code start error: ${error}`);
|
|
488
|
+
return { success: false, error };
|
|
362
489
|
}
|
|
363
490
|
}
|
|
491
|
+
|
|
492
|
+
async function pollDeviceCode(
|
|
493
|
+
generation: number,
|
|
494
|
+
deviceAuthId: string,
|
|
495
|
+
userCode: string,
|
|
496
|
+
intervalSec: number,
|
|
497
|
+
): Promise<void> {
|
|
498
|
+
const startedAt = Date.now();
|
|
499
|
+
|
|
500
|
+
while (true) {
|
|
501
|
+
// Stale generation = a newer login was started or this one was cancelled.
|
|
502
|
+
if (deviceLogin.generation !== generation) {
|
|
503
|
+
log.ok(`Codex device-code poll for gen ${generation} stopped (superseded)`);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (Date.now() - startedAt > DEVICE_TIMEOUT_MS) {
|
|
508
|
+
deviceLogin = {
|
|
509
|
+
generation,
|
|
510
|
+
state: 'error',
|
|
511
|
+
error: 'Device-code login timed out (15 minutes). Try again.',
|
|
512
|
+
};
|
|
513
|
+
log.warn('Codex device-code login timed out');
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
let res: Response;
|
|
518
|
+
try {
|
|
519
|
+
res = await fetch(DEVICE_POLL_URL, {
|
|
520
|
+
method: 'POST',
|
|
521
|
+
headers: {
|
|
522
|
+
'Content-Type': 'application/json',
|
|
523
|
+
'User-Agent': 'bloby-bot',
|
|
524
|
+
},
|
|
525
|
+
body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),
|
|
526
|
+
});
|
|
527
|
+
} catch (err: any) {
|
|
528
|
+
// Transient network errors — log and keep polling within timeout.
|
|
529
|
+
log.warn(`Codex device-code poll network error: ${err?.message || err}`);
|
|
530
|
+
await sleep(intervalSec * 1000);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (res.status === 403 || res.status === 404) {
|
|
535
|
+
// Pending — user hasn't approved yet.
|
|
536
|
+
await sleep(intervalSec * 1000);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (!res.ok) {
|
|
541
|
+
const body = await res.text().catch(() => '');
|
|
542
|
+
const error = `Device-code poll failed (${res.status}). ${body.slice(0, 200)}`;
|
|
543
|
+
if (deviceLogin.generation === generation) {
|
|
544
|
+
deviceLogin = { generation, state: 'error', error };
|
|
545
|
+
}
|
|
546
|
+
log.warn(error);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// 2xx — server returned the authorization_code + PKCE verifier.
|
|
551
|
+
let data: { authorization_code?: string; code_verifier?: string };
|
|
552
|
+
try {
|
|
553
|
+
data = await res.json();
|
|
554
|
+
} catch (err: any) {
|
|
555
|
+
const error = `Device-code poll: malformed JSON (${err?.message || err})`;
|
|
556
|
+
if (deviceLogin.generation === generation) {
|
|
557
|
+
deviceLogin = { generation, state: 'error', error };
|
|
558
|
+
}
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (!data.authorization_code || !data.code_verifier) {
|
|
563
|
+
const error = 'Device-code poll: response missing authorization_code or code_verifier.';
|
|
564
|
+
if (deviceLogin.generation === generation) {
|
|
565
|
+
deviceLogin = { generation, state: 'error', error };
|
|
566
|
+
}
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Final step: exchange for tokens.
|
|
571
|
+
const exchanged = await exchangeDeviceCode(data.authorization_code, data.code_verifier);
|
|
572
|
+
if (deviceLogin.generation !== generation) return;
|
|
573
|
+
|
|
574
|
+
if (exchanged.success) {
|
|
575
|
+
deviceLogin = { generation, state: 'success' };
|
|
576
|
+
log.ok('Codex device-code login complete');
|
|
577
|
+
} else {
|
|
578
|
+
deviceLogin = {
|
|
579
|
+
generation,
|
|
580
|
+
state: 'error',
|
|
581
|
+
error: exchanged.error || 'Token exchange failed.',
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
async function exchangeDeviceCode(
|
|
589
|
+
authorizationCode: string,
|
|
590
|
+
codeVerifierFromServer: string,
|
|
591
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
592
|
+
try {
|
|
593
|
+
const payload = new URLSearchParams({
|
|
594
|
+
grant_type: 'authorization_code',
|
|
595
|
+
client_id: OAUTH_CONFIG.CLIENT_ID,
|
|
596
|
+
code: authorizationCode,
|
|
597
|
+
redirect_uri: DEVICE_REDIRECT_URI,
|
|
598
|
+
code_verifier: codeVerifierFromServer,
|
|
599
|
+
});
|
|
600
|
+
const res = await fetch(OAUTH_CONFIG.TOKEN_URL, {
|
|
601
|
+
method: 'POST',
|
|
602
|
+
headers: {
|
|
603
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
604
|
+
'User-Agent': 'bloby-bot',
|
|
605
|
+
},
|
|
606
|
+
body: payload.toString(),
|
|
607
|
+
});
|
|
608
|
+
if (!res.ok) {
|
|
609
|
+
const body = await res.text().catch(() => '');
|
|
610
|
+
log.warn(`Codex device-code token exchange failed (${res.status}): ${body.slice(0, 200)}`);
|
|
611
|
+
return { success: false, error: `Token exchange failed (${res.status}).` };
|
|
612
|
+
}
|
|
613
|
+
const tokens = await res.json();
|
|
614
|
+
if (!tokens.access_token) {
|
|
615
|
+
return { success: false, error: 'Token exchange response missing access_token.' };
|
|
616
|
+
}
|
|
617
|
+
storeTokens(tokens);
|
|
618
|
+
try { fs.unlinkSync(LEGACY_AUTH_FILE); } catch {}
|
|
619
|
+
return { success: true };
|
|
620
|
+
} catch (err: any) {
|
|
621
|
+
return { success: false, error: err?.message || String(err) };
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function sleep(ms: number): Promise<void> {
|
|
626
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
627
|
+
}
|
package/worker/index.ts
CHANGED
|
@@ -9,7 +9,10 @@ import { initDb, closeDb, listConversations, createConversation, deleteConversat
|
|
|
9
9
|
import webpush from 'web-push';
|
|
10
10
|
import { TOTP } from 'otpauth';
|
|
11
11
|
import QRCode from 'qrcode';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
startCodexOAuth, cancelCodexOAuth, getCodexAuthStatus, exchangeCodexCode,
|
|
14
|
+
startDeviceCodeLogin, getDeviceCodeStatus, cancelDeviceCodeLogin,
|
|
15
|
+
} from './codex-auth.js';
|
|
13
16
|
import { startClaudeOAuth, exchangeClaudeCode, getClaudeAuthStatus, readClaudeAccessToken } from './claude-auth.js';
|
|
14
17
|
import { checkAvailability, registerHandle, claimReservedHandle, releaseHandle, updateTunnelUrl, startHeartbeat, stopHeartbeat } from '../shared/relay.js';
|
|
15
18
|
import { ensureFileDirs } from '../supervisor/file-saver.js';
|
|
@@ -171,9 +174,17 @@ app.post('/api/context/clear', (_, res) => {
|
|
|
171
174
|
|
|
172
175
|
// ── Codex OAuth routes ──
|
|
173
176
|
|
|
174
|
-
app.post('/api/auth/codex/start',
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
app.post('/api/auth/codex/start', (_req, res) => {
|
|
178
|
+
res.json(startCodexOAuth());
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
app.post('/api/auth/codex/exchange', async (req, res) => {
|
|
182
|
+
const { code } = req.body || {};
|
|
183
|
+
if (!code || typeof code !== 'string') {
|
|
184
|
+
res.json({ success: false, error: 'No code provided' });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
res.json(await exchangeCodexCode(code));
|
|
177
188
|
});
|
|
178
189
|
|
|
179
190
|
app.post('/api/auth/codex/cancel', (_req, res) => {
|
|
@@ -185,6 +196,21 @@ app.get('/api/auth/codex/status', async (_req, res) => {
|
|
|
185
196
|
res.json(await getCodexAuthStatus());
|
|
186
197
|
});
|
|
187
198
|
|
|
199
|
+
// ── Codex device-code routes (preferred for headless dashboards) ──
|
|
200
|
+
|
|
201
|
+
app.post('/api/auth/codex/device/start', async (_req, res) => {
|
|
202
|
+
res.json(await startDeviceCodeLogin());
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
app.get('/api/auth/codex/device/status', (_req, res) => {
|
|
206
|
+
res.json(getDeviceCodeStatus());
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
app.post('/api/auth/codex/device/cancel', (_req, res) => {
|
|
210
|
+
cancelDeviceCodeLogin();
|
|
211
|
+
res.json({ ok: true });
|
|
212
|
+
});
|
|
213
|
+
|
|
188
214
|
// ── Claude OAuth routes ──
|
|
189
215
|
|
|
190
216
|
app.post('/api/auth/claude/start', (_req, res) => {
|