bloby-bot 0.30.1 → 0.32.1

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 (348) 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/bloby-agent.ts +65 -633
  96. package/supervisor/chat/OnboardWizard.tsx +315 -69
  97. package/supervisor/harnesses/claude.ts +684 -0
  98. package/supervisor/harnesses/codex.ts +73 -0
  99. package/supervisor/harnesses/types.ts +81 -0
  100. package/supervisor/index.ts +1 -1
  101. package/worker/codex-auth.ts +362 -137
  102. package/worker/index.ts +30 -4
  103. package/dist-bloby/assets/angular-html-olSuI25H.js +0 -1
  104. package/dist-bloby/assets/c-BvB8CVo8.js +0 -1
  105. package/dist-bloby/assets/cpp-BblbpnyR.js +0 -1
  106. package/dist-bloby/assets/css-zY4NE9yA.js +0 -1
  107. package/dist-bloby/assets/globals-LpXKrQgt.css +0 -2
  108. package/dist-bloby/assets/globals-zKQhzQOX.js +0 -18
  109. package/dist-bloby/assets/glsl-CEMf-THb.js +0 -1
  110. package/dist-bloby/assets/graphql-dBCd2Czl.js +0 -1
  111. package/dist-bloby/assets/haml-Ck5pVAEG.js +0 -1
  112. package/dist-bloby/assets/highlighted-body-OFNGDK62-B0W8hCx-.js +0 -1
  113. package/dist-bloby/assets/html-CzX0w7K_.js +0 -1
  114. package/dist-bloby/assets/java-BqKEu7zh.js +0 -1
  115. package/dist-bloby/assets/javascript-CzjRtS1s.js +0 -1
  116. package/dist-bloby/assets/json-CdFmZMJc.js +0 -1
  117. package/dist-bloby/assets/jsx-BL6Wh6Qw.js +0 -1
  118. package/dist-bloby/assets/jsx-runtime-C0W9Wf2W.js +0 -1
  119. package/dist-bloby/assets/lua-B4ezzssg.js +0 -1
  120. package/dist-bloby/assets/mermaid-GHXKKRXX-Dr8I7wwH.js +0 -1
  121. package/dist-bloby/assets/onboard-C1yXK8uT.js +0 -1
  122. package/dist-bloby/assets/r-CGji9_vM.js +0 -1
  123. package/dist-bloby/assets/regexp-CvWG4lI-.js +0 -1
  124. package/dist-bloby/assets/scss-Efq7Dmbs.js +0 -1
  125. package/dist-bloby/assets/shellscript-BbEstezf.js +0 -1
  126. package/dist-bloby/assets/sql-CB6kO6Km.js +0 -1
  127. package/dist-bloby/assets/tsx-DrzBggF8.js +0 -1
  128. package/dist-bloby/assets/typescript-COZIw7xM.js +0 -1
  129. package/dist-bloby/assets/xml-BlDEvPia.js +0 -1
  130. package/dist-bloby/assets/yaml-iUXljnLs.js +0 -1
  131. /package/dist-bloby/assets/{abap-smLpETzL.js → abap--vzi7Rxy.js} +0 -0
  132. /package/dist-bloby/assets/{actionscript-3-o-aRvjY5.js → actionscript-3-CV21uODD.js} +0 -0
  133. /package/dist-bloby/assets/{ada-D5RRX1i4.js → ada-DpXSEmbw.js} +0 -0
  134. /package/dist-bloby/assets/{andromeeda-N4z3YzmR.js → andromeeda-C1V0Cb0M.js} +0 -0
  135. /package/dist-bloby/assets/{apache-DttKlSqg.js → apache-CRmVjs8c.js} +0 -0
  136. /package/dist-bloby/assets/{apex-DL7j-a2n.js → apex-DIIc4r7E.js} +0 -0
  137. /package/dist-bloby/assets/{applescript-DCbL_2FX.js → applescript-DMX6NGuU.js} +0 -0
  138. /package/dist-bloby/assets/{ara-DqheWJCe.js → ara-3SArX2Zn.js} +0 -0
  139. /package/dist-bloby/assets/{asciidoc-BH2sf2K4.js → asciidoc-CnVFjb7X.js} +0 -0
  140. /package/dist-bloby/assets/{asm-rfjOMz3U.js → asm-Cb-CgaBD.js} +0 -0
  141. /package/dist-bloby/assets/{aurora-x-CND-FqEb.js → aurora-x-CjvoFyi0.js} +0 -0
  142. /package/dist-bloby/assets/{awk-CMV5n9Z7.js → awk-BYjsWVhV.js} +0 -0
  143. /package/dist-bloby/assets/{ayu-dark-on7xzq_B.js → ayu-dark-C4UVdT_g.js} +0 -0
  144. /package/dist-bloby/assets/{ayu-light-DnGeGGc2.js → ayu-light-CFJ-dST-.js} +0 -0
  145. /package/dist-bloby/assets/{ayu-mirage-DG3LlYC_.js → ayu-mirage-BxM9D2Mi.js} +0 -0
  146. /package/dist-bloby/assets/{ballerina-BjMqJjlr.js → ballerina-BsKCUtAm.js} +0 -0
  147. /package/dist-bloby/assets/{bat-BaVbo_qw.js → bat-CJlQOahT.js} +0 -0
  148. /package/dist-bloby/assets/{beancount-DBt5Mbc_.js → beancount-Cyf6Xlzd.js} +0 -0
  149. /package/dist-bloby/assets/{berry-Cyjuxiss.js → berry-DHYmFnza.js} +0 -0
  150. /package/dist-bloby/assets/{bibtex-BV_0nsPq.js → bibtex-BUB9btZd.js} +0 -0
  151. /package/dist-bloby/assets/{bicep-C2gEwu4J.js → bicep-CNVX4dQj.js} +0 -0
  152. /package/dist-bloby/assets/{bird2-BRyaEJd0.js → bird2-LZP25z1s.js} +0 -0
  153. /package/dist-bloby/assets/{c3-DTTbp5N2.js → c3-BI41OB2W.js} +0 -0
  154. /package/dist-bloby/assets/{cadence-CPz83cmI.js → cadence-BDnzkZFt.js} +0 -0
  155. /package/dist-bloby/assets/{catppuccin-frappe-Dr22sraq.js → catppuccin-frappe-DpT1lCYX.js} +0 -0
  156. /package/dist-bloby/assets/{catppuccin-latte-C57EeX8c.js → catppuccin-latte-qMMse1WJ.js} +0 -0
  157. /package/dist-bloby/assets/{catppuccin-macchiato-CpheI4uD.js → catppuccin-macchiato-DMu0Ac9B.js} +0 -0
  158. /package/dist-bloby/assets/{catppuccin-mocha-D8Lmdks_.js → catppuccin-mocha-DicTaD9V.js} +0 -0
  159. /package/dist-bloby/assets/{clarity-CFJ2Yc3q.js → clarity-CPz-yzAn.js} +0 -0
  160. /package/dist-bloby/assets/{clojure-6R01QgJC.js → clojure-BxJLFKTj.js} +0 -0
  161. /package/dist-bloby/assets/{cmake-D5rSbMir.js → cmake-BmC4o4J9.js} +0 -0
  162. /package/dist-bloby/assets/{codeowners-_3A-ClkN.js → codeowners-BPHDuybI.js} +0 -0
  163. /package/dist-bloby/assets/{codeql-DlIhJTR7.js → codeql-DYWyWzRY.js} +0 -0
  164. /package/dist-bloby/assets/{common-lisp-BvQzz173.js → common-lisp-CsDdrwfa.js} +0 -0
  165. /package/dist-bloby/assets/{coq-DTNXReIC.js → coq-BZNwxllS.js} +0 -0
  166. /package/dist-bloby/assets/{csharp-BDKQY1K9.js → csharp-BLhQzhUA.js} +0 -0
  167. /package/dist-bloby/assets/{csv-DNUpVBxl.js → csv-DPc9UZFt.js} +0 -0
  168. /package/dist-bloby/assets/{cue-DDdBc2s3.js → cue-Bat8Mt8Y.js} +0 -0
  169. /package/dist-bloby/assets/{cypher-CguaznO2.js → cypher-CTnWkM4Y.js} +0 -0
  170. /package/dist-bloby/assets/{d-CHcoyjv3.js → d-CccbtpLU.js} +0 -0
  171. /package/dist-bloby/assets/{dark-plus-CqeW_0kH.js → dark-plus-CKh7uIvz.js} +0 -0
  172. /package/dist-bloby/assets/{dart-RM3aRphk.js → dart-SbRHwU1n.js} +0 -0
  173. /package/dist-bloby/assets/{dax-nbnY1d79.js → dax-vVKSTwd9.js} +0 -0
  174. /package/dist-bloby/assets/{desktop-BD76cvxT.js → desktop-rdWGepy4.js} +0 -0
  175. /package/dist-bloby/assets/{diff-CdkWtnkL.js → diff-G5H-0DNT.js} +0 -0
  176. /package/dist-bloby/assets/{docker-ZyPHc6zB.js → docker-CC20slQp.js} +0 -0
  177. /package/dist-bloby/assets/{dotenv-BdJZEwA6.js → dotenv-C36c6TdP.js} +0 -0
  178. /package/dist-bloby/assets/{dracula-CtqCPLGa.js → dracula-nNMQZYa7.js} +0 -0
  179. /package/dist-bloby/assets/{dracula-soft-DmBpwRAy.js → dracula-soft-BPmUsSlJ.js} +0 -0
  180. /package/dist-bloby/assets/{dream-maker-BJL4qlg3.js → dream-maker-DleGc9Hy.js} +0 -0
  181. /package/dist-bloby/assets/{emacs-lisp-_LyYa2Ky.js → emacs-lisp-D_QlcMHs.js} +0 -0
  182. /package/dist-bloby/assets/{everforest-dark-CrbyKk4n.js → everforest-dark-FkVvIMUl.js} +0 -0
  183. /package/dist-bloby/assets/{everforest-light-DRbSh8Tm.js → everforest-light-d3V1wTAd.js} +0 -0
  184. /package/dist-bloby/assets/{fennel-CC2BkRsS.js → fennel-BEssPROc.js} +0 -0
  185. /package/dist-bloby/assets/{fish-D2ZCzqcE.js → fish-Cz5yLEyJ.js} +0 -0
  186. /package/dist-bloby/assets/{fluent-DKAm3m7q.js → fluent-TGO8KajN.js} +0 -0
  187. /package/dist-bloby/assets/{fortran-free-form-BPTf0lbT.js → fortran-free-form-CHQXX5JB.js} +0 -0
  188. /package/dist-bloby/assets/{gdscript-CsadCSaZ.js → gdscript-DBkVGsC6.js} +0 -0
  189. /package/dist-bloby/assets/{gdshader-PfnN_8tR.js → gdshader-CWQhZP7Q.js} +0 -0
  190. /package/dist-bloby/assets/{genie-Bj-orPAV.js → genie-7iw14YxB.js} +0 -0
  191. /package/dist-bloby/assets/{gherkin-COVWpJ-Q.js → gherkin-D4AlAQSH.js} +0 -0
  192. /package/dist-bloby/assets/{github-dark-ipGuFGYC.js → github-dark-CpBni1SQ.js} +0 -0
  193. /package/dist-bloby/assets/{github-dark-default-DX3IG_X0.js → github-dark-default-Cr5Q59Ad.js} +0 -0
  194. /package/dist-bloby/assets/{github-dark-dimmed-CH6p_7ez.js → github-dark-dimmed-WEORr92a.js} +0 -0
  195. /package/dist-bloby/assets/{github-dark-high-contrast-Bg2sSao5.js → github-dark-high-contrast-uM2plAzl.js} +0 -0
  196. /package/dist-bloby/assets/{github-light-BxjqOQl0.js → github-light-BROm54vS.js} +0 -0
  197. /package/dist-bloby/assets/{github-light-default-DwpDd1IQ.js → github-light-default-jSwgX00f.js} +0 -0
  198. /package/dist-bloby/assets/{github-light-high-contrast-C0QeixPf.js → github-light-high-contrast-Bp9ESXtp.js} +0 -0
  199. /package/dist-bloby/assets/{gleam-BF2NigGj.js → gleam-D1LXnIj0.js} +0 -0
  200. /package/dist-bloby/assets/{gn-CMIt9roj.js → gn-CReOiE5m.js} +0 -0
  201. /package/dist-bloby/assets/{gnuplot-DgWlRTEj.js → gnuplot-DufViamc.js} +0 -0
  202. /package/dist-bloby/assets/{go-DLnOLj8q.js → go-DC_Zm44P.js} +0 -0
  203. /package/dist-bloby/assets/{groovy-B9qLWIkE.js → groovy-DEGDVBi0.js} +0 -0
  204. /package/dist-bloby/assets/{gruvbox-dark-hard-BIMX9ePb.js → gruvbox-dark-hard-C-zANgxR.js} +0 -0
  205. /package/dist-bloby/assets/{gruvbox-dark-medium-DxuwyVzM.js → gruvbox-dark-medium-DY7Z6TBK.js} +0 -0
  206. /package/dist-bloby/assets/{gruvbox-dark-soft-ba2fjht0.js → gruvbox-dark-soft-Bpj6owGh.js} +0 -0
  207. /package/dist-bloby/assets/{gruvbox-light-hard-DAJK2PqC.js → gruvbox-light-hard-DVwTvHam.js} +0 -0
  208. /package/dist-bloby/assets/{gruvbox-light-medium-WRifDAJD.js → gruvbox-light-medium-98PeoD5Y.js} +0 -0
  209. /package/dist-bloby/assets/{gruvbox-light-soft-B0dBOoVB.js → gruvbox-light-soft-BHI2PZTB.js} +0 -0
  210. /package/dist-bloby/assets/{haskell-BaGpmm_c.js → haskell-B-K-GoPf.js} +0 -0
  211. /package/dist-bloby/assets/{haxe-DfXTCEOz.js → haxe-md5t_Y_E.js} +0 -0
  212. /package/dist-bloby/assets/{hcl-CbCtpSbi.js → hcl-qSvp9jTg.js} +0 -0
  213. /package/dist-bloby/assets/{hjson-_4-w-pHU.js → hjson-BNeV6JDA.js} +0 -0
  214. /package/dist-bloby/assets/{hlsl-DpuYn7pp.js → hlsl-CFf5czm3.js} +0 -0
  215. /package/dist-bloby/assets/{horizon-C5RtD1fY.js → horizon-C4a2pCDo.js} +0 -0
  216. /package/dist-bloby/assets/{horizon-bright-pEOice34.js → horizon-bright-Bgpx-0aF.js} +0 -0
  217. /package/dist-bloby/assets/{houston-A0zg9vNP.js → houston-BZHNDhe5.js} +0 -0
  218. /package/dist-bloby/assets/{hy-t9zDXBje.js → hy-hI-CUgFt.js} +0 -0
  219. /package/dist-bloby/assets/{imba-Bxu-TDfw.js → imba-Dr5pZl3x.js} +0 -0
  220. /package/dist-bloby/assets/{ini-D-v34c8N.js → ini-KxzJ-qxg.js} +0 -0
  221. /package/dist-bloby/assets/{json5-D0XL1D5m.js → json5-SRM7tKmT.js} +0 -0
  222. /package/dist-bloby/assets/{jsonc-BBgf3TX3.js → jsonc-Cix1XnqC.js} +0 -0
  223. /package/dist-bloby/assets/{jsonl-KrKLbtB7.js → jsonl-BzKwo-fD.js} +0 -0
  224. /package/dist-bloby/assets/{jsonnet-B2ZwWMOt.js → jsonnet-DaiLv8or.js} +0 -0
  225. /package/dist-bloby/assets/{jssm-ByRpI9-B.js → jssm-B1pV58QJ.js} +0 -0
  226. /package/dist-bloby/assets/{kanagawa-dragon-CtPmcCMp.js → kanagawa-dragon-BihvT_N-.js} +0 -0
  227. /package/dist-bloby/assets/{kanagawa-lotus-DpOXEGCa.js → kanagawa-lotus-DQN_bzSt.js} +0 -0
  228. /package/dist-bloby/assets/{kanagawa-wave-CLVCyc-n.js → kanagawa-wave-Bvz_F3hD.js} +0 -0
  229. /package/dist-bloby/assets/{kdl-6FPPEH4H.js → kdl-DupMG4Bk.js} +0 -0
  230. /package/dist-bloby/assets/{kotlin-D4L3Nd2D.js → kotlin-rOGI_fXV.js} +0 -0
  231. /package/dist-bloby/assets/{kusto-D-mmc07O.js → kusto-CHXnQR8L.js} +0 -0
  232. /package/dist-bloby/assets/{laserwave-7fEj4XGb.js → laserwave-CPMyzJF3.js} +0 -0
  233. /package/dist-bloby/assets/{lean-BMVMuP2E.js → lean-B76KugVy.js} +0 -0
  234. /package/dist-bloby/assets/{less-C95PyOu0.js → less-DwUMKQAG.js} +0 -0
  235. /package/dist-bloby/assets/{light-plus-DHI2dh3p.js → light-plus-C6sdUQiS.js} +0 -0
  236. /package/dist-bloby/assets/{llvm-Dy3qORTl.js → llvm-DumY6MCH.js} +0 -0
  237. /package/dist-bloby/assets/{log-BQop7fzg.js → log-DdP6k-FU.js} +0 -0
  238. /package/dist-bloby/assets/{logo-DKtnYmrp.js → logo-Cx0gX691.js} +0 -0
  239. /package/dist-bloby/assets/{luau-Dha4KG0q.js → luau-CI4wJBxI.js} +0 -0
  240. /package/dist-bloby/assets/{make-DfmS6buu.js → make-BlyBJiAs.js} +0 -0
  241. /package/dist-bloby/assets/{markdown-BaI9LyM4.js → markdown-BFgBvytj.js} +0 -0
  242. /package/dist-bloby/assets/{material-theme-Dm6ETY8i.js → material-theme-CyGvAAeY.js} +0 -0
  243. /package/dist-bloby/assets/{material-theme-darker-BeyjmM5Z.js → material-theme-darker-DJAOSarR.js} +0 -0
  244. /package/dist-bloby/assets/{material-theme-lighter-CCOYYzKL.js → material-theme-lighter-Cb7t96j2.js} +0 -0
  245. /package/dist-bloby/assets/{material-theme-ocean-CUtPiiX3.js → material-theme-ocean-EZZ55_HD.js} +0 -0
  246. /package/dist-bloby/assets/{material-theme-palenight-2L4zMwIM.js → material-theme-palenight-DtmMSfya.js} +0 -0
  247. /package/dist-bloby/assets/{matlab-BT79Cq_j.js → matlab-BFLobVcp.js} +0 -0
  248. /package/dist-bloby/assets/{mdx-CxGBwLNt.js → mdx-Baux4qlv.js} +0 -0
  249. /package/dist-bloby/assets/{mermaid-DLf3axBN.js → mermaid-DHr7T0Rt.js} +0 -0
  250. /package/dist-bloby/assets/{min-dark-B8TUPGHg.js → min-dark-C9N1U4-e.js} +0 -0
  251. /package/dist-bloby/assets/{min-light-BDOoBxcA.js → min-light-Ce9oxBvH.js} +0 -0
  252. /package/dist-bloby/assets/{mipsasm-DXuU_0cI.js → mipsasm-Cgb1v7yV.js} +0 -0
  253. /package/dist-bloby/assets/{mojo-1Omp2pIo.js → mojo-BnTBKscO.js} +0 -0
  254. /package/dist-bloby/assets/{monokai-E_VBmXGZ.js → monokai-BGD_YBH-.js} +0 -0
  255. /package/dist-bloby/assets/{moonbit-DZzq699o.js → moonbit-HXw0ZM4h.js} +0 -0
  256. /package/dist-bloby/assets/{move-DxDAOJVd.js → move-DG2efXqI.js} +0 -0
  257. /package/dist-bloby/assets/{narrat-CxDcPPb9.js → narrat-BSasSB5t.js} +0 -0
  258. /package/dist-bloby/assets/{nextflow-groovy-wvmJO4hi.js → nextflow-groovy-DXLl8k8E.js} +0 -0
  259. /package/dist-bloby/assets/{night-owl-DefhalNX.js → night-owl-DxqNTXDa.js} +0 -0
  260. /package/dist-bloby/assets/{night-owl-light-byb3AbEn.js → night-owl-light-MPn8GCyh.js} +0 -0
  261. /package/dist-bloby/assets/{nix-DsFTDHWT.js → nix-BpnttlWr.js} +0 -0
  262. /package/dist-bloby/assets/{nord-D5rQzHT-.js → nord-Mt6M_qHE.js} +0 -0
  263. /package/dist-bloby/assets/{nushell-BQ_rO0AM.js → nushell-CS7Mvg-G.js} +0 -0
  264. /package/dist-bloby/assets/{objective-c-BMq6JT_m.js → objective-c-U4EuJXJs.js} +0 -0
  265. /package/dist-bloby/assets/{objective-cpp-DRwojuGv.js → objective-cpp-CE_PrXRW.js} +0 -0
  266. /package/dist-bloby/assets/{ocaml-e4_gKO6E.js → ocaml-ZsxDKzyv.js} +0 -0
  267. /package/dist-bloby/assets/{odin-mdTPwYOg.js → odin-CDoDiNYU.js} +0 -0
  268. /package/dist-bloby/assets/{one-dark-pro-DxXww9jg.js → one-dark-pro-B9P_I1yh.js} +0 -0
  269. /package/dist-bloby/assets/{one-light-D9c03w7t.js → one-light-Cv3j6GXq.js} +0 -0
  270. /package/dist-bloby/assets/{openscad-D2aTdNfr.js → openscad-CfJwW9dY.js} +0 -0
  271. /package/dist-bloby/assets/{pascal-D4n_G8vj.js → pascal-CjE0UTC7.js} +0 -0
  272. /package/dist-bloby/assets/{pkl-DcjhAp0L.js → pkl-BN6EkHr9.js} +0 -0
  273. /package/dist-bloby/assets/{plastic-uOsw7z1x.js → plastic-BCnZnfMk.js} +0 -0
  274. /package/dist-bloby/assets/{plsql-BSy3Ag0J.js → plsql-1LW-CqWM.js} +0 -0
  275. /package/dist-bloby/assets/{po-Be96RYkA.js → po-Cf5hRC9x.js} +0 -0
  276. /package/dist-bloby/assets/{poimandres-CyO4HORD.js → poimandres-B_zC30Vt.js} +0 -0
  277. /package/dist-bloby/assets/{polar-BmhMKWum.js → polar-S6fWkEw8.js} +0 -0
  278. /package/dist-bloby/assets/{postcss-BTQso3H9.js → postcss-cZXfRCsF.js} +0 -0
  279. /package/dist-bloby/assets/{powerquery-DVyQv3M2.js → powerquery-CoRQQdNP.js} +0 -0
  280. /package/dist-bloby/assets/{powershell-BmtCGJVD.js → powershell-B2VxwRch.js} +0 -0
  281. /package/dist-bloby/assets/{prisma-CCFA9rEj.js → prisma-sLrt38jj.js} +0 -0
  282. /package/dist-bloby/assets/{prolog-DWGEEo78.js → prolog-CL99toUJ.js} +0 -0
  283. /package/dist-bloby/assets/{proto-C3eop1kM.js → proto-CtiBQJNn.js} +0 -0
  284. /package/dist-bloby/assets/{puppet-C0_7Nv5A.js → puppet-BlbpxWq2.js} +0 -0
  285. /package/dist-bloby/assets/{purescript-Bv-B8yRw.js → purescript-DPcVkoDV.js} +0 -0
  286. /package/dist-bloby/assets/{python-CKg5r0C3.js → python-BLpCXkJ6.js} +0 -0
  287. /package/dist-bloby/assets/{qmldir-Cqfb4Lox.js → qmldir-BcwbwUc8.js} +0 -0
  288. /package/dist-bloby/assets/{qss-Csho9BH8.js → qss-erDfnnzG.js} +0 -0
  289. /package/dist-bloby/assets/{racket-D8-uWeQH.js → racket-Dch6VQku.js} +0 -0
  290. /package/dist-bloby/assets/{raku-Cj4JSa8p.js → raku-Db8mfsiE.js} +0 -0
  291. /package/dist-bloby/assets/{red-z4H4llUY.js → red-DWyyM82l.js} +0 -0
  292. /package/dist-bloby/assets/{reg-DXGFiJSl.js → reg-3F9yjO5J.js} +0 -0
  293. /package/dist-bloby/assets/{rel-CunnVTBK.js → rel-CQq8nxxL.js} +0 -0
  294. /package/dist-bloby/assets/{riscv-C8BcOCkS.js → riscv-CsUwotvK.js} +0 -0
  295. /package/dist-bloby/assets/{ron-DiDyR9oa.js → ron-BwlS4rWu.js} +0 -0
  296. /package/dist-bloby/assets/{rose-pine-BADquuIH.js → rose-pine-DEj8gOox.js} +0 -0
  297. /package/dist-bloby/assets/{rose-pine-dawn-BLcEeBoh.js → rose-pine-dawn-DjarqQ2I.js} +0 -0
  298. /package/dist-bloby/assets/{rose-pine-moon-BK_tLY1Y.js → rose-pine-moon-D7ffkR_D.js} +0 -0
  299. /package/dist-bloby/assets/{rosmsg-CHmL1Uyj.js → rosmsg-BmwwVMq5.js} +0 -0
  300. /package/dist-bloby/assets/{rust-DjJFInu3.js → rust-DsIgDjpj.js} +0 -0
  301. /package/dist-bloby/assets/{sass-D3xZ5o-v.js → sass-CkIFK_bT.js} +0 -0
  302. /package/dist-bloby/assets/{scala-B0IRml5w.js → scala-C0TSxhxD.js} +0 -0
  303. /package/dist-bloby/assets/{scheme-BhwcV3Av.js → scheme-e-5nJ58U.js} +0 -0
  304. /package/dist-bloby/assets/{sdbl-BmWYR-pI.js → sdbl-DOe8Nral.js} +0 -0
  305. /package/dist-bloby/assets/{slack-dark-DOnVms5P.js → slack-dark-CClHvLju.js} +0 -0
  306. /package/dist-bloby/assets/{slack-ochin-DcRTft4q.js → slack-ochin-DwCpSVBI.js} +0 -0
  307. /package/dist-bloby/assets/{smalltalk-DVQuUMII.js → smalltalk-fjkC4HKG.js} +0 -0
  308. /package/dist-bloby/assets/{snazzy-light-x9CLJ1W9.js → snazzy-light-2nD216w0.js} +0 -0
  309. /package/dist-bloby/assets/{solarized-dark-BB1sh-pe.js → solarized-dark-BkxMSETv.js} +0 -0
  310. /package/dist-bloby/assets/{solarized-light-9-RPS998.js → solarized-light-BScqQ1C4.js} +0 -0
  311. /package/dist-bloby/assets/{solidity-gQ4WXILB.js → solidity-DbOxJfAY.js} +0 -0
  312. /package/dist-bloby/assets/{splunk-OB48_RcD.js → splunk-BW0l10cw.js} +0 -0
  313. /package/dist-bloby/assets/{ssh-config-DA9YMRGV.js → ssh-config-XN7RWvZy.js} +0 -0
  314. /package/dist-bloby/assets/{stylus-sKwvsUaC.js → stylus-D69is74S.js} +0 -0
  315. /package/dist-bloby/assets/{swift-C72NbAtg.js → swift-CqNHAbQB.js} +0 -0
  316. /package/dist-bloby/assets/{synthwave-84-eJ9uRN_S.js → synthwave-84-Ct3Np89a.js} +0 -0
  317. /package/dist-bloby/assets/{system-verilog-CnWMF7Nq.js → system-verilog-CHbvBf8h.js} +0 -0
  318. /package/dist-bloby/assets/{systemd-DMzItW5N.js → systemd-BBC3Z_R4.js} +0 -0
  319. /package/dist-bloby/assets/{talonscript-DopQCWDL.js → talonscript-DhYQB2ic.js} +0 -0
  320. /package/dist-bloby/assets/{tasl-C28SYKbq.js → tasl-CNtai3BH.js} +0 -0
  321. /package/dist-bloby/assets/{tcl-DHq7zmoF.js → tcl-DFzyQSXW.js} +0 -0
  322. /package/dist-bloby/assets/{terraform-CogS1YKX.js → terraform-BijD6Khb.js} +0 -0
  323. /package/dist-bloby/assets/{tokyo-night-B9N7LyrF.js → tokyo-night-Dd5BGAxh.js} +0 -0
  324. /package/dist-bloby/assets/{toml-BH_iPsgK.js → toml-DZofdujH.js} +0 -0
  325. /package/dist-bloby/assets/{tsv-BIkdBZX1.js → tsv-DOp6g7sz.js} +0 -0
  326. /package/dist-bloby/assets/{turtle-CqNXyJWZ.js → turtle-BKcRDROw.js} +0 -0
  327. /package/dist-bloby/assets/{typespec-CQ9LYD_e.js → typespec-Mmt3-2Cw.js} +0 -0
  328. /package/dist-bloby/assets/{typst-T-Fsk-Sv.js → typst-CndOdNo_.js} +0 -0
  329. /package/dist-bloby/assets/{v-BhMEOw9x.js → v-DjlZIA0C.js} +0 -0
  330. /package/dist-bloby/assets/{vala-DzajMnwt.js → vala-C5Nm5NXo.js} +0 -0
  331. /package/dist-bloby/assets/{vb-7Xr8dEYW.js → vb-zZeWbE2_.js} +0 -0
  332. /package/dist-bloby/assets/{verilog-AvXtwZir.js → verilog-CyZIVfoz.js} +0 -0
  333. /package/dist-bloby/assets/{vesper-CtgQQ2sf.js → vesper-B0BMGbco.js} +0 -0
  334. /package/dist-bloby/assets/{vhdl-BHu0zg1P.js → vhdl-DH1mJdjZ.js} +0 -0
  335. /package/dist-bloby/assets/{viml-Di0QpLfC.js → viml-e-oP1x-l.js} +0 -0
  336. /package/dist-bloby/assets/{vitesse-black-jXdfyqgD.js → vitesse-black-BRAUsA4Q.js} +0 -0
  337. /package/dist-bloby/assets/{vitesse-dark-B88PxG1r.js → vitesse-dark-Dyg71HnT.js} +0 -0
  338. /package/dist-bloby/assets/{vitesse-light-BXxZh2iV.js → vitesse-light-BJKZKqvd.js} +0 -0
  339. /package/dist-bloby/assets/{vyper-C3R5yXgx.js → vyper-BRPzCrki.js} +0 -0
  340. /package/dist-bloby/assets/{wasm-Chsuwt1A.js → wasm-DYMpDie-.js} +0 -0
  341. /package/dist-bloby/assets/{wasm-CEUrWlVz.js → wasm-Drz0Uqci.js} +0 -0
  342. /package/dist-bloby/assets/{wenyan-BonVcr2i.js → wenyan-BiJ0NePu.js} +0 -0
  343. /package/dist-bloby/assets/{wgsl-D59WYmNq.js → wgsl-CNe_V6SG.js} +0 -0
  344. /package/dist-bloby/assets/{wikitext-ariTI2Wk.js → wikitext-DZrjZKWn.js} +0 -0
  345. /package/dist-bloby/assets/{wit-EA4fa3Dt.js → wit-BUTESHa8.js} +0 -0
  346. /package/dist-bloby/assets/{wolfram-DDp7LhyU.js → wolfram-COEZldPx.js} +0 -0
  347. /package/dist-bloby/assets/{zenscript-4WaROUyc.js → zenscript-DThCxjUC.js} +0 -0
  348. /package/dist-bloby/assets/{zig-CJoLJGwV.js → zig-Bu6QWpR2.js} +0 -0
