bloby-bot 0.30.1 → 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.
Files changed (344) hide show
  1. package/dist-bloby/assets/angular-html-DxXh-QMA.js +1 -0
  2. package/dist-bloby/assets/{angular-ts-BJPoZ_vo.js → angular-ts-BNEmshfa.js} +1 -1
  3. package/dist-bloby/assets/{apl-CyVuPSCb.js → apl-CD5excG6.js} +1 -1
  4. package/dist-bloby/assets/{astro-CKc3-gwH.js → astro-BsuvMd51.js} +1 -1
  5. package/dist-bloby/assets/{blade-DMAsVBaV.js → blade-BzCfsa5s.js} +1 -1
  6. package/dist-bloby/assets/{bloby-CqtSjokc.js → bloby-B1w9ReAR.js} +19 -19
  7. package/dist-bloby/assets/{bsl-B1qbqNES.js → bsl-BODK--Fo.js} +1 -1
  8. package/dist-bloby/assets/c-QpHxjkb9.js +1 -0
  9. package/dist-bloby/assets/{cairo-BDj8wWhy.js → cairo-BwpHIzLA.js} +1 -1
  10. package/dist-bloby/assets/{cobol-hBjMZW-R.js → cobol-Dvyhsqyz.js} +1 -1
  11. package/dist-bloby/assets/{coffee-B4OtR3w-.js → coffee-CyaHgmLy.js} +1 -1
  12. package/dist-bloby/assets/cpp-DlbkFQj0.js +1 -0
  13. package/dist-bloby/assets/{crystal-x3k4USY-.js → crystal-CR4Yni1K.js} +1 -1
  14. package/dist-bloby/assets/css-jgrsA6xW.js +1 -0
  15. package/dist-bloby/assets/{edge-B-9TrlZC.js → edge-CeStCG6d.js} +1 -1
  16. package/dist-bloby/assets/{elixir-CXCzbj1r.js → elixir-CNfWtFyr.js} +1 -1
  17. package/dist-bloby/assets/{elm-BdRiwmde.js → elm-WhyRrsYH.js} +1 -1
  18. package/dist-bloby/assets/{erb-C9tvRzx3.js → erb-BvJkfco6.js} +1 -1
  19. package/dist-bloby/assets/{erlang-Bc4hQuqa.js → erlang-CjZU-VwD.js} +1 -1
  20. package/dist-bloby/assets/{fortran-fixed-form-B02FOYI-.js → fortran-fixed-form-CLgNuKMV.js} +1 -1
  21. package/dist-bloby/assets/{fsharp-DhdR18vN.js → fsharp-kVgJ9XJy.js} +1 -1
  22. package/dist-bloby/assets/{gdresource-DgnrMPIx.js → gdresource-DDsMuL8p.js} +1 -1
  23. package/dist-bloby/assets/{git-commit-DGJi7qBD.js → git-commit-BKhxSJdF.js} +1 -1
  24. package/dist-bloby/assets/{git-rebase-HwDSB2qJ.js → git-rebase-C1GyNmcX.js} +1 -1
  25. package/dist-bloby/assets/{glimmer-js-B6LF_BMd.js → glimmer-js-Cl3u7vjy.js} +1 -1
  26. package/dist-bloby/assets/{glimmer-ts-Cn42BUKe.js → glimmer-ts-CtPlRgiA.js} +1 -1
  27. package/dist-bloby/assets/globals-B1T5ANQV.js +18 -0
  28. package/dist-bloby/assets/globals-CcIc79IH.css +2 -0
  29. package/dist-bloby/assets/glsl-Bz5r7Lln.js +1 -0
  30. package/dist-bloby/assets/graphql-IV9ZCUty.js +1 -0
  31. package/dist-bloby/assets/{hack-DDEqRjBe.js → hack-XsNdYtzr.js} +1 -1
  32. package/dist-bloby/assets/haml-BDRqXh7d.js +1 -0
  33. package/dist-bloby/assets/{handlebars-g9Qe0ao2.js → handlebars-Rv2-mTii.js} +1 -1
  34. package/dist-bloby/assets/highlighted-body-OFNGDK62-CHkKxiLr.js +1 -0
  35. package/dist-bloby/assets/html-BkYSbpwH.js +1 -0
  36. package/dist-bloby/assets/{html-derivative-D-XvNBA6.js → html-derivative-CNiypDIO.js} +1 -1
  37. package/dist-bloby/assets/{http-qlhghEti.js → http-Vgn8hmbu.js} +1 -1
  38. package/dist-bloby/assets/{hurl-CHIKfBKk.js → hurl-C_EA75yu.js} +1 -1
  39. package/dist-bloby/assets/{hxml-adC65L_J.js → hxml-YehGxZ3T.js} +1 -1
  40. package/dist-bloby/assets/java-div3J5pm.js +1 -0
  41. package/dist-bloby/assets/javascript-D7sYfeLa.js +1 -0
  42. package/dist-bloby/assets/{jinja-BHZt0_Dn.js → jinja-BovBDArb.js} +1 -1
  43. package/dist-bloby/assets/{jison-TqJYWKkW.js → jison-C7UZOdoh.js} +1 -1
  44. package/dist-bloby/assets/json-DsAnzN7U.js +1 -0
  45. package/dist-bloby/assets/jsx-CftCCFil.js +1 -0
  46. package/dist-bloby/assets/jsx-runtime-DsY8nUeV.js +1 -0
  47. package/dist-bloby/assets/{julia-CW07fy07.js → julia-D8hM3XBr.js} +1 -1
  48. package/dist-bloby/assets/{just-DBcWo9WY.js → just-CHnwfRRG.js} +1 -1
  49. package/dist-bloby/assets/{latex-D6lXiPTF.js → latex-Ccu-ZO0T.js} +1 -1
  50. package/dist-bloby/assets/{liquid-DhYYAQ41.js → liquid-BRbNyfzr.js} +1 -1
  51. package/dist-bloby/assets/lua-BcwT4KiU.js +1 -0
  52. package/dist-bloby/assets/{marko-xtrIBdcL.js → marko-Both7s0f.js} +1 -1
  53. package/dist-bloby/assets/{mdc-DyZVNnwP.js → mdc-7TpRllSI.js} +1 -1
  54. package/dist-bloby/assets/mermaid-GHXKKRXX-LsCge3XG.js +1 -0
  55. package/dist-bloby/assets/{nextflow-JEyYUlIq.js → nextflow-C2lnptGp.js} +1 -1
  56. package/dist-bloby/assets/{nginx-CGgm1VOJ.js → nginx-1MGd6YK-.js} +1 -1
  57. package/dist-bloby/assets/{nim-Br7S817Z.js → nim-CXWhMB6N.js} +1 -1
  58. package/dist-bloby/assets/onboard-DdL-0meC.js +1 -0
  59. package/dist-bloby/assets/{perl-DqDX-7VG.js → perl-s-whHxj8.js} +1 -1
  60. package/dist-bloby/assets/{php-DYSqNNGJ.js → php-KdIqqcNq.js} +1 -1
  61. package/dist-bloby/assets/{pug-Bob3gNio.js → pug-Cj_1QUAx.js} +1 -1
  62. package/dist-bloby/assets/{qml-CsMafcqN.js → qml-BQHwZF2t.js} +1 -1
  63. package/dist-bloby/assets/r-BW3neTZ6.js +1 -0
  64. package/dist-bloby/assets/{razor-B4PzhaZX.js → razor-D4oLdRr2.js} +1 -1
  65. package/dist-bloby/assets/regexp-CK2Vecnb.js +1 -0
  66. package/dist-bloby/assets/rolldown-runtime-C-57s9n3.js +1 -0
  67. package/dist-bloby/assets/{rst-BXuz-2b8.js → rst-kaCCXG10.js} +1 -1
  68. package/dist-bloby/assets/{ruby-CXP5_4kq.js → ruby-DIAu88GV.js} +1 -1
  69. package/dist-bloby/assets/{sas-Cov9PzAD.js → sas-DW2U5bKI.js} +1 -1
  70. package/dist-bloby/assets/scss-CpUwMEPb.js +1 -0
  71. package/dist-bloby/assets/{shaderlab-DZ3Lsiak.js → shaderlab-CCgEvKkt.js} +1 -1
  72. package/dist-bloby/assets/shellscript-BhywzMlr.js +1 -0
  73. package/dist-bloby/assets/{shellsession-BHLVblBB.js → shellsession-vB5Hy6UU.js} +1 -1
  74. package/dist-bloby/assets/{soy-e0u3-wIA.js → soy-BNDHXm4e.js} +1 -1
  75. package/dist-bloby/assets/{sparql-B9c85a_o.js → sparql-DH0hFmAi.js} +1 -1
  76. package/dist-bloby/assets/sql-D395ukne.js +1 -0
  77. package/dist-bloby/assets/{stata-B1mLEMrz.js → stata-BHXdpuN3.js} +1 -1
  78. package/dist-bloby/assets/{surrealql-BTKo2XFY.js → surrealql-eiBkI2Jy.js} +1 -1
  79. package/dist-bloby/assets/{svelte-B7URZ-wm.js → svelte-DcqzCcP6.js} +1 -1
  80. package/dist-bloby/assets/{templ-DVRYIgGq.js → templ-DpMCsFaT.js} +1 -1
  81. package/dist-bloby/assets/{tex-CdJ24HJj.js → tex-B71AZ6Vb.js} +1 -1
  82. package/dist-bloby/assets/{ts-tags-CCSbelDn.js → ts-tags-CRuJWBGV.js} +1 -1
  83. package/dist-bloby/assets/tsx-CEFbrBOd.js +1 -0
  84. package/dist-bloby/assets/{twig-Dn4ruiVl.js → twig-CuSIh_aH.js} +1 -1
  85. package/dist-bloby/assets/typescript-CV9iMaP7.js +1 -0
  86. package/dist-bloby/assets/{vue-D19cWHwY.js → vue-YbgnWnT2.js} +1 -1
  87. package/dist-bloby/assets/{vue-html-_j-KC7Cs.js → vue-html-CXsio3-X.js} +1 -1
  88. package/dist-bloby/assets/{vue-vine-BC03MN6c.js → vue-vine-C8pVogU0.js} +1 -1
  89. package/dist-bloby/assets/xml-Zmzpltp0.js +1 -0
  90. package/dist-bloby/assets/{xsl-DR-zOeBm.js → xsl-CqzL2w2F.js} +1 -1
  91. package/dist-bloby/assets/yaml-Dc_auW1I.js +1 -0
  92. package/dist-bloby/bloby.html +5 -4
  93. package/dist-bloby/onboard.html +5 -4
  94. package/package.json +1 -1
  95. package/supervisor/chat/OnboardWizard.tsx +278 -56
  96. package/supervisor/index.ts +1 -1
  97. package/worker/codex-auth.ts +362 -137
  98. package/worker/index.ts +30 -4
  99. package/dist-bloby/assets/angular-html-olSuI25H.js +0 -1
  100. package/dist-bloby/assets/c-BvB8CVo8.js +0 -1
  101. package/dist-bloby/assets/cpp-BblbpnyR.js +0 -1
  102. package/dist-bloby/assets/css-zY4NE9yA.js +0 -1
  103. package/dist-bloby/assets/globals-LpXKrQgt.css +0 -2
  104. package/dist-bloby/assets/globals-zKQhzQOX.js +0 -18
  105. package/dist-bloby/assets/glsl-CEMf-THb.js +0 -1
  106. package/dist-bloby/assets/graphql-dBCd2Czl.js +0 -1
  107. package/dist-bloby/assets/haml-Ck5pVAEG.js +0 -1
  108. package/dist-bloby/assets/highlighted-body-OFNGDK62-B0W8hCx-.js +0 -1
  109. package/dist-bloby/assets/html-CzX0w7K_.js +0 -1
  110. package/dist-bloby/assets/java-BqKEu7zh.js +0 -1
  111. package/dist-bloby/assets/javascript-CzjRtS1s.js +0 -1
  112. package/dist-bloby/assets/json-CdFmZMJc.js +0 -1
  113. package/dist-bloby/assets/jsx-BL6Wh6Qw.js +0 -1
  114. package/dist-bloby/assets/jsx-runtime-C0W9Wf2W.js +0 -1
  115. package/dist-bloby/assets/lua-B4ezzssg.js +0 -1
  116. package/dist-bloby/assets/mermaid-GHXKKRXX-Dr8I7wwH.js +0 -1
  117. package/dist-bloby/assets/onboard-C1yXK8uT.js +0 -1
  118. package/dist-bloby/assets/r-CGji9_vM.js +0 -1
  119. package/dist-bloby/assets/regexp-CvWG4lI-.js +0 -1
  120. package/dist-bloby/assets/scss-Efq7Dmbs.js +0 -1
  121. package/dist-bloby/assets/shellscript-BbEstezf.js +0 -1
  122. package/dist-bloby/assets/sql-CB6kO6Km.js +0 -1
  123. package/dist-bloby/assets/tsx-DrzBggF8.js +0 -1
  124. package/dist-bloby/assets/typescript-COZIw7xM.js +0 -1
  125. package/dist-bloby/assets/xml-BlDEvPia.js +0 -1
  126. package/dist-bloby/assets/yaml-iUXljnLs.js +0 -1
  127. /package/dist-bloby/assets/{abap-smLpETzL.js → abap--vzi7Rxy.js} +0 -0
  128. /package/dist-bloby/assets/{actionscript-3-o-aRvjY5.js → actionscript-3-CV21uODD.js} +0 -0
  129. /package/dist-bloby/assets/{ada-D5RRX1i4.js → ada-DpXSEmbw.js} +0 -0
  130. /package/dist-bloby/assets/{andromeeda-N4z3YzmR.js → andromeeda-C1V0Cb0M.js} +0 -0
  131. /package/dist-bloby/assets/{apache-DttKlSqg.js → apache-CRmVjs8c.js} +0 -0
  132. /package/dist-bloby/assets/{apex-DL7j-a2n.js → apex-DIIc4r7E.js} +0 -0
  133. /package/dist-bloby/assets/{applescript-DCbL_2FX.js → applescript-DMX6NGuU.js} +0 -0
  134. /package/dist-bloby/assets/{ara-DqheWJCe.js → ara-3SArX2Zn.js} +0 -0
  135. /package/dist-bloby/assets/{asciidoc-BH2sf2K4.js → asciidoc-CnVFjb7X.js} +0 -0
  136. /package/dist-bloby/assets/{asm-rfjOMz3U.js → asm-Cb-CgaBD.js} +0 -0
  137. /package/dist-bloby/assets/{aurora-x-CND-FqEb.js → aurora-x-CjvoFyi0.js} +0 -0
  138. /package/dist-bloby/assets/{awk-CMV5n9Z7.js → awk-BYjsWVhV.js} +0 -0
  139. /package/dist-bloby/assets/{ayu-dark-on7xzq_B.js → ayu-dark-C4UVdT_g.js} +0 -0
  140. /package/dist-bloby/assets/{ayu-light-DnGeGGc2.js → ayu-light-CFJ-dST-.js} +0 -0
  141. /package/dist-bloby/assets/{ayu-mirage-DG3LlYC_.js → ayu-mirage-BxM9D2Mi.js} +0 -0
  142. /package/dist-bloby/assets/{ballerina-BjMqJjlr.js → ballerina-BsKCUtAm.js} +0 -0
  143. /package/dist-bloby/assets/{bat-BaVbo_qw.js → bat-CJlQOahT.js} +0 -0
  144. /package/dist-bloby/assets/{beancount-DBt5Mbc_.js → beancount-Cyf6Xlzd.js} +0 -0
  145. /package/dist-bloby/assets/{berry-Cyjuxiss.js → berry-DHYmFnza.js} +0 -0
  146. /package/dist-bloby/assets/{bibtex-BV_0nsPq.js → bibtex-BUB9btZd.js} +0 -0
  147. /package/dist-bloby/assets/{bicep-C2gEwu4J.js → bicep-CNVX4dQj.js} +0 -0
  148. /package/dist-bloby/assets/{bird2-BRyaEJd0.js → bird2-LZP25z1s.js} +0 -0
  149. /package/dist-bloby/assets/{c3-DTTbp5N2.js → c3-BI41OB2W.js} +0 -0
  150. /package/dist-bloby/assets/{cadence-CPz83cmI.js → cadence-BDnzkZFt.js} +0 -0
  151. /package/dist-bloby/assets/{catppuccin-frappe-Dr22sraq.js → catppuccin-frappe-DpT1lCYX.js} +0 -0
  152. /package/dist-bloby/assets/{catppuccin-latte-C57EeX8c.js → catppuccin-latte-qMMse1WJ.js} +0 -0
  153. /package/dist-bloby/assets/{catppuccin-macchiato-CpheI4uD.js → catppuccin-macchiato-DMu0Ac9B.js} +0 -0
  154. /package/dist-bloby/assets/{catppuccin-mocha-D8Lmdks_.js → catppuccin-mocha-DicTaD9V.js} +0 -0
  155. /package/dist-bloby/assets/{clarity-CFJ2Yc3q.js → clarity-CPz-yzAn.js} +0 -0
  156. /package/dist-bloby/assets/{clojure-6R01QgJC.js → clojure-BxJLFKTj.js} +0 -0
  157. /package/dist-bloby/assets/{cmake-D5rSbMir.js → cmake-BmC4o4J9.js} +0 -0
  158. /package/dist-bloby/assets/{codeowners-_3A-ClkN.js → codeowners-BPHDuybI.js} +0 -0
  159. /package/dist-bloby/assets/{codeql-DlIhJTR7.js → codeql-DYWyWzRY.js} +0 -0
  160. /package/dist-bloby/assets/{common-lisp-BvQzz173.js → common-lisp-CsDdrwfa.js} +0 -0
  161. /package/dist-bloby/assets/{coq-DTNXReIC.js → coq-BZNwxllS.js} +0 -0
  162. /package/dist-bloby/assets/{csharp-BDKQY1K9.js → csharp-BLhQzhUA.js} +0 -0
  163. /package/dist-bloby/assets/{csv-DNUpVBxl.js → csv-DPc9UZFt.js} +0 -0
  164. /package/dist-bloby/assets/{cue-DDdBc2s3.js → cue-Bat8Mt8Y.js} +0 -0
  165. /package/dist-bloby/assets/{cypher-CguaznO2.js → cypher-CTnWkM4Y.js} +0 -0
  166. /package/dist-bloby/assets/{d-CHcoyjv3.js → d-CccbtpLU.js} +0 -0
  167. /package/dist-bloby/assets/{dark-plus-CqeW_0kH.js → dark-plus-CKh7uIvz.js} +0 -0
  168. /package/dist-bloby/assets/{dart-RM3aRphk.js → dart-SbRHwU1n.js} +0 -0
  169. /package/dist-bloby/assets/{dax-nbnY1d79.js → dax-vVKSTwd9.js} +0 -0
  170. /package/dist-bloby/assets/{desktop-BD76cvxT.js → desktop-rdWGepy4.js} +0 -0
  171. /package/dist-bloby/assets/{diff-CdkWtnkL.js → diff-G5H-0DNT.js} +0 -0
  172. /package/dist-bloby/assets/{docker-ZyPHc6zB.js → docker-CC20slQp.js} +0 -0
  173. /package/dist-bloby/assets/{dotenv-BdJZEwA6.js → dotenv-C36c6TdP.js} +0 -0
  174. /package/dist-bloby/assets/{dracula-CtqCPLGa.js → dracula-nNMQZYa7.js} +0 -0
  175. /package/dist-bloby/assets/{dracula-soft-DmBpwRAy.js → dracula-soft-BPmUsSlJ.js} +0 -0
  176. /package/dist-bloby/assets/{dream-maker-BJL4qlg3.js → dream-maker-DleGc9Hy.js} +0 -0
  177. /package/dist-bloby/assets/{emacs-lisp-_LyYa2Ky.js → emacs-lisp-D_QlcMHs.js} +0 -0
  178. /package/dist-bloby/assets/{everforest-dark-CrbyKk4n.js → everforest-dark-FkVvIMUl.js} +0 -0
  179. /package/dist-bloby/assets/{everforest-light-DRbSh8Tm.js → everforest-light-d3V1wTAd.js} +0 -0
  180. /package/dist-bloby/assets/{fennel-CC2BkRsS.js → fennel-BEssPROc.js} +0 -0
  181. /package/dist-bloby/assets/{fish-D2ZCzqcE.js → fish-Cz5yLEyJ.js} +0 -0
  182. /package/dist-bloby/assets/{fluent-DKAm3m7q.js → fluent-TGO8KajN.js} +0 -0
  183. /package/dist-bloby/assets/{fortran-free-form-BPTf0lbT.js → fortran-free-form-CHQXX5JB.js} +0 -0
  184. /package/dist-bloby/assets/{gdscript-CsadCSaZ.js → gdscript-DBkVGsC6.js} +0 -0
  185. /package/dist-bloby/assets/{gdshader-PfnN_8tR.js → gdshader-CWQhZP7Q.js} +0 -0
  186. /package/dist-bloby/assets/{genie-Bj-orPAV.js → genie-7iw14YxB.js} +0 -0
  187. /package/dist-bloby/assets/{gherkin-COVWpJ-Q.js → gherkin-D4AlAQSH.js} +0 -0
  188. /package/dist-bloby/assets/{github-dark-ipGuFGYC.js → github-dark-CpBni1SQ.js} +0 -0
  189. /package/dist-bloby/assets/{github-dark-default-DX3IG_X0.js → github-dark-default-Cr5Q59Ad.js} +0 -0
  190. /package/dist-bloby/assets/{github-dark-dimmed-CH6p_7ez.js → github-dark-dimmed-WEORr92a.js} +0 -0
  191. /package/dist-bloby/assets/{github-dark-high-contrast-Bg2sSao5.js → github-dark-high-contrast-uM2plAzl.js} +0 -0
  192. /package/dist-bloby/assets/{github-light-BxjqOQl0.js → github-light-BROm54vS.js} +0 -0
  193. /package/dist-bloby/assets/{github-light-default-DwpDd1IQ.js → github-light-default-jSwgX00f.js} +0 -0
  194. /package/dist-bloby/assets/{github-light-high-contrast-C0QeixPf.js → github-light-high-contrast-Bp9ESXtp.js} +0 -0
  195. /package/dist-bloby/assets/{gleam-BF2NigGj.js → gleam-D1LXnIj0.js} +0 -0
  196. /package/dist-bloby/assets/{gn-CMIt9roj.js → gn-CReOiE5m.js} +0 -0
  197. /package/dist-bloby/assets/{gnuplot-DgWlRTEj.js → gnuplot-DufViamc.js} +0 -0
  198. /package/dist-bloby/assets/{go-DLnOLj8q.js → go-DC_Zm44P.js} +0 -0
  199. /package/dist-bloby/assets/{groovy-B9qLWIkE.js → groovy-DEGDVBi0.js} +0 -0
  200. /package/dist-bloby/assets/{gruvbox-dark-hard-BIMX9ePb.js → gruvbox-dark-hard-C-zANgxR.js} +0 -0
  201. /package/dist-bloby/assets/{gruvbox-dark-medium-DxuwyVzM.js → gruvbox-dark-medium-DY7Z6TBK.js} +0 -0
  202. /package/dist-bloby/assets/{gruvbox-dark-soft-ba2fjht0.js → gruvbox-dark-soft-Bpj6owGh.js} +0 -0
  203. /package/dist-bloby/assets/{gruvbox-light-hard-DAJK2PqC.js → gruvbox-light-hard-DVwTvHam.js} +0 -0
  204. /package/dist-bloby/assets/{gruvbox-light-medium-WRifDAJD.js → gruvbox-light-medium-98PeoD5Y.js} +0 -0
  205. /package/dist-bloby/assets/{gruvbox-light-soft-B0dBOoVB.js → gruvbox-light-soft-BHI2PZTB.js} +0 -0
  206. /package/dist-bloby/assets/{haskell-BaGpmm_c.js → haskell-B-K-GoPf.js} +0 -0
  207. /package/dist-bloby/assets/{haxe-DfXTCEOz.js → haxe-md5t_Y_E.js} +0 -0
  208. /package/dist-bloby/assets/{hcl-CbCtpSbi.js → hcl-qSvp9jTg.js} +0 -0
  209. /package/dist-bloby/assets/{hjson-_4-w-pHU.js → hjson-BNeV6JDA.js} +0 -0
  210. /package/dist-bloby/assets/{hlsl-DpuYn7pp.js → hlsl-CFf5czm3.js} +0 -0
  211. /package/dist-bloby/assets/{horizon-C5RtD1fY.js → horizon-C4a2pCDo.js} +0 -0
  212. /package/dist-bloby/assets/{horizon-bright-pEOice34.js → horizon-bright-Bgpx-0aF.js} +0 -0
  213. /package/dist-bloby/assets/{houston-A0zg9vNP.js → houston-BZHNDhe5.js} +0 -0
  214. /package/dist-bloby/assets/{hy-t9zDXBje.js → hy-hI-CUgFt.js} +0 -0
  215. /package/dist-bloby/assets/{imba-Bxu-TDfw.js → imba-Dr5pZl3x.js} +0 -0
  216. /package/dist-bloby/assets/{ini-D-v34c8N.js → ini-KxzJ-qxg.js} +0 -0
  217. /package/dist-bloby/assets/{json5-D0XL1D5m.js → json5-SRM7tKmT.js} +0 -0
  218. /package/dist-bloby/assets/{jsonc-BBgf3TX3.js → jsonc-Cix1XnqC.js} +0 -0
  219. /package/dist-bloby/assets/{jsonl-KrKLbtB7.js → jsonl-BzKwo-fD.js} +0 -0
  220. /package/dist-bloby/assets/{jsonnet-B2ZwWMOt.js → jsonnet-DaiLv8or.js} +0 -0
  221. /package/dist-bloby/assets/{jssm-ByRpI9-B.js → jssm-B1pV58QJ.js} +0 -0
  222. /package/dist-bloby/assets/{kanagawa-dragon-CtPmcCMp.js → kanagawa-dragon-BihvT_N-.js} +0 -0
  223. /package/dist-bloby/assets/{kanagawa-lotus-DpOXEGCa.js → kanagawa-lotus-DQN_bzSt.js} +0 -0
  224. /package/dist-bloby/assets/{kanagawa-wave-CLVCyc-n.js → kanagawa-wave-Bvz_F3hD.js} +0 -0
  225. /package/dist-bloby/assets/{kdl-6FPPEH4H.js → kdl-DupMG4Bk.js} +0 -0
  226. /package/dist-bloby/assets/{kotlin-D4L3Nd2D.js → kotlin-rOGI_fXV.js} +0 -0
  227. /package/dist-bloby/assets/{kusto-D-mmc07O.js → kusto-CHXnQR8L.js} +0 -0
  228. /package/dist-bloby/assets/{laserwave-7fEj4XGb.js → laserwave-CPMyzJF3.js} +0 -0
  229. /package/dist-bloby/assets/{lean-BMVMuP2E.js → lean-B76KugVy.js} +0 -0
  230. /package/dist-bloby/assets/{less-C95PyOu0.js → less-DwUMKQAG.js} +0 -0
  231. /package/dist-bloby/assets/{light-plus-DHI2dh3p.js → light-plus-C6sdUQiS.js} +0 -0
  232. /package/dist-bloby/assets/{llvm-Dy3qORTl.js → llvm-DumY6MCH.js} +0 -0
  233. /package/dist-bloby/assets/{log-BQop7fzg.js → log-DdP6k-FU.js} +0 -0
  234. /package/dist-bloby/assets/{logo-DKtnYmrp.js → logo-Cx0gX691.js} +0 -0
  235. /package/dist-bloby/assets/{luau-Dha4KG0q.js → luau-CI4wJBxI.js} +0 -0
  236. /package/dist-bloby/assets/{make-DfmS6buu.js → make-BlyBJiAs.js} +0 -0
  237. /package/dist-bloby/assets/{markdown-BaI9LyM4.js → markdown-BFgBvytj.js} +0 -0
  238. /package/dist-bloby/assets/{material-theme-Dm6ETY8i.js → material-theme-CyGvAAeY.js} +0 -0
  239. /package/dist-bloby/assets/{material-theme-darker-BeyjmM5Z.js → material-theme-darker-DJAOSarR.js} +0 -0
  240. /package/dist-bloby/assets/{material-theme-lighter-CCOYYzKL.js → material-theme-lighter-Cb7t96j2.js} +0 -0
  241. /package/dist-bloby/assets/{material-theme-ocean-CUtPiiX3.js → material-theme-ocean-EZZ55_HD.js} +0 -0
  242. /package/dist-bloby/assets/{material-theme-palenight-2L4zMwIM.js → material-theme-palenight-DtmMSfya.js} +0 -0
  243. /package/dist-bloby/assets/{matlab-BT79Cq_j.js → matlab-BFLobVcp.js} +0 -0
  244. /package/dist-bloby/assets/{mdx-CxGBwLNt.js → mdx-Baux4qlv.js} +0 -0
  245. /package/dist-bloby/assets/{mermaid-DLf3axBN.js → mermaid-DHr7T0Rt.js} +0 -0
  246. /package/dist-bloby/assets/{min-dark-B8TUPGHg.js → min-dark-C9N1U4-e.js} +0 -0
  247. /package/dist-bloby/assets/{min-light-BDOoBxcA.js → min-light-Ce9oxBvH.js} +0 -0
  248. /package/dist-bloby/assets/{mipsasm-DXuU_0cI.js → mipsasm-Cgb1v7yV.js} +0 -0
  249. /package/dist-bloby/assets/{mojo-1Omp2pIo.js → mojo-BnTBKscO.js} +0 -0
  250. /package/dist-bloby/assets/{monokai-E_VBmXGZ.js → monokai-BGD_YBH-.js} +0 -0
  251. /package/dist-bloby/assets/{moonbit-DZzq699o.js → moonbit-HXw0ZM4h.js} +0 -0
  252. /package/dist-bloby/assets/{move-DxDAOJVd.js → move-DG2efXqI.js} +0 -0
  253. /package/dist-bloby/assets/{narrat-CxDcPPb9.js → narrat-BSasSB5t.js} +0 -0
  254. /package/dist-bloby/assets/{nextflow-groovy-wvmJO4hi.js → nextflow-groovy-DXLl8k8E.js} +0 -0
  255. /package/dist-bloby/assets/{night-owl-DefhalNX.js → night-owl-DxqNTXDa.js} +0 -0
  256. /package/dist-bloby/assets/{night-owl-light-byb3AbEn.js → night-owl-light-MPn8GCyh.js} +0 -0
  257. /package/dist-bloby/assets/{nix-DsFTDHWT.js → nix-BpnttlWr.js} +0 -0
  258. /package/dist-bloby/assets/{nord-D5rQzHT-.js → nord-Mt6M_qHE.js} +0 -0
  259. /package/dist-bloby/assets/{nushell-BQ_rO0AM.js → nushell-CS7Mvg-G.js} +0 -0
  260. /package/dist-bloby/assets/{objective-c-BMq6JT_m.js → objective-c-U4EuJXJs.js} +0 -0
  261. /package/dist-bloby/assets/{objective-cpp-DRwojuGv.js → objective-cpp-CE_PrXRW.js} +0 -0
  262. /package/dist-bloby/assets/{ocaml-e4_gKO6E.js → ocaml-ZsxDKzyv.js} +0 -0
  263. /package/dist-bloby/assets/{odin-mdTPwYOg.js → odin-CDoDiNYU.js} +0 -0
  264. /package/dist-bloby/assets/{one-dark-pro-DxXww9jg.js → one-dark-pro-B9P_I1yh.js} +0 -0
  265. /package/dist-bloby/assets/{one-light-D9c03w7t.js → one-light-Cv3j6GXq.js} +0 -0
  266. /package/dist-bloby/assets/{openscad-D2aTdNfr.js → openscad-CfJwW9dY.js} +0 -0
  267. /package/dist-bloby/assets/{pascal-D4n_G8vj.js → pascal-CjE0UTC7.js} +0 -0
  268. /package/dist-bloby/assets/{pkl-DcjhAp0L.js → pkl-BN6EkHr9.js} +0 -0
  269. /package/dist-bloby/assets/{plastic-uOsw7z1x.js → plastic-BCnZnfMk.js} +0 -0
  270. /package/dist-bloby/assets/{plsql-BSy3Ag0J.js → plsql-1LW-CqWM.js} +0 -0
  271. /package/dist-bloby/assets/{po-Be96RYkA.js → po-Cf5hRC9x.js} +0 -0
  272. /package/dist-bloby/assets/{poimandres-CyO4HORD.js → poimandres-B_zC30Vt.js} +0 -0
  273. /package/dist-bloby/assets/{polar-BmhMKWum.js → polar-S6fWkEw8.js} +0 -0
  274. /package/dist-bloby/assets/{postcss-BTQso3H9.js → postcss-cZXfRCsF.js} +0 -0
  275. /package/dist-bloby/assets/{powerquery-DVyQv3M2.js → powerquery-CoRQQdNP.js} +0 -0
  276. /package/dist-bloby/assets/{powershell-BmtCGJVD.js → powershell-B2VxwRch.js} +0 -0
  277. /package/dist-bloby/assets/{prisma-CCFA9rEj.js → prisma-sLrt38jj.js} +0 -0
  278. /package/dist-bloby/assets/{prolog-DWGEEo78.js → prolog-CL99toUJ.js} +0 -0
  279. /package/dist-bloby/assets/{proto-C3eop1kM.js → proto-CtiBQJNn.js} +0 -0
  280. /package/dist-bloby/assets/{puppet-C0_7Nv5A.js → puppet-BlbpxWq2.js} +0 -0
  281. /package/dist-bloby/assets/{purescript-Bv-B8yRw.js → purescript-DPcVkoDV.js} +0 -0
  282. /package/dist-bloby/assets/{python-CKg5r0C3.js → python-BLpCXkJ6.js} +0 -0
  283. /package/dist-bloby/assets/{qmldir-Cqfb4Lox.js → qmldir-BcwbwUc8.js} +0 -0
  284. /package/dist-bloby/assets/{qss-Csho9BH8.js → qss-erDfnnzG.js} +0 -0
  285. /package/dist-bloby/assets/{racket-D8-uWeQH.js → racket-Dch6VQku.js} +0 -0
  286. /package/dist-bloby/assets/{raku-Cj4JSa8p.js → raku-Db8mfsiE.js} +0 -0
  287. /package/dist-bloby/assets/{red-z4H4llUY.js → red-DWyyM82l.js} +0 -0
  288. /package/dist-bloby/assets/{reg-DXGFiJSl.js → reg-3F9yjO5J.js} +0 -0
  289. /package/dist-bloby/assets/{rel-CunnVTBK.js → rel-CQq8nxxL.js} +0 -0
  290. /package/dist-bloby/assets/{riscv-C8BcOCkS.js → riscv-CsUwotvK.js} +0 -0
  291. /package/dist-bloby/assets/{ron-DiDyR9oa.js → ron-BwlS4rWu.js} +0 -0
  292. /package/dist-bloby/assets/{rose-pine-BADquuIH.js → rose-pine-DEj8gOox.js} +0 -0
  293. /package/dist-bloby/assets/{rose-pine-dawn-BLcEeBoh.js → rose-pine-dawn-DjarqQ2I.js} +0 -0
  294. /package/dist-bloby/assets/{rose-pine-moon-BK_tLY1Y.js → rose-pine-moon-D7ffkR_D.js} +0 -0
  295. /package/dist-bloby/assets/{rosmsg-CHmL1Uyj.js → rosmsg-BmwwVMq5.js} +0 -0
  296. /package/dist-bloby/assets/{rust-DjJFInu3.js → rust-DsIgDjpj.js} +0 -0
  297. /package/dist-bloby/assets/{sass-D3xZ5o-v.js → sass-CkIFK_bT.js} +0 -0
  298. /package/dist-bloby/assets/{scala-B0IRml5w.js → scala-C0TSxhxD.js} +0 -0
  299. /package/dist-bloby/assets/{scheme-BhwcV3Av.js → scheme-e-5nJ58U.js} +0 -0
  300. /package/dist-bloby/assets/{sdbl-BmWYR-pI.js → sdbl-DOe8Nral.js} +0 -0
  301. /package/dist-bloby/assets/{slack-dark-DOnVms5P.js → slack-dark-CClHvLju.js} +0 -0
  302. /package/dist-bloby/assets/{slack-ochin-DcRTft4q.js → slack-ochin-DwCpSVBI.js} +0 -0
  303. /package/dist-bloby/assets/{smalltalk-DVQuUMII.js → smalltalk-fjkC4HKG.js} +0 -0
  304. /package/dist-bloby/assets/{snazzy-light-x9CLJ1W9.js → snazzy-light-2nD216w0.js} +0 -0
  305. /package/dist-bloby/assets/{solarized-dark-BB1sh-pe.js → solarized-dark-BkxMSETv.js} +0 -0
  306. /package/dist-bloby/assets/{solarized-light-9-RPS998.js → solarized-light-BScqQ1C4.js} +0 -0
  307. /package/dist-bloby/assets/{solidity-gQ4WXILB.js → solidity-DbOxJfAY.js} +0 -0
  308. /package/dist-bloby/assets/{splunk-OB48_RcD.js → splunk-BW0l10cw.js} +0 -0
  309. /package/dist-bloby/assets/{ssh-config-DA9YMRGV.js → ssh-config-XN7RWvZy.js} +0 -0
  310. /package/dist-bloby/assets/{stylus-sKwvsUaC.js → stylus-D69is74S.js} +0 -0
  311. /package/dist-bloby/assets/{swift-C72NbAtg.js → swift-CqNHAbQB.js} +0 -0
  312. /package/dist-bloby/assets/{synthwave-84-eJ9uRN_S.js → synthwave-84-Ct3Np89a.js} +0 -0
  313. /package/dist-bloby/assets/{system-verilog-CnWMF7Nq.js → system-verilog-CHbvBf8h.js} +0 -0
  314. /package/dist-bloby/assets/{systemd-DMzItW5N.js → systemd-BBC3Z_R4.js} +0 -0
  315. /package/dist-bloby/assets/{talonscript-DopQCWDL.js → talonscript-DhYQB2ic.js} +0 -0
  316. /package/dist-bloby/assets/{tasl-C28SYKbq.js → tasl-CNtai3BH.js} +0 -0
  317. /package/dist-bloby/assets/{tcl-DHq7zmoF.js → tcl-DFzyQSXW.js} +0 -0
  318. /package/dist-bloby/assets/{terraform-CogS1YKX.js → terraform-BijD6Khb.js} +0 -0
  319. /package/dist-bloby/assets/{tokyo-night-B9N7LyrF.js → tokyo-night-Dd5BGAxh.js} +0 -0
  320. /package/dist-bloby/assets/{toml-BH_iPsgK.js → toml-DZofdujH.js} +0 -0
  321. /package/dist-bloby/assets/{tsv-BIkdBZX1.js → tsv-DOp6g7sz.js} +0 -0
  322. /package/dist-bloby/assets/{turtle-CqNXyJWZ.js → turtle-BKcRDROw.js} +0 -0
  323. /package/dist-bloby/assets/{typespec-CQ9LYD_e.js → typespec-Mmt3-2Cw.js} +0 -0
  324. /package/dist-bloby/assets/{typst-T-Fsk-Sv.js → typst-CndOdNo_.js} +0 -0
  325. /package/dist-bloby/assets/{v-BhMEOw9x.js → v-DjlZIA0C.js} +0 -0
  326. /package/dist-bloby/assets/{vala-DzajMnwt.js → vala-C5Nm5NXo.js} +0 -0
  327. /package/dist-bloby/assets/{vb-7Xr8dEYW.js → vb-zZeWbE2_.js} +0 -0
  328. /package/dist-bloby/assets/{verilog-AvXtwZir.js → verilog-CyZIVfoz.js} +0 -0
  329. /package/dist-bloby/assets/{vesper-CtgQQ2sf.js → vesper-B0BMGbco.js} +0 -0
  330. /package/dist-bloby/assets/{vhdl-BHu0zg1P.js → vhdl-DH1mJdjZ.js} +0 -0
  331. /package/dist-bloby/assets/{viml-Di0QpLfC.js → viml-e-oP1x-l.js} +0 -0
  332. /package/dist-bloby/assets/{vitesse-black-jXdfyqgD.js → vitesse-black-BRAUsA4Q.js} +0 -0
  333. /package/dist-bloby/assets/{vitesse-dark-B88PxG1r.js → vitesse-dark-Dyg71HnT.js} +0 -0
  334. /package/dist-bloby/assets/{vitesse-light-BXxZh2iV.js → vitesse-light-BJKZKqvd.js} +0 -0
  335. /package/dist-bloby/assets/{vyper-C3R5yXgx.js → vyper-BRPzCrki.js} +0 -0
  336. /package/dist-bloby/assets/{wasm-Chsuwt1A.js → wasm-DYMpDie-.js} +0 -0
  337. /package/dist-bloby/assets/{wasm-CEUrWlVz.js → wasm-Drz0Uqci.js} +0 -0
  338. /package/dist-bloby/assets/{wenyan-BonVcr2i.js → wenyan-BiJ0NePu.js} +0 -0
  339. /package/dist-bloby/assets/{wgsl-D59WYmNq.js → wgsl-CNe_V6SG.js} +0 -0
  340. /package/dist-bloby/assets/{wikitext-ariTI2Wk.js → wikitext-DZrjZKWn.js} +0 -0
  341. /package/dist-bloby/assets/{wit-EA4fa3Dt.js → wit-BUTESHa8.js} +0 -0
  342. /package/dist-bloby/assets/{wolfram-DDp7LhyU.js → wolfram-COEZldPx.js} +0 -0
  343. /package/dist-bloby/assets/{zenscript-4WaROUyc.js → zenscript-DThCxjUC.js} +0 -0
  344. /package/dist-bloby/assets/{zig-CJoLJGwV.js → zig-Bu6QWpR2.js} +0 -0
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * Codex OAuth PKCE flow for ChatGPT Plus/Pro subscription authentication.
3
3
  *
4
- * Spins up a temporary HTTP server on port 1455 to capture the OAuth callback.
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 callbackServers: http.Server[] = [];
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 (seconds). Null if missing/invalid. */
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,108 +188,124 @@ async function refreshTokens(refreshToken: string): Promise<boolean> {
226
188
  }
227
189
  }
228
190
 
229
- /* ── Public API ── */
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
+ }
230
212
 
231
- export function startCodexOAuth(): Promise<{ success: boolean; authUrl?: string; error?: string }> {
232
- return new Promise((resolve) => {
233
- stopCallbackServer();
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
+ }
234
225
 
235
- codeVerifier = crypto.randomBytes(32).toString('base64url');
236
- const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
237
- oauthState = crypto.randomUUID();
226
+ // Treat as raw code
227
+ return { code: trimmed };
228
+ }
238
229
 
239
- const handleCallback = (req: http.IncomingMessage, res: http.ServerResponse) => {
240
- if (!req.url?.startsWith('/auth/callback')) {
241
- res.writeHead(404);
242
- res.end();
243
- return;
244
- }
230
+ /* ── Public API ── */
245
231
 
246
- const url = new URL(req.url, `http://localhost:${OAUTH_CONFIG.PORT}`);
247
- const code = url.searchParams.get('code');
248
- const returnedState = url.searchParams.get('state');
249
- const error = url.searchParams.get('error');
250
- log.ok(`Codex OAuth callback hit (code=${code ? 'yes' : 'no'}, state=${returnedState === oauthState ? 'ok' : 'mismatch'}, error=${error || 'none'})`);
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
+ });
251
248
 