@@ -0,0 +1,684 @@
1
+ /**
2
+ * Claude Agent SDK wrapper — v2 Long-lived Query Model
3
+ *
4
+ * Two modes:
5
+ * 1. Live Conversation (main chat + admin WhatsApp):
6
+ * Single long-lived query() per conversation. User messages pushed into async queue.
7
+ * Agent stays alive, processes messages as they arrive, reports sub-agent completions.
8
+ *
9
+ * 2. One-shot Query (customer WhatsApp, scheduler):
10
+ * Classic request-response: one query() per message. Backward compat.
11
+ */
12
+
13
+ import { query, type SDKMessage, type SDKUserMessage, type Options } from '@anthropic-ai/claude-agent-sdk';
14
+ import fs from 'fs';
15
+ import path from 'path';
16
+ import { log } from '../../shared/logger.js';
17
+ import { WORKSPACE_DIR } from '../../shared/paths.js';
18
+ import type { SavedFile } from '../file-saver.js';
19
+ import { getClaudeAccessToken } from '../../worker/claude-auth.js';
20
+ import { assembleSystemPrompt } from '../../worker/prompts/prompt-assembler.js';
21
+ import { buildAgents } from '../agents/index.js';
22
+ import { preWarm, claimWarmup, discardWarmup } from '../cli-warmup.js';
23
+
24
+ // ── Types ──────────────────────────────────────────────────────────────────
25
+
26
+ import type { RecentMessage, AgentAttachment } from './types.js';
27
+ export type { RecentMessage, AgentAttachment };
28
+
29
+ // ── Async Queue ────────────────────────────────────────────────────────────
30
+
31
+ interface AsyncQueue<T> extends AsyncIterable<T> {
32
+ push(item: T): void;
33
+ end(): void;
34
+ }
35
+
36
+ /** Create an async queue that can be used as an AsyncIterable prompt for the SDK */
37
+ function createAsyncQueue<T>(): AsyncQueue<T> {
38
+ const pending: T[] = [];
39
+ let resolve: ((value: IteratorResult<T>) => void) | null = null;
40
+ let done = false;
41
+
42
+ return {
43
+ push(item: T) {
44
+ if (done) return;
45
+ if (resolve) {
46
+ resolve({ value: item, done: false });
47
+ resolve = null;
48
+ } else {
49
+ pending.push(item);
50
+ }
51
+ },
52
+ end() {
53
+ done = true;
54
+ if (resolve) resolve({ value: undefined as any, done: true });
55
+ },
56
+ [Symbol.asyncIterator]() {
57
+ return {
58
+ next(): Promise<IteratorResult<T>> {
59
+ if (pending.length > 0) {
60
+ return Promise.resolve({ value: pending.shift()!, done: false });
61
+ }
62
+ if (done) return Promise.resolve({ value: undefined as any, done: true });
63
+ return new Promise((r) => { resolve = r; });
64
+ },
65
+ };
66
+ },
67
+ };
68
+ }
69
+
70
+ // ── Live Conversation Manager ──────────────────────────────────────────────
71
+
72
+ interface LiveConversation {
73
+ id: string;
74
+ inputQueue: AsyncQueue<SDKUserMessage>;
75
+ abortController: AbortController;
76
+ queryHandle: any;
77
+ onMessage: (type: string, data: any) => void;
78
+ /** True while the model is actively processing (between message push and result) */
79
+ busy: boolean;
80
+ }
81
+
82
+ const liveConversations = new Map<string, LiveConversation>();
83
+
84
+ /** Check if a live conversation exists */
85
+ export function hasConversation(conversationId: string): boolean {
86
+ return liveConversations.has(conversationId);
87
+ }
88
+
89
+ /** End all live conversations (e.g. after re-auth so they restart with fresh token) */
90
+ export function endAllConversations(): void {
91
+ for (const convId of liveConversations.keys()) {
92
+ log.info(`[conversation] Ending conversation ${convId} (auth changed)`);
93
+ endConversation(convId);
94
+ }
95
+ // The pre-warmed subprocess was initialized with the old OAuth token — drop it.
96
+ discardWarmup();
97
+ }
98
+
99
+ // ── Helpers ─────────────────────────────────────────────────────────────────
100
+
101
+ /** Read a memory file from workspace, returning '(empty)' if missing or empty */
102
+ function readMemoryFile(filename: string): string {
103
+ try {
104
+ const content = fs.readFileSync(path.join(WORKSPACE_DIR, filename), 'utf-8').trim();
105
+ return content || '(empty)';
106
+ } catch {
107
+ return '(empty)';
108
+ }
109
+ }
110
+
111
+ /** Read all memory + config files */
112
+ function readMemoryFiles() {
113
+ return {
114
+ myself: readMemoryFile('MYSELF.md'),
115
+ myhuman: readMemoryFile('MYHUMAN.md'),
116
+ memory: readMemoryFile('MEMORY.md'),
117
+ pulse: readMemoryFile('PULSE.json'),
118
+ crons: readMemoryFile('CRONS.json'),
119
+ };
120
+ }
121
+
122
+ /** Format recent messages as conversation history text */
123
+ function formatConversationHistory(messages: RecentMessage[]): string {
124
+ if (!messages.length) return '';
125
+ return messages.map((m) => `${m.role}: ${m.content}`).join('\n\n');
126
+ }
127
+
128
+ /** Load MCP server config from workspace/MCP.json */
129
+ function loadMcpServers(): Record<string, any> | undefined {
130
+ try {
131
+ const mcpConfigPath = path.join(WORKSPACE_DIR, 'MCP.json');
132
+ const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf-8'));
133
+ if (mcpConfig && typeof mcpConfig === 'object' && !Array.isArray(mcpConfig) && Object.keys(mcpConfig).length) {
134
+ return mcpConfig;
135
+ } else if (Array.isArray(mcpConfig) && mcpConfig.length) {
136
+ return Object.assign({}, ...mcpConfig);
137
+ }
138
+ } catch {}
139
+ return undefined;
140
+ }
141
+
142
+ /** Build an SDKUserMessage from text + optional attachments */
143
+ function buildUserMessage(text: string, attachments?: AgentAttachment[], savedFiles?: SavedFile[]): SDKUserMessage {
144
+ const content: any[] = [];
145
+
146
+ if (attachments?.length) {
147
+ for (const att of attachments) {
148
+ if (att.type === 'image') {
149
+ content.push({
150
+ type: 'image',
151
+ source: { type: 'base64', media_type: att.mediaType, data: att.data },
152
+ });
153
+ } else {
154
+ content.push({
155
+ type: 'document',
156
+ source: { type: 'base64', media_type: att.mediaType, data: att.data },
157
+ });
158
+ }
159
+ }
160
+ }
161
+
162
+ let promptText = text || '(attached files)';
163
+ if (savedFiles?.length) {
164
+ const lines = savedFiles.map((f) => `- ${f.name} -> ${f.relPath}`);
165
+ promptText += `\n\n[Attached files saved to disk]\n${lines.join('\n')}\nYou can read or reference these files using the paths above (relative to your cwd).`;
166
+ }
167
+
168
+ content.push({ type: 'text', text: promptText });
169
+
170
+ return {
171
+ type: 'user' as const,
172
+ message: { role: 'user' as const, content },
173
+ parent_tool_use_id: null,
174
+ } as SDKUserMessage;
175
+ }
176
+
177
+ // ── Live Conversation API ──────────────────────────────────────────────────
178
+
179
+ /**
180
+ * Build the options for a live conversation's query(). Shared by
181
+ * `startConversation` and the boot-time pre-warmer so a warmed subprocess
182
+ * has byte-identical options.
183
+ */
184
+ async function buildConversationOptions(
185
+ model: string,
186
+ oauthToken: string,
187
+ names?: { botName: string; humanName: string },
188
+ recentMessages?: RecentMessage[],
189
+ ): Promise<Omit<Options, 'abortController' | 'stderr'>> {
190
+ const memoryFiles = readMemoryFiles();
191
+ const basePrompt = await assembleSystemPrompt(names?.botName, names?.humanName);
192
+ let systemPrompt = basePrompt;
193
+ systemPrompt += `\n\n---\n# Your Memory Files\n\n## MYSELF.md\n${memoryFiles.myself}\n\n## MYHUMAN.md\n${memoryFiles.myhuman}\n\n## MEMORY.md\n${memoryFiles.memory}\n\n---\n# Your Config Files\n\n## PULSE.json\n${memoryFiles.pulse}\n\n## CRONS.json\n${memoryFiles.crons}`;
194
+
195
+ try {
196
+ const { loadConfig: loadCfg } = await import('../../shared/config.js');
197
+ const cfg = loadCfg();
198
+ const channels = (cfg as any).channels;
199
+ if (channels) {
200
+ systemPrompt += `\n\n---\n# Channel Config\n\`\`\`json\n${JSON.stringify(channels, null, 2)}\n\`\`\``;
201
+ }
202
+ } catch {}
203
+
204
+ if (recentMessages?.length) {
205
+ systemPrompt += `\n\n---\n# Recent Conversation\n${formatConversationHistory(recentMessages)}`;
206
+ }
207
+
208
+ const agents = buildAgents();
209
+ const mcpServers = loadMcpServers();
210
+
211
+ return {
212
+ model,
213
+ cwd: WORKSPACE_DIR,
214
+ permissionMode: 'bypassPermissions',
215
+ allowDangerouslySkipPermissions: true,
216
+ systemPrompt,
217
+ mcpServers,
218
+ agents,
219
+ agentProgressSummaries: true,
220
+ env: {
221
+ ...process.env as Record<string, string>,
222
+ CLAUDE_CODE_OAUTH_TOKEN: oauthToken,
223
+ CLAUDE_CODE_BUBBLEWRAP: '1',
224
+ },
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Pre-warm the Claude CLI subprocess for the next live conversation. Call
230
+ * fire-and-forget at supervisor boot (and after a conversation ends) so the
231
+ * first user message doesn't pay CLI startup latency.
232
+ */
233
+ export async function warmUpForLiveConversation(
234
+ model: string,
235
+ names?: { botName: string; humanName: string },
236
+ ): Promise<void> {
237
+ if (!model) return;
238
+ try {
239
+ const oauthToken = await getClaudeAccessToken();
240
+ if (!oauthToken) return;
241
+ const options = await buildConversationOptions(model, oauthToken, names);
242
+ await preWarm(options);
243
+ } catch (err: any) {
244
+ log.warn(`[conversation] Warm-up skipped: ${err?.message || err}`);
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Start a long-lived conversation.
250
+ * Creates a single query() with an async input queue.
251
+ * Messages are pushed via pushMessage(). The query stays alive until endConversation().
252
+ */
253
+ export async function startConversation(
254
+ conversationId: string,
255
+ model: string,
256
+ onMessage: (type: string, data: any) => void,
257
+ names?: { botName: string; humanName: string },
258
+ recentMessages?: RecentMessage[],
259
+ ): Promise<boolean> {
260
+ log.info(`[conversation] ──── STARTING CONVERSATION ────`);
261
+ log.info(`[conversation] Conv ID: ${conversationId}`);
262
+ log.info(`[conversation] Model: ${model}`);
263
+
264
+ // End any existing conversation with this ID
265
+ if (liveConversations.has(conversationId)) {
266
+ log.info(`[conversation] Ending existing conversation ${conversationId} before starting new one`);
267
+ endConversation(conversationId);
268
+ }
269
+
270
+ const oauthToken = await getClaudeAccessToken();
271
+ if (!oauthToken) {
272
+ log.warn('[conversation] No OAuth token — cannot start');
273
+ onMessage('bot:error', { conversationId, error: 'Claude OAuth token not found. Please authenticate via the dashboard.' });
274
+ return false;
275
+ }
276
+
277
+ const baseOptions = await buildConversationOptions(model, oauthToken, names, recentMessages);
278
+ const systemPromptLen = typeof baseOptions.systemPrompt === 'string' ? baseOptions.systemPrompt.length : 0;
279
+ log.info(`[conversation] Loaded ${Object.keys(baseOptions.agents || {}).length} sub-agent(s): ${Object.keys(baseOptions.agents || {}).join(', ')}`);
280
+ if (baseOptions.mcpServers) {
281
+ log.info(`[conversation] MCP servers: ${Object.keys(baseOptions.mcpServers).join(', ')}`);
282
+ }
283
+
284
+ // Try to claim a pre-warmed subprocess — its abortController is the one
285
+ // baked into the warm query and must be reused for end/abort to reach it.
286
+ const claimed = claimWarmup(baseOptions);
287
+ const abortController = claimed?.abortController ?? new AbortController();
288
+
289
+ // Create the async input queue
290
+ const inputQueue = createAsyncQueue<SDKUserMessage>();
291
+
292
+ // Store the conversation
293
+ const conv: LiveConversation = {
294
+ id: conversationId,
295
+ inputQueue,
296
+ abortController,
297
+ queryHandle: null,
298
+ onMessage,
299
+ busy: false,
300
+ };
301
+ liveConversations.set(conversationId, conv);
302
+
303
+ log.info(`[conversation] System prompt: ${systemPromptLen} chars`);
304
+ log.info(`[conversation] Starting long-lived query... (${claimed ? 'warm' : 'cold'})`);
305
+
306
+ // Run the for-await loop in the background (fire and forget)
307
+ (async () => {
308
+ let fullText = '';
309
+ const usedTools = new Set<string>();
310
+ let stderrBuf = '';
311
+
312
+ try {
313
+ const claudeQuery = claimed
314
+ ? claimed.warmQuery.query(inputQueue)
315
+ : query({
316
+ prompt: inputQueue,
317
+ options: {
318
+ ...baseOptions,
319
+ abortController,
320
+ stderr: (chunk: string) => { stderrBuf += chunk; },
321
+ },
322
+ });
323
+
324
+ conv.queryHandle = claudeQuery;
325
+ log.info(`[conversation] ──── QUERY LOOP STARTED ────`);
326
+
327
+ for await (const msg of claudeQuery) {
328
+ if (abortController.signal.aborted) {
329
+ log.info(`[conversation] Query aborted — exiting loop`);
330
+ break;
331
+ }
332
+
333
+ switch (msg.type) {
334
+ case 'assistant': {
335
+ const assistantMsg = msg.message;
336
+ if (!assistantMsg?.content) break;
337
+
338
+ for (const block of assistantMsg.content) {
339
+ if (block.type === 'text' && block.text) {
340
+ if (fullText && !fullText.endsWith('\n')) {
341
+ fullText += '\n\n';
342
+ onMessage('bot:token', { conversationId, token: '\n\n' });
343
+ }
344
+ fullText += block.text;
345
+ onMessage('bot:token', { conversationId, token: block.text });
346
+ } else if (block.type === 'tool_use') {
347
+ usedTools.add(block.name);
348
+ onMessage('bot:tool', { conversationId, name: block.name, input: block.input });
349
+ }
350
+ }
351
+ break;
352
+ }
353
+
354
+ case 'result': {
355
+ // Agent finished processing the current message
356
+ log.info(`[conversation] ──── TURN COMPLETE ────`);
357
+ log.info(`[conversation] Response length: ${fullText.length} chars`);
358
+ log.info(`[conversation] Tools used this turn: ${Array.from(usedTools).join(', ') || 'none'}`);
359
+
360
+ if (fullText) {
361
+ onMessage('bot:response', { conversationId, content: fullText });
362
+ fullText = '';
363
+ } else if (msg.subtype?.startsWith('error')) {
364
+ const errorText = (msg as any).errors?.join('; ') || 'Agent turn failed';
365
+ log.warn(`[conversation] Turn error: ${errorText}`);
366
+ onMessage('bot:error', { conversationId, error: errorText });
367
+ }
368
+
369
+ // Signal turn complete — backend restart + UI update
370
+ const FILE_TOOLS = ['Write', 'Edit'];
371
+ const usedFileTools = FILE_TOOLS.some((t) => usedTools.has(t));
372
+ onMessage('bot:turn-complete', { conversationId, usedFileTools });
373
+
374
+ // Reset per-turn state
375
+ usedTools.clear();
376
+ conv.busy = false;
377
+ log.info(`[conversation] Agent idle — waiting for next message`);
378
+ break;
379
+ }
380
+
381
+ case 'tool_progress':
382
+ onMessage('bot:tool', {
383
+ conversationId,
384
+ name: (msg as any).tool_name || 'working',
385
+ status: 'running',
386
+ });
387
+ break;
388
+
389
+ // ── Background sub-agent events ──
390
+ case 'system': {
391
+ const sysMsg = msg as any;
392
+ if (sysMsg.subtype === 'task_started') {
393
+ log.info(`[conversation] ──── SUB-AGENT STARTED ────`);
394
+ log.info(`[conversation] Task ID: ${sysMsg.task_id}`);
395
+ log.info(`[conversation] Description: ${sysMsg.description}`);
396
+ onMessage('bot:task-created', {
397
+ conversationId,
398
+ taskId: sysMsg.task_id,
399
+ description: sysMsg.description,
400
+ type: sysMsg.task_type,
401
+ });
402
+ } else if (sysMsg.subtype === 'task_progress') {
403
+ const summary = sysMsg.summary || sysMsg.last_tool_name || 'working';
404
+ log.info(`[conversation] Sub-agent ${sysMsg.task_id} | ${summary} | Tools: ${sysMsg.usage?.tool_uses || 0} | ${Math.round((sysMsg.usage?.duration_ms || 0) / 1000)}s`);
405
+ onMessage('bot:task-progress', {
406
+ conversationId,
407
+ taskId: sysMsg.task_id,
408
+ summary,
409
+ lastTool: sysMsg.last_tool_name,
410
+ usage: sysMsg.usage,
411
+ });
412
+ } else if (sysMsg.subtype === 'task_notification') {
413
+ log.info(`[conversation] ──── SUB-AGENT ${sysMsg.status?.toUpperCase()} ────`);
414
+ log.info(`[conversation] Task ID: ${sysMsg.task_id}`);
415
+ log.info(`[conversation] Status: ${sysMsg.status}`);
416
+ log.info(`[conversation] Summary: ${sysMsg.summary?.slice(0, 200)}`);
417
+ log.info(`[conversation] Tokens: ${sysMsg.usage?.total_tokens || 0} | Tools: ${sysMsg.usage?.tool_uses || 0} | Duration: ${Math.round((sysMsg.usage?.duration_ms || 0) / 1000)}s`);
418
+ onMessage('bot:task-done', {
419
+ conversationId,
420
+ taskId: sysMsg.task_id,
421
+ status: sysMsg.status,
422
+ summary: sysMsg.summary,
423
+ usage: sysMsg.usage,
424
+ });
425
+ // Sub-agent completion may have written files
426
+ if (sysMsg.status === 'completed') {
427
+ onMessage('bot:turn-complete', { conversationId, usedFileTools: true });
428
+ }
429
+ }
430
+ break;
431
+ }
432
+ }
433
+ }
434
+
435
+ log.info(`[conversation] ──── QUERY LOOP ENDED ────`);
436
+
437
+ // Send any remaining text
438
+ if (fullText && !abortController.signal.aborted) {
439
+ onMessage('bot:response', { conversationId, content: fullText });
440
+ }
441
+ } catch (err: any) {
442
+ if (!abortController.signal.aborted) {
443
+ const detail = stderrBuf.trim();
444
+ const errMsg = detail ? `${err.message}\n\nCLI stderr:\n${detail}` : err.message;
445
+ log.warn(`[conversation] Query error: ${errMsg}`);
446
+ onMessage('bot:error', { conversationId, error: errMsg });
447
+ }
448
+ } finally {
449
+ log.info(`[conversation] Cleaning up conversation ${conversationId}`);
450
+ liveConversations.delete(conversationId);
451
+ onMessage('bot:conversation-ended', { conversationId });
452
+ // Pre-warm a fresh subprocess for the next live conversation (fire-and-forget).
453
+ warmUpForLiveConversation(model, names);
454
+ }
455
+ })();
456
+
457
+ return true;
458
+ }
459
+
460
+ /**
461
+ * Push a user message into an existing live conversation.
462
+ * The agent will process it as part of the ongoing conversation.
463
+ */
464
+ export function pushMessage(
465
+ conversationId: string,
466
+ content: string,
467
+ attachments?: AgentAttachment[],
468
+ savedFiles?: SavedFile[],
469
+ ): boolean {
470
+ const conv = liveConversations.get(conversationId);
471
+ if (!conv) {
472
+ log.warn(`[conversation] pushMessage — no live conversation ${conversationId}`);
473
+ return false;
474
+ }
475
+
476
+ log.info(`[conversation] ──── PUSH MESSAGE ────`);
477
+ log.info(`[conversation] Conv: ${conversationId}`);
478
+ log.info(`[conversation] Content: "${content.slice(0, 100)}..."`);
479
+ log.info(`[conversation] Attachments: ${attachments?.length || 0}`);
480
+ log.info(`[conversation] Agent busy: ${conv.busy}`);
481
+
482
+ const userMessage = buildUserMessage(content, attachments, savedFiles);
483
+ conv.busy = true;
484
+ conv.inputQueue.push(userMessage);
485
+
486
+ // Emit typing indicator
487
+ conv.onMessage('bot:typing', { conversationId });
488
+
489
+ return true;
490
+ }
491
+
492
+ /** End a live conversation */
493
+ export function endConversation(conversationId: string): void {
494
+ const conv = liveConversations.get(conversationId);
495
+ if (!conv) return;
496
+
497
+ log.info(`[conversation] ──── ENDING CONVERSATION ────`);
498
+ log.info(`[conversation] Conv: ${conversationId}`);
499
+
500
+ conv.inputQueue.end();
501
+ conv.abortController.abort();
502
+ liveConversations.delete(conversationId);
503
+ }
504
+
505
+ /** Check if the agent is currently busy processing a message */
506
+ export function isConversationBusy(conversationId: string): boolean {
507
+ return liveConversations.get(conversationId)?.busy || false;
508
+ }
509
+
510
+ /** Stop a specific background sub-agent task */
511
+ export async function stopSubAgentTask(conversationId: string, taskId: string): Promise<void> {
512
+ const conv = liveConversations.get(conversationId);
513
+ if (conv?.queryHandle?.stopTask) {
514
+ log.info(`[conversation] Stopping sub-agent task: ${taskId}`);
515
+ await conv.queryHandle.stopTask(taskId);
516
+ } else {
517
+ log.warn(`[conversation] Cannot stop task ${taskId} — no live conversation ${conversationId}`);
518
+ }
519
+ }
520
+
521
+ // ── One-shot Query API (backward compat) ────────────────────────────────────
522
+ // Used by: customer WhatsApp (handleCustomerMessage), scheduler (triggerAgent)
523
+
524
+ interface ActiveQuery {
525
+ abortController: AbortController;
526
+ }
527
+
528
+ const activeQueries = new Map<string, ActiveQuery>();
529
+
530
+ /**
531
+ * Run a one-shot Agent SDK query (classic request-response).
532
+ * Used for customer-facing messages and scheduler triggers.
533
+ */
534
+ export async function startBlobyAgentQuery(
535
+ conversationId: string,
536
+ prompt: string,
537
+ model: string,
538
+ onMessage: (type: string, data: any) => void,
539
+ attachments?: AgentAttachment[],
540
+ savedFiles?: SavedFile[],
541
+ names?: { botName: string; humanName: string },
542
+ recentMessages?: RecentMessage[],
543
+ supportPrompt?: string,
544
+ maxTurns?: number,
545
+ ): Promise<void> {
546
+ const oauthToken = await getClaudeAccessToken();
547
+ if (!oauthToken) {
548
+ onMessage('bot:error', { conversationId, error: 'Claude OAuth token not found. Please authenticate via the dashboard.' });
549
+ return;
550
+ }
551
+
552
+ const abortController = new AbortController();
553
+ const memoryFiles = readMemoryFiles();
554
+
555
+ let enrichedPrompt: string;
556
+ if (supportPrompt) {
557
+ enrichedPrompt = supportPrompt;
558
+ } else {
559
+ const basePrompt = await assembleSystemPrompt(names?.botName, names?.humanName);
560
+ enrichedPrompt = basePrompt;
561
+ enrichedPrompt += `\n\n---\n# Your Memory Files\n\n## MYSELF.md\n${memoryFiles.myself}\n\n## MYHUMAN.md\n${memoryFiles.myhuman}\n\n## MEMORY.md\n${memoryFiles.memory}\n\n---\n# Your Config Files\n\n## PULSE.json\n${memoryFiles.pulse}\n\n## CRONS.json\n${memoryFiles.crons}`;
562
+
563
+ try {
564
+ const { loadConfig: loadCfg } = await import('../../shared/config.js');
565
+ const cfg = loadCfg();
566
+ const channels = (cfg as any).channels;
567
+ if (channels) {
568
+ enrichedPrompt += `\n\n---\n# Channel Config\n\`\`\`json\n${JSON.stringify(channels, null, 2)}\n\`\`\``;
569
+ }
570
+ } catch {}
571
+ }
572
+
573
+ if (recentMessages?.length) {
574
+ enrichedPrompt += `\n\n---\n# Recent Conversation\n${formatConversationHistory(recentMessages)}`;
575
+ }
576
+
577
+ activeQueries.set(conversationId, { abortController });
578
+
579
+ let fullText = '';
580
+ const usedTools = new Set<string>();
581
+ let stderrBuf = '';
582
+
583
+ let plainPrompt = prompt;
584
+ if (savedFiles?.length && !attachments?.length) {
585
+ const lines = savedFiles.map((f) => `- ${f.name} -> ${f.relPath}`);
586
+ plainPrompt += `\n\n[Attached files saved to disk]\n${lines.join('\n')}\nYou can read or reference these files using the paths above (relative to your cwd).`;
587
+ }
588
+
589
+ const sdkPrompt: string | AsyncIterable<SDKUserMessage> =
590
+ attachments?.length ? (async function* () {
591
+ yield buildUserMessage(prompt, attachments, savedFiles);
592
+ })() : plainPrompt;
593
+
594
+ try {
595
+ const mcpServers = loadMcpServers();
596
+ const effectiveMaxTurns = maxTurns ?? 50;
597
+
598
+ log.info(`[bloby-agent] One-shot query: conv=${conversationId}, maxTurns=${effectiveMaxTurns}`);
599
+
600
+ const claudeQuery = query({
601
+ prompt: sdkPrompt,
602
+ options: {
603
+ model,
604
+ cwd: WORKSPACE_DIR,
605
+ permissionMode: 'bypassPermissions',
606
+ allowDangerouslySkipPermissions: true,
607
+ maxTurns: effectiveMaxTurns,
608
+ abortController,
609
+ systemPrompt: enrichedPrompt,
610
+ mcpServers,
611
+ stderr: (chunk: string) => { stderrBuf += chunk; },
612
+ env: {
613
+ ...process.env as Record<string, string>,
614
+ CLAUDE_CODE_OAUTH_TOKEN: oauthToken,
615
+ CLAUDE_CODE_BUBBLEWRAP: '1',
616
+ },
617
+ },
618
+ });
619
+
620
+ onMessage('bot:typing', { conversationId });
621
+
622
+ for await (const msg of claudeQuery) {
623
+ if (abortController.signal.aborted) break;
624
+
625
+ switch (msg.type) {
626
+ case 'assistant': {
627
+ const assistantMsg = msg.message;
628
+ if (!assistantMsg?.content) break;
629
+ for (const block of assistantMsg.content) {
630
+ if (block.type === 'text' && block.text) {
631
+ if (fullText && !fullText.endsWith('\n')) {
632
+ fullText += '\n\n';
633
+ onMessage('bot:token', { conversationId, token: '\n\n' });
634
+ }
635
+ fullText += block.text;
636
+ onMessage('bot:token', { conversationId, token: block.text });
637
+ } else if (block.type === 'tool_use') {
638
+ usedTools.add(block.name);
639
+ onMessage('bot:tool', { conversationId, name: block.name, input: block.input });
640
+ }
641
+ }
642
+ break;
643
+ }
644
+ case 'result': {
645
+ if (fullText) {
646
+ onMessage('bot:response', { conversationId, content: fullText });
647
+ fullText = '';
648
+ } else if (msg.subtype?.startsWith('error')) {
649
+ onMessage('bot:error', { conversationId, error: (msg as any).errors?.join('; ') || 'Agent query failed' });
650
+ }
651
+ break;
652
+ }
653
+ case 'tool_progress':
654
+ onMessage('bot:tool', { conversationId, name: (msg as any).tool_name || 'working', status: 'running' });
655
+ break;
656
+ }
657
+ }
658
+
659
+ if (fullText && !abortController.signal.aborted) {
660
+ onMessage('bot:response', { conversationId, content: fullText });
661
+ }
662
+ } catch (err: any) {
663
+ if (!abortController.signal.aborted) {
664
+ const detail = stderrBuf.trim();
665
+ const errMsg = detail ? `${err.message}\n\nCLI stderr:\n${detail}` : err.message;
666
+ log.warn(`Bloby agent error (${conversationId}): ${errMsg}`);
667
+ onMessage('bot:error', { conversationId, error: errMsg });
668
+ }
669
+ } finally {
670
+ activeQueries.delete(conversationId);
671
+ const FILE_TOOLS = ['Write', 'Edit'];
672
+ const usedFileTools = FILE_TOOLS.some((t) => usedTools.has(t));
673
+ onMessage('bot:done', { conversationId, usedFileTools });
674
+ }
675
+ }
676
+
677
+ /** Stop a one-shot query */
678
+ export function stopBlobyAgentQuery(conversationId: string): void {
679
+ const q = activeQueries.get(conversationId);
680
+ if (q) {
681
+ q.abortController.abort();
682
+ activeQueries.delete(conversationId);
683
+ }
684
+ }