252
- res.writeHead(200, { 'Content-Type': 'text/html' });
253
- res.end(`<html><body style="font-family:sans-serif;text-align:center;padding:60px;background:#0a0a0a;color:#fff">
254
- <h2>${error ? 'Authentication Failed' : 'Authenticated!'}</h2>
255
- <p style="color:#888">${error || 'You can close this tab and return to Bloby.'}</p>
256
- </body></html>`);
249
+ log.ok('Codex OAuth flow started (paste-back mode)');
250
+ return { success: true, authUrl: `${OAUTH_CONFIG.AUTHORIZE_URL}?${params.toString()}` };
251
+ }
257
252
 
258
- stopCallbackServer();
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
+ }
259
257
 
260
- if (error || !code || returnedState !== oauthState) return;
261
- exchangeCode(code);
262
- };
258
+ const parsed = parsePastedInput(input);
259
+ if ('error' in parsed) return { success: false, error: parsed.error };
263
260
 
264
- // Bind BOTH IPv4 and IPv6 loopback. On dual-stack systems where
265
- // `localhost` resolves to ::1 first, an IPv4-only bind silently fails
266
- // when the browser hits the callback URL.
267
- const bindHosts: Array<{ host: string; required: boolean }> = [
268
- { host: '127.0.0.1', required: true },
269
- { host: '::1', required: false }, // tolerate machines without IPv6
270
- ];
271
-
272
- let resolved = false;
273
- let pendingBinds = bindHosts.length;
274
- let bindFailures = 0;
275
-
276
- const finishWithSuccess = () => {
277
- if (resolved) return;
278
- resolved = true;
279
- log.ok(`Codex OAuth callback servers listening on port ${OAUTH_CONFIG.PORT} (${callbackServers.length} bind${callbackServers.length === 1 ? '' : 's'})`);
280
- const params = new URLSearchParams({
281
- response_type: 'code',
282
- client_id: OAUTH_CONFIG.CLIENT_ID,
283
- redirect_uri: OAUTH_CONFIG.REDIRECT_URI,
284
- scope: OAUTH_CONFIG.SCOPES,
285
- code_challenge: codeChallenge,
286
- code_challenge_method: 'S256',
287
- state: oauthState!,
288
- id_token_add_organizations: 'true',
289
- codex_cli_simplified_flow: 'true',
290
- });
291
- resolve({ success: true, authUrl: `${OAUTH_CONFIG.AUTHORIZE_URL}?${params.toString()}` });
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.',
292
266
  };
267
+ }
293
268
 
294
- const finishWithError = (err: any) => {
295
- if (resolved) return;
296
- resolved = true;
297
- stopCallbackServer();
298
- const error = err?.code === 'EADDRINUSE'
299
- ? `Port ${OAUTH_CONFIG.PORT} is busy. Close other Codex instances.`
300
- : (err?.message || String(err));
301
- resolve({ success: false, error });
302
- };
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,
276
+ });
303
277
 
304
- for (const { host, required } of bindHosts) {
305
- const server = http.createServer(handleCallback);
306
-
307
- server.once('error', (err: any) => {
308
- log.warn(`Codex OAuth bind ${host}:${OAUTH_CONFIG.PORT} failed — ${err.code || err.message}`);
309
- if (required) {
310
- finishWithError(err);
311
- } else {
312
- bindFailures++;
313
- pendingBinds--;
314
- // If only the optional bind failed but we already have at least one
315
- // server up, that's still a success.
316
- if (pendingBinds === 0 && callbackServers.length > 0) finishWithSuccess();
317
- }
318
- });
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(),
282
+ });
319
283
 
320
- server.listen(OAUTH_CONFIG.PORT, host, () => {
321
- callbackServers.push(server);
322
- pendingBinds--;
323
- if (pendingBinds === 0) finishWithSuccess();
324
- });
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
+ };
325
291
  }
326
- });
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
+ }
327
306
  }
328
307
 
329
308
  export function cancelCodexOAuth(): void {
330
- stopCallbackServer();
331
309
  codeVerifier = null;
332
310
  oauthState = null;
333
311
  }
@@ -392,11 +370,258 @@ export function readCodexAccessToken(): string | null {
392
370
  return token;
393
371
  }
394
372
 
395
- /* ── Helpers ── */
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
+ }
396
432
 
397
- function stopCallbackServer(): void {
398
- for (const server of callbackServers) {
399
- try { server.close(); } catch {}
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 };
400
489
  }
401
- callbackServers = [];
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));
402
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 { startCodexOAuth, cancelCodexOAuth, getCodexAuthStatus } from './codex-auth.js';
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', async (_req, res) => {
175
- const result = await startCodexOAuth();
176
- res.json(result);
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) => {