@openpalm/ui 0.11.0-rc.4 → 0.11.0-rc.6

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 (252) hide show
  1. package/build/.openpalm-ui-version +1 -1
  2. package/build/client/_app/immutable/chunks/{DTwNbG18.js → CJ4t2a2c.js} +1 -1
  3. package/build/client/_app/immutable/chunks/CJ4t2a2c.js.br +0 -0
  4. package/build/client/_app/immutable/chunks/CJ4t2a2c.js.gz +0 -0
  5. package/build/client/_app/immutable/chunks/{DKrt-Ofe.js → D6tVMRB1.js} +2 -2
  6. package/build/client/_app/immutable/chunks/D6tVMRB1.js.br +0 -0
  7. package/build/client/_app/immutable/chunks/D6tVMRB1.js.gz +0 -0
  8. package/build/client/_app/immutable/chunks/{CmvkId2p.js → DtQA2RPv.js} +1 -1
  9. package/build/client/_app/immutable/chunks/DtQA2RPv.js.br +0 -0
  10. package/build/client/_app/immutable/chunks/DtQA2RPv.js.gz +0 -0
  11. package/build/client/_app/immutable/entry/{app.D2QrHH7_.js → app.DaV1p_yf.js} +2 -2
  12. package/build/client/_app/immutable/entry/app.DaV1p_yf.js.br +0 -0
  13. package/build/client/_app/immutable/entry/app.DaV1p_yf.js.gz +0 -0
  14. package/build/client/_app/immutable/entry/start.DwrTolTH.js +1 -0
  15. package/build/client/_app/immutable/entry/start.DwrTolTH.js.br +0 -0
  16. package/build/client/_app/immutable/entry/start.DwrTolTH.js.gz +0 -0
  17. package/build/client/_app/immutable/nodes/{1.vc1gswpN.js → 1.BcYYXdgz.js} +1 -1
  18. package/build/client/_app/immutable/nodes/1.BcYYXdgz.js.br +0 -0
  19. package/build/client/_app/immutable/nodes/1.BcYYXdgz.js.gz +0 -0
  20. package/build/client/_app/immutable/nodes/{4.DD0APCkW.js → 4.Cttl54lU.js} +1 -1
  21. package/build/client/_app/immutable/nodes/4.Cttl54lU.js.br +0 -0
  22. package/build/client/_app/immutable/nodes/{4.DD0APCkW.js.gz → 4.Cttl54lU.js.gz} +0 -0
  23. package/build/client/_app/immutable/nodes/{5.BIkQUR1G.js → 5.dN79W272.js} +1 -1
  24. package/build/client/_app/immutable/nodes/5.dN79W272.js.br +0 -0
  25. package/build/client/_app/immutable/nodes/5.dN79W272.js.gz +0 -0
  26. package/build/client/_app/immutable/nodes/{6.DVDakR8k.js → 6.CyAbk8Zx.js} +1 -1
  27. package/build/client/_app/immutable/nodes/6.CyAbk8Zx.js.br +0 -0
  28. package/build/client/_app/immutable/nodes/6.CyAbk8Zx.js.gz +0 -0
  29. package/build/client/_app/immutable/nodes/{7.wMxDFXAt.js → 7.BiwhNQmS.js} +1 -1
  30. package/build/client/_app/immutable/nodes/7.BiwhNQmS.js.br +0 -0
  31. package/build/client/_app/immutable/nodes/7.BiwhNQmS.js.gz +0 -0
  32. package/build/client/_app/immutable/nodes/{8.Cb4MWMah.js → 8.DNsQWKjK.js} +1 -1
  33. package/build/client/_app/immutable/nodes/8.DNsQWKjK.js.br +0 -0
  34. package/build/client/_app/immutable/nodes/{8.Cb4MWMah.js.gz → 8.DNsQWKjK.js.gz} +0 -0
  35. package/build/client/_app/version.json +1 -1
  36. package/build/client/_app/version.json.br +1 -1
  37. package/build/client/_app/version.json.gz +0 -0
  38. package/build/server/chunks/1-DrJ3Bkxz.js +9 -0
  39. package/build/server/chunks/{1-BwC-cEPZ.js.map → 1-DrJ3Bkxz.js.map} +1 -1
  40. package/build/server/chunks/{4-BHTk326s.js → 4-CrmPw4La.js} +3 -3
  41. package/build/server/chunks/{4-BHTk326s.js.map → 4-CrmPw4La.js.map} +1 -1
  42. package/build/server/chunks/{5-BZDwO3BH.js → 5-CtHPRN1L.js} +3 -3
  43. package/build/server/chunks/{5-BZDwO3BH.js.map → 5-CtHPRN1L.js.map} +1 -1
  44. package/build/server/chunks/{6-DtvUY6SF.js → 6-CO8aswdn.js} +3 -3
  45. package/build/server/chunks/{6-DtvUY6SF.js.map → 6-CO8aswdn.js.map} +1 -1
  46. package/build/server/chunks/{7-C9TeiPbc.js → 7-hc1cB6hI.js} +3 -3
  47. package/build/server/chunks/{7-C9TeiPbc.js.map → 7-hc1cB6hI.js.map} +1 -1
  48. package/build/server/chunks/{8-CF5kn4AY.js → 8-b9MOJ1zI.js} +2 -2
  49. package/build/server/chunks/{8-CF5kn4AY.js.map → 8-b9MOJ1zI.js.map} +1 -1
  50. package/build/server/chunks/{AuthGate-CdtQ21Tn.js → AuthGate-DZ0ZMuag.js} +3 -3
  51. package/build/server/chunks/{AuthGate-CdtQ21Tn.js.map → AuthGate-DZ0ZMuag.js.map} +1 -1
  52. package/build/server/chunks/{_page.svelte-2puUmKay.js → _page.svelte-0LBL-kWB.js} +5 -5
  53. package/build/server/chunks/{_page.svelte-2puUmKay.js.map → _page.svelte-0LBL-kWB.js.map} +1 -1
  54. package/build/server/chunks/{_page.svelte-DkYHUL4U.js → _page.svelte-CCe0W6d_.js} +4 -4
  55. package/build/server/chunks/{_page.svelte-DkYHUL4U.js.map → _page.svelte-CCe0W6d_.js.map} +1 -1
  56. package/build/server/chunks/{_page.svelte-Cb3M2n38.js → _page.svelte-Cj-Ei5f0.js} +4 -4
  57. package/build/server/chunks/{_page.svelte-Cb3M2n38.js.map → _page.svelte-Cj-Ei5f0.js.map} +1 -1
  58. package/build/server/chunks/_page.svelte-D0gMlmzQ.js.map +1 -1
  59. package/build/server/chunks/{_page.svelte-DYWY35Zz.js → _page.svelte-oqyV-Sbu.js} +4 -4
  60. package/build/server/chunks/{_page.svelte-DYWY35Zz.js.map → _page.svelte-oqyV-Sbu.js.map} +1 -1
  61. package/build/server/chunks/{_server.ts-DgTJfsxX.js → _server.ts-19QmVay0.js} +5 -5
  62. package/build/server/chunks/{_server.ts-DgTJfsxX.js.map → _server.ts-19QmVay0.js.map} +1 -1
  63. package/build/server/chunks/{_server.ts-djChqJ3l.js → _server.ts-3XBYy8_r.js} +4 -4
  64. package/build/server/chunks/{_server.ts-djChqJ3l.js.map → _server.ts-3XBYy8_r.js.map} +1 -1
  65. package/build/server/chunks/{_server.ts-FzTKvasI.js → _server.ts-8jHBLHCk.js} +5 -5
  66. package/build/server/chunks/{_server.ts-FzTKvasI.js.map → _server.ts-8jHBLHCk.js.map} +1 -1
  67. package/build/server/chunks/{_server.ts-Br304l_4.js → _server.ts-B2zo-DK5.js} +3 -3
  68. package/build/server/chunks/{_server.ts-Br304l_4.js.map → _server.ts-B2zo-DK5.js.map} +1 -1
  69. package/build/server/chunks/{_server.ts-BajIVU3T.js → _server.ts-B395XNkL.js} +4 -4
  70. package/build/server/chunks/{_server.ts-BajIVU3T.js.map → _server.ts-B395XNkL.js.map} +1 -1
  71. package/build/server/chunks/{_server.ts-BheY_Hpx.js → _server.ts-B3QTVRYG.js} +4 -4
  72. package/build/server/chunks/{_server.ts-BheY_Hpx.js.map → _server.ts-B3QTVRYG.js.map} +1 -1
  73. package/build/server/chunks/{_server.ts-B4-U2IgV.js → _server.ts-B3k7cThn.js} +4 -4
  74. package/build/server/chunks/{_server.ts-B4-U2IgV.js.map → _server.ts-B3k7cThn.js.map} +1 -1
  75. package/build/server/chunks/{_server.ts-CZVFChDK.js → _server.ts-B45wZgyy.js} +5 -5
  76. package/build/server/chunks/{_server.ts-CZVFChDK.js.map → _server.ts-B45wZgyy.js.map} +1 -1
  77. package/build/server/chunks/{_server.ts-DGwGBkiZ.js → _server.ts-B6qNkB4n.js} +2 -2
  78. package/build/server/chunks/{_server.ts-DGwGBkiZ.js.map → _server.ts-B6qNkB4n.js.map} +1 -1
  79. package/build/server/chunks/{_server.ts-DGvfj1AD.js → _server.ts-B8HFj-Dx.js} +4 -4
  80. package/build/server/chunks/{_server.ts-DGvfj1AD.js.map → _server.ts-B8HFj-Dx.js.map} +1 -1
  81. package/build/server/chunks/{_server.ts-CED6YvVP.js → _server.ts-BETfAVwa.js} +4 -4
  82. package/build/server/chunks/{_server.ts-CED6YvVP.js.map → _server.ts-BETfAVwa.js.map} +1 -1
  83. package/build/server/chunks/{_server.ts-DglztWzk.js → _server.ts-BRK4Ir_R.js} +4 -4
  84. package/build/server/chunks/{_server.ts-DglztWzk.js.map → _server.ts-BRK4Ir_R.js.map} +1 -1
  85. package/build/server/chunks/{_server.ts-31Ih8YM7.js → _server.ts-BVLer_FF.js} +6 -6
  86. package/build/server/chunks/{_server.ts-31Ih8YM7.js.map → _server.ts-BVLer_FF.js.map} +1 -1
  87. package/build/server/chunks/{_server.ts-uLRX2uy0.js → _server.ts-BYVcXj0z.js} +2 -2
  88. package/build/server/chunks/{_server.ts-uLRX2uy0.js.map → _server.ts-BYVcXj0z.js.map} +1 -1
  89. package/build/server/chunks/{_server.ts-ZcRUavo2.js → _server.ts-BgjZfCV7.js} +4 -4
  90. package/build/server/chunks/{_server.ts-ZcRUavo2.js.map → _server.ts-BgjZfCV7.js.map} +1 -1
  91. package/build/server/chunks/{_server.ts-Cct9ZWnS.js → _server.ts-BkL5Ectn.js} +4 -4
  92. package/build/server/chunks/{_server.ts-Cct9ZWnS.js.map → _server.ts-BkL5Ectn.js.map} +1 -1
  93. package/build/server/chunks/{_server.ts-BPbPm6_H.js → _server.ts-BlC-qzze.js} +4 -4
  94. package/build/server/chunks/{_server.ts-BPbPm6_H.js.map → _server.ts-BlC-qzze.js.map} +1 -1
  95. package/build/server/chunks/{_server.ts-DG6Qxh-v.js → _server.ts-BoZlbX_k.js} +4 -4
  96. package/build/server/chunks/{_server.ts-DG6Qxh-v.js.map → _server.ts-BoZlbX_k.js.map} +1 -1
  97. package/build/server/chunks/{_server.ts-XmCgdAim.js → _server.ts-BviOfIbS.js} +4 -4
  98. package/build/server/chunks/{_server.ts-XmCgdAim.js.map → _server.ts-BviOfIbS.js.map} +1 -1
  99. package/build/server/chunks/{_server.ts-CCMxf_7S.js → _server.ts-BwGHtnRM.js} +4 -4
  100. package/build/server/chunks/{_server.ts-CCMxf_7S.js.map → _server.ts-BwGHtnRM.js.map} +1 -1
  101. package/build/server/chunks/{_server.ts-CD9ePvQZ.js → _server.ts-C10Bwaam.js} +4 -4
  102. package/build/server/chunks/{_server.ts-CD9ePvQZ.js.map → _server.ts-C10Bwaam.js.map} +1 -1
  103. package/build/server/chunks/{_server.ts-CLzZwKQq.js → _server.ts-C1Tej7yY.js} +6 -6
  104. package/build/server/chunks/{_server.ts-CLzZwKQq.js.map → _server.ts-C1Tej7yY.js.map} +1 -1
  105. package/build/server/chunks/{_server.ts-UM7mXEsQ.js → _server.ts-C1dtzbLs.js} +5 -5
  106. package/build/server/chunks/{_server.ts-UM7mXEsQ.js.map → _server.ts-C1dtzbLs.js.map} +1 -1
  107. package/build/server/chunks/{_server.ts-lmcyfcf5.js → _server.ts-C3dlXrHW.js} +4 -4
  108. package/build/server/chunks/{_server.ts-lmcyfcf5.js.map → _server.ts-C3dlXrHW.js.map} +1 -1
  109. package/build/server/chunks/{_server.ts-CBKtVzEl.js → _server.ts-C41Rea-i.js} +4 -4
  110. package/build/server/chunks/{_server.ts-CBKtVzEl.js.map → _server.ts-C41Rea-i.js.map} +1 -1
  111. package/build/server/chunks/{_server.ts-BUzhYY5b.js → _server.ts-C5bAGAi7.js} +4 -4
  112. package/build/server/chunks/{_server.ts-BUzhYY5b.js.map → _server.ts-C5bAGAi7.js.map} +1 -1
  113. package/build/server/chunks/{_server.ts-CzmHtvBP.js → _server.ts-C9GXq1YZ.js} +4 -4
  114. package/build/server/chunks/{_server.ts-CzmHtvBP.js.map → _server.ts-C9GXq1YZ.js.map} +1 -1
  115. package/build/server/chunks/{_server.ts-B5ewU2jA.js → _server.ts-CDbwBsKE.js} +4 -4
  116. package/build/server/chunks/{_server.ts-B5ewU2jA.js.map → _server.ts-CDbwBsKE.js.map} +1 -1
  117. package/build/server/chunks/{_server.ts-CoCYLLcy.js → _server.ts-CTMWM7jo.js} +4 -4
  118. package/build/server/chunks/{_server.ts-CoCYLLcy.js.map → _server.ts-CTMWM7jo.js.map} +1 -1
  119. package/build/server/chunks/{_server.ts-D2a0wAaS.js → _server.ts-CUuEa0Vv.js} +4 -4
  120. package/build/server/chunks/{_server.ts-D2a0wAaS.js.map → _server.ts-CUuEa0Vv.js.map} +1 -1
  121. package/build/server/chunks/{_server.ts-BnsyzAfd.js → _server.ts-CZLR8h_a.js} +4 -4
  122. package/build/server/chunks/{_server.ts-BnsyzAfd.js.map → _server.ts-CZLR8h_a.js.map} +1 -1
  123. package/build/server/chunks/{_server.ts-7YQtir-c.js → _server.ts-CboC8Emy.js} +6 -6
  124. package/build/server/chunks/{_server.ts-7YQtir-c.js.map → _server.ts-CboC8Emy.js.map} +1 -1
  125. package/build/server/chunks/{_server.ts-VHHuwb3V.js → _server.ts-CeRAfDvp.js} +4 -4
  126. package/build/server/chunks/{_server.ts-VHHuwb3V.js.map → _server.ts-CeRAfDvp.js.map} +1 -1
  127. package/build/server/chunks/{_server.ts-CmcnDpcq.js → _server.ts-CejCgHrV.js} +4 -4
  128. package/build/server/chunks/{_server.ts-CmcnDpcq.js.map → _server.ts-CejCgHrV.js.map} +1 -1
  129. package/build/server/chunks/{_server.ts-Broe0WRV.js → _server.ts-Cj7yoyyc.js} +4 -4
  130. package/build/server/chunks/{_server.ts-Broe0WRV.js.map → _server.ts-Cj7yoyyc.js.map} +1 -1
  131. package/build/server/chunks/{_server.ts-DIt7oZ78.js → _server.ts-Cp1Z8TiT.js} +4 -4
  132. package/build/server/chunks/{_server.ts-DIt7oZ78.js.map → _server.ts-Cp1Z8TiT.js.map} +1 -1
  133. package/build/server/chunks/{_server.ts-Cc4BIEOJ.js → _server.ts-CpKo_OmL.js} +4 -4
  134. package/build/server/chunks/{_server.ts-Cc4BIEOJ.js.map → _server.ts-CpKo_OmL.js.map} +1 -1
  135. package/build/server/chunks/{_server.ts-zY_DK-6S.js → _server.ts-Css6k_3m.js} +4 -4
  136. package/build/server/chunks/{_server.ts-zY_DK-6S.js.map → _server.ts-Css6k_3m.js.map} +1 -1
  137. package/build/server/chunks/{_server.ts-BdqgSniA.js → _server.ts-D4fc4Lga.js} +4 -4
  138. package/build/server/chunks/{_server.ts-BdqgSniA.js.map → _server.ts-D4fc4Lga.js.map} +1 -1
  139. package/build/server/chunks/{_server.ts-CHxBpqNs.js → _server.ts-D7qmDX8Q.js} +4 -4
  140. package/build/server/chunks/{_server.ts-CHxBpqNs.js.map → _server.ts-D7qmDX8Q.js.map} +1 -1
  141. package/build/server/chunks/{_server.ts-sAx1xFio.js → _server.ts-D9ykShFh.js} +4 -4
  142. package/build/server/chunks/{_server.ts-sAx1xFio.js.map → _server.ts-D9ykShFh.js.map} +1 -1
  143. package/build/server/chunks/{_server.ts-D2eLvAHH.js → _server.ts-DAOUg3-k.js} +4 -4
  144. package/build/server/chunks/{_server.ts-D2eLvAHH.js.map → _server.ts-DAOUg3-k.js.map} +1 -1
  145. package/build/server/chunks/{_server.ts-DW3vY8LS.js → _server.ts-DDfVjae-.js} +2 -2
  146. package/build/server/chunks/{_server.ts-DW3vY8LS.js.map → _server.ts-DDfVjae-.js.map} +1 -1
  147. package/build/server/chunks/{_server.ts-CJa40B0Z.js → _server.ts-DJ7YX-XH.js} +4 -4
  148. package/build/server/chunks/{_server.ts-CJa40B0Z.js.map → _server.ts-DJ7YX-XH.js.map} +1 -1
  149. package/build/server/chunks/{_server.ts-BN0-6jX7.js → _server.ts-DJsZ93rI.js} +4 -4
  150. package/build/server/chunks/{_server.ts-BN0-6jX7.js.map → _server.ts-DJsZ93rI.js.map} +1 -1
  151. package/build/server/chunks/{_server.ts-D2MVikBE.js → _server.ts-DUCEhzWJ.js} +4 -4
  152. package/build/server/chunks/{_server.ts-D2MVikBE.js.map → _server.ts-DUCEhzWJ.js.map} +1 -1
  153. package/build/server/chunks/{_server.ts-CsB6omUv.js → _server.ts-D_ktEzQJ.js} +4 -4
  154. package/build/server/chunks/{_server.ts-CsB6omUv.js.map → _server.ts-D_ktEzQJ.js.map} +1 -1
  155. package/build/server/chunks/{_server.ts-BwNngfUJ.js → _server.ts-DjqRdwzV.js} +4 -4
  156. package/build/server/chunks/{_server.ts-BwNngfUJ.js.map → _server.ts-DjqRdwzV.js.map} +1 -1
  157. package/build/server/chunks/{_server.ts-BHy1FIWT.js → _server.ts-DkOQZuRC.js} +4 -4
  158. package/build/server/chunks/{_server.ts-BHy1FIWT.js.map → _server.ts-DkOQZuRC.js.map} +1 -1
  159. package/build/server/chunks/{_server.ts-BNHq_0XB.js → _server.ts-DkZ1Mmoh.js} +5 -5
  160. package/build/server/chunks/{_server.ts-BNHq_0XB.js.map → _server.ts-DkZ1Mmoh.js.map} +1 -1
  161. package/build/server/chunks/{_server.ts-C6WJsZ0G.js → _server.ts-DnY4rmOV.js} +6 -6
  162. package/build/server/chunks/{_server.ts-C6WJsZ0G.js.map → _server.ts-DnY4rmOV.js.map} +1 -1
  163. package/build/server/chunks/{_server.ts-B7hqA-QH.js → _server.ts-DnpsO93M.js} +4 -4
  164. package/build/server/chunks/{_server.ts-B7hqA-QH.js.map → _server.ts-DnpsO93M.js.map} +1 -1
  165. package/build/server/chunks/{_server.ts-DUC-QWMj.js → _server.ts-Dp3aS528.js} +4 -4
  166. package/build/server/chunks/{_server.ts-DUC-QWMj.js.map → _server.ts-Dp3aS528.js.map} +1 -1
  167. package/build/server/chunks/{_server.ts-R7dMpaPA.js → _server.ts-DrBuaoVz.js} +2 -2
  168. package/build/server/chunks/{_server.ts-R7dMpaPA.js.map → _server.ts-DrBuaoVz.js.map} +1 -1
  169. package/build/server/chunks/{_server.ts-DStLQ6G7.js → _server.ts-DrhLq9je.js} +4 -4
  170. package/build/server/chunks/{_server.ts-DStLQ6G7.js.map → _server.ts-DrhLq9je.js.map} +1 -1
  171. package/build/server/chunks/{_server.ts-ncFk6KuU.js → _server.ts-Dzi_uR57.js} +4 -4
  172. package/build/server/chunks/{_server.ts-ncFk6KuU.js.map → _server.ts-Dzi_uR57.js.map} +1 -1
  173. package/build/server/chunks/{_server.ts-CuVTkFXh.js → _server.ts-E9Jx4RZl.js} +4 -4
  174. package/build/server/chunks/{_server.ts-CuVTkFXh.js.map → _server.ts-E9Jx4RZl.js.map} +1 -1
  175. package/build/server/chunks/{_server.ts-DbBkQ5gv.js → _server.ts-I4AR1K-d.js} +4 -4
  176. package/build/server/chunks/{_server.ts-DbBkQ5gv.js.map → _server.ts-I4AR1K-d.js.map} +1 -1
  177. package/build/server/chunks/{_server.ts-DXLqkvU1.js → _server.ts-L40fgGK2.js} +5 -5
  178. package/build/server/chunks/{_server.ts-DXLqkvU1.js.map → _server.ts-L40fgGK2.js.map} +1 -1
  179. package/build/server/chunks/{_server.ts-C4qYb4T-.js → _server.ts-LH7_dhbT.js} +2 -2
  180. package/build/server/chunks/{_server.ts-C4qYb4T-.js.map → _server.ts-LH7_dhbT.js.map} +1 -1
  181. package/build/server/chunks/{_server.ts-Ur_t9bMU.js → _server.ts-Oeuvw5C1.js} +4 -4
  182. package/build/server/chunks/{_server.ts-Ur_t9bMU.js.map → _server.ts-Oeuvw5C1.js.map} +1 -1
  183. package/build/server/chunks/{_server.ts-BOcqQDtZ.js → _server.ts-X4eLzYa3.js} +4 -4
  184. package/build/server/chunks/{_server.ts-BOcqQDtZ.js.map → _server.ts-X4eLzYa3.js.map} +1 -1
  185. package/build/server/chunks/{_server.ts-7SYeoL8H.js → _server.ts-XYviVWKw.js} +4 -4
  186. package/build/server/chunks/{_server.ts-7SYeoL8H.js.map → _server.ts-XYviVWKw.js.map} +1 -1
  187. package/build/server/chunks/{_server.ts-BIRnkRp-.js → _server.ts-grXc3lpo.js} +4 -4
  188. package/build/server/chunks/{_server.ts-BIRnkRp-.js.map → _server.ts-grXc3lpo.js.map} +1 -1
  189. package/build/server/chunks/{_server.ts-Bz5eysrP.js → _server.ts-hNck8JSQ.js} +5 -5
  190. package/build/server/chunks/{_server.ts-Bz5eysrP.js.map → _server.ts-hNck8JSQ.js.map} +1 -1
  191. package/build/server/chunks/{_server.ts-Dwklttlo.js → _server.ts-l6P5GPNF.js} +2 -2
  192. package/build/server/chunks/{_server.ts-Dwklttlo.js.map → _server.ts-l6P5GPNF.js.map} +1 -1
  193. package/build/server/chunks/{_server.ts-DDJ_6hbd.js → _server.ts-oPUaAhwQ.js} +4 -4
  194. package/build/server/chunks/{_server.ts-DDJ_6hbd.js.map → _server.ts-oPUaAhwQ.js.map} +1 -1
  195. package/build/server/chunks/{_server.ts-CaHJSZZ1.js → _server.ts-tHI7RAXv.js} +4 -4
  196. package/build/server/chunks/{_server.ts-CaHJSZZ1.js.map → _server.ts-tHI7RAXv.js.map} +1 -1
  197. package/build/server/chunks/{_server.ts-DVdN-5bk.js → _server.ts-u7HOQxSc.js} +4 -4
  198. package/build/server/chunks/{_server.ts-DVdN-5bk.js.map → _server.ts-u7HOQxSc.js.map} +1 -1
  199. package/build/server/chunks/{_server.ts-DAti5TMB.js → _server.ts-vLpDptQT.js} +4 -4
  200. package/build/server/chunks/{_server.ts-DAti5TMB.js.map → _server.ts-vLpDptQT.js.map} +1 -1
  201. package/build/server/chunks/{addon-helpers-DM77guzq.js → addon-helpers-CbNmFpKY.js} +2 -2
  202. package/build/server/chunks/{addon-helpers-DM77guzq.js.map → addon-helpers-CbNmFpKY.js.map} +1 -1
  203. package/build/server/chunks/{config-BE8RNUzZ.js → config-CWdj6ZuI.js} +2 -2
  204. package/build/server/chunks/{config-BE8RNUzZ.js.map → config-CWdj6ZuI.js.map} +1 -1
  205. package/build/server/chunks/{docker-BFje1OYT.js → docker-CjX7RsXx.js} +2 -2
  206. package/build/server/chunks/{docker-BFje1OYT.js.map → docker-CjX7RsXx.js.map} +1 -1
  207. package/build/server/chunks/{endpoints-Dz6qhKXB.js → endpoints-eF0TVirP.js} +3 -3
  208. package/build/server/chunks/{endpoints-Dz6qhKXB.js.map → endpoints-eF0TVirP.js.map} +1 -1
  209. package/build/server/chunks/{error.svelte-8jbbCpmR.js → error.svelte-BCEnO98F.js} +3 -3
  210. package/build/server/chunks/{error.svelte-8jbbCpmR.js.map → error.svelte-BCEnO98F.js.map} +1 -1
  211. package/build/server/chunks/{helpers-C1fMEpiP.js → helpers-BlYXYNks.js} +3 -3
  212. package/build/server/chunks/{helpers-C1fMEpiP.js.map → helpers-BlYXYNks.js.map} +1 -1
  213. package/build/server/chunks/{hooks.server-C6uX-Qkd.js → hooks.server-MxqwJ1Ug.js} +4 -4
  214. package/build/server/chunks/{hooks.server-C6uX-Qkd.js.map → hooks.server-MxqwJ1Ug.js.map} +1 -1
  215. package/build/server/chunks/{http-CmL_uneS.js → http-CbN2XzaU.js} +2 -2
  216. package/build/server/chunks/{http-CmL_uneS.js.map → http-CbN2XzaU.js.map} +1 -1
  217. package/build/server/chunks/{internal-BJjTqjxK.js → internal-r__KO0cl.js} +3 -3
  218. package/build/server/chunks/{internal-BJjTqjxK.js.map → internal-r__KO0cl.js.map} +1 -1
  219. package/build/server/chunks/{setup-deploy-tjcmiBUv.js → setup-deploy-DTpn9m1O.js} +2 -2
  220. package/build/server/chunks/{setup-deploy-tjcmiBUv.js.map → setup-deploy-DTpn9m1O.js.map} +1 -1
  221. package/build/server/chunks/{src-BWQ05CjI.js → src-BuTsJttD.js} +8 -3
  222. package/build/server/chunks/src-BuTsJttD.js.map +1 -0
  223. package/build/server/chunks/{state-CKV51p4g.js → state-BMvo7e8L.js} +2 -2
  224. package/build/server/chunks/{state-CKV51p4g.js.map → state-BMvo7e8L.js.map} +1 -1
  225. package/build/server/index.js +1 -1
  226. package/build/server/index.js.map +1 -1
  227. package/build/server/manifest.js +77 -77
  228. package/build/server/manifest.js.map +1 -1
  229. package/package.json +2 -2
  230. package/build/client/_app/immutable/chunks/CmvkId2p.js.br +0 -0
  231. package/build/client/_app/immutable/chunks/CmvkId2p.js.gz +0 -0
  232. package/build/client/_app/immutable/chunks/DKrt-Ofe.js.br +0 -0
  233. package/build/client/_app/immutable/chunks/DKrt-Ofe.js.gz +0 -0
  234. package/build/client/_app/immutable/chunks/DTwNbG18.js.br +0 -2
  235. package/build/client/_app/immutable/chunks/DTwNbG18.js.gz +0 -0
  236. package/build/client/_app/immutable/entry/app.D2QrHH7_.js.br +0 -0
  237. package/build/client/_app/immutable/entry/app.D2QrHH7_.js.gz +0 -0
  238. package/build/client/_app/immutable/entry/start.BM5p1xOI.js +0 -1
  239. package/build/client/_app/immutable/entry/start.BM5p1xOI.js.br +0 -0
  240. package/build/client/_app/immutable/entry/start.BM5p1xOI.js.gz +0 -0
  241. package/build/client/_app/immutable/nodes/1.vc1gswpN.js.br +0 -0
  242. package/build/client/_app/immutable/nodes/1.vc1gswpN.js.gz +0 -0
  243. package/build/client/_app/immutable/nodes/4.DD0APCkW.js.br +0 -0
  244. package/build/client/_app/immutable/nodes/5.BIkQUR1G.js.br +0 -0
  245. package/build/client/_app/immutable/nodes/5.BIkQUR1G.js.gz +0 -0
  246. package/build/client/_app/immutable/nodes/6.DVDakR8k.js.br +0 -0
  247. package/build/client/_app/immutable/nodes/6.DVDakR8k.js.gz +0 -0
  248. package/build/client/_app/immutable/nodes/7.wMxDFXAt.js.br +0 -0
  249. package/build/client/_app/immutable/nodes/7.wMxDFXAt.js.gz +0 -0
  250. package/build/client/_app/immutable/nodes/8.Cb4MWMah.js.br +0 -0
  251. package/build/server/chunks/1-BwC-cEPZ.js +0 -9
  252. package/build/server/chunks/src-BWQ05CjI.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"_page.svelte-D0gMlmzQ.js","sources":["../../../.svelte-kit/adapter-node/chunks/VoiceProfileSelector.js","../../../.svelte-kit/adapter-node/entries/pages/setup/_page.svelte.js"],"sourcesContent":["import { B as attr, V as escape_html, a as ensure_array_like, i as derived, l as stringify, n as attr_class } from \"./dev.js\";\n//#region src/lib/wizard/constants.ts\nvar PROVIDER_GROUPS = [\n\t{\n\t\tid: \"recommended\",\n\t\tlabel: \"Recommended\",\n\t\tdesc: \"Best options to get started quickly\"\n\t},\n\t{\n\t\tid: \"local\",\n\t\tlabel: \"Local\",\n\t\tdesc: \"Run models on your own hardware\"\n\t},\n\t{\n\t\tid: \"cloud\",\n\t\tlabel: \"Cloud\",\n\t\tdesc: \"Hosted inference providers\"\n\t},\n\t{\n\t\tid: \"advanced\",\n\t\tlabel: \"Advanced\",\n\t\tdesc: \"Additional providers\"\n\t}\n];\nvar PROVIDERS = [\n\t{\n\t\tid: \"ollama\",\n\t\tname: \"Ollama\",\n\t\tkind: \"local\",\n\t\tgroup: \"recommended\",\n\t\torder: 1,\n\t\ticon: \"🦙\",\n\t\tdesc: \"Run open models on your hardware\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:11434\",\n\t\tllmModel: \"llama3.2\",\n\t\tembModel: \"nomic-embed-text\",\n\t\tembDims: 768,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"huggingface\",\n\t\tname: \"Hugging Face\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 2,\n\t\ticon: \"🤗\",\n\t\tdesc: \"10,000+ open models via Inference Providers\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"hf_...\",\n\t\tbaseUrl: \"https://router.huggingface.co/v1\",\n\t\tllmModel: \"Qwen/Qwen3-32B\",\n\t\tembModel: \"intfloat/multilingual-e5-large\",\n\t\tembDims: 1024,\n\t\tkeyPrefix: \"hf_\"\n\t},\n\t{\n\t\tid: \"openai\",\n\t\tname: \"OpenAI\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 3,\n\t\ticon: \"◐\",\n\t\tdesc: \"GPT and o-series reasoning models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"sk-...\",\n\t\tbaseUrl: \"https://api.openai.com\",\n\t\tllmModel: \"gpt-4o\",\n\t\tembModel: \"text-embedding-3-small\",\n\t\tembDims: 1536\n\t},\n\t{\n\t\tid: \"google\",\n\t\tname: \"Google\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 4,\n\t\ticon: \"◆\",\n\t\tdesc: \"Gemini models with large context\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"AIza...\",\n\t\tbaseUrl: \"https://generativelanguage.googleapis.com\",\n\t\tllmModel: \"gemini-2.5-flash\",\n\t\tembModel: \"\",\n\t\tembDims: 0,\n\t\tkeyPrefix: \"AI\"\n\t},\n\t{\n\t\tid: \"model-runner\",\n\t\tname: \"Docker Model Runner\",\n\t\tkind: \"local\",\n\t\tgroup: \"local\",\n\t\torder: 1,\n\t\ticon: \"🐳\",\n\t\tdesc: \"Docker-managed model runtime\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:12434\",\n\t\tllmModel: \"ai/llama3.2\",\n\t\tembModel: \"ai/mxbai-embed-large-v1\",\n\t\tembDims: 1024,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"lmstudio\",\n\t\tname: \"LM Studio\",\n\t\tkind: \"local\",\n\t\tgroup: \"local\",\n\t\torder: 2,\n\t\ticon: \"🔬\",\n\t\tdesc: \"Desktop app for local inference\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:1234\",\n\t\tllmModel: \"loaded-model\",\n\t\tembModel: \"\",\n\t\tembDims: 0,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"groq\",\n\t\tname: \"Groq\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 1,\n\t\ticon: \"⚡\",\n\t\tdesc: \"Ultra-fast inference\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"gsk_...\",\n\t\tbaseUrl: \"https://api.groq.com/openai\",\n\t\tllmModel: \"llama-3.3-70b-versatile\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"mistral\",\n\t\tname: \"Mistral\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 2,\n\t\ticon: \"◆\",\n\t\tdesc: \"Mistral & Codestral models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"...\",\n\t\tbaseUrl: \"https://api.mistral.ai\",\n\t\tllmModel: \"mistral-large-latest\",\n\t\tembModel: \"mistral-embed\",\n\t\tembDims: 1024\n\t},\n\t{\n\t\tid: \"together\",\n\t\tname: \"Together AI\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 3,\n\t\ticon: \"✦\",\n\t\tdesc: \"Open models at scale\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"...\",\n\t\tbaseUrl: \"https://api.together.xyz\",\n\t\tllmModel: \"meta-llama/Llama-3.3-70B-Instruct-Turbo\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"deepseek\",\n\t\tname: \"DeepSeek\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 1,\n\t\ticon: \"◎\",\n\t\tdesc: \"DeepSeek chat & reasoning\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"sk-...\",\n\t\tbaseUrl: \"https://api.deepseek.com\",\n\t\tllmModel: \"deepseek-chat\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"xai\",\n\t\tname: \"xAI (Grok)\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 2,\n\t\ticon: \"✦\",\n\t\tdesc: \"Grok models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"xai-...\",\n\t\tbaseUrl: \"https://api.x.ai\",\n\t\tllmModel: \"grok-2\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"openai-compatible\",\n\t\tname: \"Custom API server\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 3,\n\t\ticon: \"🔧\",\n\t\tdesc: \"Connect any AI server that uses the standard OpenAI API format.\",\n\t\tneedsKey: false,\n\t\tneedsUrl: true,\n\t\toptionalKey: true,\n\t\tplaceholder: \"API key (optional)\",\n\t\tbaseUrl: \"\",\n\t\tllmModel: \"\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t}\n];\nvar KNOWN_EMB_DIMS = {\n\t\"text-embedding-3-small\": 1536,\n\t\"text-embedding-3-large\": 3072,\n\t\"text-embedding-ada-002\": 1536,\n\t\"nomic-embed-text\": 768,\n\t\"mxbai-embed-large\": 1024,\n\t\"mxbai-embed-large-v1\": 1024,\n\t\"ai/mxbai-embed-large-v1\": 1024,\n\t\"mistral-embed\": 1024,\n\t\"all-minilm\": 384,\n\t\"snowflake-arctic-embed\": 1024,\n\t\"intfloat/multilingual-e5-large\": 1024\n};\nvar STEP_LABELS = [\n\t\"System Check\",\n\t\"Get Started\",\n\t\"Providers\",\n\t\"Models\",\n\t\"Voice\",\n\t\"Options\",\n\t\"Review\"\n];\nvar TTS_OPTIONS = [\n\t{\n\t\tid: \"openpalm-voice\",\n\t\tname: \"OpenPalm Voice\",\n\t\ttype: \"local\",\n\t\trecommended: true,\n\t\tdesc: \"Bundled Kokoro TTS + Whisper STT — runs locally, no cloud. First install downloads ~2.4 GB.\"\n\t},\n\t{\n\t\tid: \"openai-tts\",\n\t\tname: \"OpenAI TTS\",\n\t\ttype: \"cloud\",\n\t\tdesc: \"Cloud voices. Uses your OpenAI API key\"\n\t},\n\t{\n\t\tid: \"browser-tts\",\n\t\tname: \"Browser Built-in\",\n\t\ttype: \"builtin\",\n\t\tdesc: \"Native speech synthesis. No setup needed\"\n\t},\n\t{\n\t\tid: \"skip-tts\",\n\t\tname: \"Skip — text only\",\n\t\ttype: \"skip\",\n\t\tdesc: \"Add TTS later from the dashboard\"\n\t}\n];\nvar STT_OPTIONS = [\n\t{\n\t\tid: \"openpalm-voice\",\n\t\tname: \"OpenPalm Voice\",\n\t\ttype: \"local\",\n\t\trecommended: true,\n\t\tdesc: \"Bundled Kokoro TTS + Whisper STT — runs locally, no cloud. First install downloads ~2.4 GB.\"\n\t},\n\t{\n\t\tid: \"openai-stt\",\n\t\tname: \"OpenAI Whisper\",\n\t\ttype: \"cloud\",\n\t\tdesc: \"Cloud Whisper API. Uses OpenAI key\"\n\t},\n\t{\n\t\tid: \"browser-stt\",\n\t\tname: \"Browser Built-in\",\n\t\ttype: \"builtin\",\n\t\tdesc: \"Web Speech API. No setup\"\n\t},\n\t{\n\t\tid: \"skip-stt\",\n\t\tname: \"Skip — text only\",\n\t\ttype: \"skip\",\n\t\tdesc: \"Add STT later from the dashboard\"\n\t}\n];\n/**\n* Per-engine configuration fields. Empty `fields` means \"no extra settings\".\n* `provider` is written to stack.env as OP_TTS_PROVIDER / OP_STT_PROVIDER\n* so the voice channel can resolve the runtime URL.\n*\n* Shared between the setup wizard's VoiceStep and the admin Capabilities tab.\n*/\nvar BASE_URL_FIELD = (placeholder, hint) => ({\n\tkey: \"baseURL\",\n\tlabel: \"Endpoint URL\",\n\tplaceholder,\n\thint\n});\nvar TTS_ENGINES = {\n\t\"openpalm-voice\": {\n\t\tid: \"openpalm-voice\",\n\t\tprovider: \"openpalm-voice\",\n\t\tfields: []\n\t},\n\t\"openai-tts\": {\n\t\tid: \"openai-tts\",\n\t\tprovider: \"openai\",\n\t\tfields: [\n\t\t\tBASE_URL_FIELD(\"https://api.openai.com/v1\", \"Leave empty to use the default OpenAI endpoint. Override for proxies / Azure-compat.\"),\n\t\t\t{\n\t\t\t\tkey: \"model\",\n\t\t\t\tlabel: \"Model\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"tts-1\",\n\t\t\t\t\t\"tts-1-hd\",\n\t\t\t\t\t\"gpt-4o-mini-tts\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"voice\",\n\t\t\t\tlabel: \"Voice\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"alloy\",\n\t\t\t\t\t\"echo\",\n\t\t\t\t\t\"fable\",\n\t\t\t\t\t\"onyx\",\n\t\t\t\t\t\"nova\",\n\t\t\t\t\t\"shimmer\"\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t},\n\t\"browser-tts\": {\n\t\tid: \"browser-tts\",\n\t\tfields: []\n\t},\n\t\"skip-tts\": {\n\t\tid: \"skip-tts\",\n\t\tfields: []\n\t}\n};\nvar STT_ENGINES = {\n\t\"openpalm-voice\": {\n\t\tid: \"openpalm-voice\",\n\t\tprovider: \"openpalm-voice\",\n\t\tfields: []\n\t},\n\t\"openai-stt\": {\n\t\tid: \"openai-stt\",\n\t\tprovider: \"openai\",\n\t\tfields: [\n\t\t\tBASE_URL_FIELD(\"https://api.openai.com/v1\", \"Leave empty to use the default OpenAI endpoint.\"),\n\t\t\t{\n\t\t\t\tkey: \"model\",\n\t\t\t\tlabel: \"Model\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"whisper-1\",\n\t\t\t\t\t\"gpt-4o-mini-transcribe\",\n\t\t\t\t\t\"gpt-4o-transcribe\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"language\",\n\t\t\t\tlabel: \"Language\",\n\t\t\t\tplaceholder: \"en\",\n\t\t\t\thint: \"A language code like `en` or `fr`, or leave blank to detect automatically.\"\n\t\t\t}\n\t\t]\n\t},\n\t\"browser-stt\": {\n\t\tid: \"browser-stt\",\n\t\tfields: [{\n\t\t\tkey: \"language\",\n\t\t\tlabel: \"Language\",\n\t\t\tplaceholder: \"en-US\",\n\t\t\thint: \"A language code like `en` or `fr`, or leave blank to detect automatically.\"\n\t\t}]\n\t},\n\t\"skip-stt\": {\n\t\tid: \"skip-stt\",\n\t\tfields: []\n\t}\n};\nvar CHANNELS = [\n\t{\n\t\tid: \"api\",\n\t\tname: \"API\",\n\t\ticon: \"🔌\",\n\t\tdesc: \"OpenAI-compatible REST API endpoint\"\n\t},\n\t{\n\t\tid: \"discord\",\n\t\tname: \"Discord\",\n\t\ticon: \"🎮\",\n\t\tdesc: \"Connect to a Discord server\",\n\t\tcredentials: [{\n\t\t\tkey: \"botToken\",\n\t\t\tlabel: \"Bot Token\",\n\t\t\tplaceholder: \"Paste Discord bot token\",\n\t\t\trequired: true\n\t\t}, {\n\t\t\tkey: \"applicationId\",\n\t\t\tlabel: \"Application ID\",\n\t\t\tplaceholder: \"Discord application ID\",\n\t\t\tsecret: false\n\t\t}]\n\t},\n\t{\n\t\tid: \"slack\",\n\t\tname: \"Slack\",\n\t\ticon: \"💼\",\n\t\tdesc: \"Access via Slack bot\",\n\t\tcredentials: [{\n\t\t\tkey: \"slackBotToken\",\n\t\t\tlabel: \"Bot Token\",\n\t\t\tplaceholder: \"xoxb-...\",\n\t\t\trequired: true\n\t\t}, {\n\t\t\tkey: \"slackAppToken\",\n\t\t\tlabel: \"App Token\",\n\t\t\tplaceholder: \"xapp-...\",\n\t\t\trequired: true\n\t\t}]\n\t}\n];\nvar LOCAL_PROVIDERS = [\n\t{\n\t\tid: \"ollama\",\n\t\tname: \"Ollama\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:11434\"\n\t},\n\t{\n\t\tid: \"model-runner\",\n\t\tname: \"Docker Model Runner\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:12434\"\n\t},\n\t{\n\t\tid: \"lmstudio\",\n\t\tname: \"LM Studio\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:1234\"\n\t},\n\t{\n\t\tid: \"openai-compatible\",\n\t\tname: \"Custom API server\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"\"\n\t}\n];\n//#endregion\n//#region src/lib/components/voice/VoiceEngineSelector.svelte\nfunction VoiceEngineSelector($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { kind, value, onchange, reachable, reachabilityEngineId, disabledEngines, hiddenEngines, engineOptions, engineConfigs } = $$props;\n\t\tconst allOptions = derived(() => engineOptions ?? (kind === \"tts\" ? TTS_OPTIONS : STT_OPTIONS));\n\t\tconst engines = derived(() => engineConfigs ?? (kind === \"tts\" ? TTS_ENGINES : STT_ENGINES));\n\t\tconst options = derived(() => hiddenEngines ? allOptions().filter((o) => !hiddenEngines.has(o.id)) : allOptions());\n\t\tfunction updateField(key, val) {\n\t\t\tconst next = { ...value };\n\t\t\tif (val) next[key] = val;\n\t\t\telse delete next[key];\n\t\t\tonchange(next);\n\t\t}\n\t\t$$renderer.push(`<div class=\"engine-list svelte-1e5u5jo\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(options());\n\t\tfor (let $$index_2 = 0, $$length = each_array.length; $$index_2 < $$length; $$index_2++) {\n\t\t\tlet o = each_array[$$index_2];\n\t\t\tconst selected = value.engine === o.id;\n\t\t\tconst config = engines()[o.id];\n\t\t\tconst engineState = disabledEngines?.[o.id];\n\t\t\tconst isDisabled = engineState?.disabled ?? false;\n\t\t\t$$renderer.push(`<button type=\"button\"${attr_class(\"engine-card svelte-1e5u5jo\", void 0, {\n\t\t\t\t\"engine-card--selected\": selected,\n\t\t\t\t\"engine-card--disabled\": isDisabled\n\t\t\t})}${attr(\"disabled\", isDisabled, true)}><div class=\"engine-body svelte-1e5u5jo\"><span class=\"engine-name svelte-1e5u5jo\">${escape_html(o.name)}</span> <span class=\"engine-desc svelte-1e5u5jo\">${escape_html(o.desc)}</span> `);\n\t\t\tif (isDisabled && engineState?.reason) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"engine-subtitle svelte-1e5u5jo\">${escape_html(engineState.reason)}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (o.id === (reachabilityEngineId ?? (kind === \"tts\" ? \"openai-tts\" : \"openai-stt\")) && reachable?.remoteConfigured) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span${attr_class(\"engine-reachability svelte-1e5u5jo\", void 0, { \"engine-reachability--ok\": reachable.remoteReachable })}>${escape_html(reachable.remoteReachable ? \"● Endpoint reachable\" : \"○ Endpoint not reachable\")}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div> `);\n\t\t\tif (o.recommended) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"badge badge-recommended\">Recommended</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></button> `);\n\t\t\tif (selected && config && config.fields.length > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"engine-config svelte-1e5u5jo\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(config.fields);\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet field = each_array_1[$$index_1];\n\t\t\t\t\t$$renderer.push(`<div class=\"form-field\"><label class=\"form-label\"${attr(\"for\", `voice-${stringify(kind)}-${stringify(field.key)}`)}>${escape_html(field.label)}</label> `);\n\t\t\t\t\tif (field.options) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.select({\n\t\t\t\t\t\t\tid: `voice-${stringify(kind)}-${stringify(field.key)}`,\n\t\t\t\t\t\t\tclass: \"form-input\",\n\t\t\t\t\t\t\tvalue: value[field.key] ?? \"\",\n\t\t\t\t\t\t\tonchange: (e) => updateField(field.key, e.currentTarget.value)\n\t\t\t\t\t\t}, ($$renderer) => {\n\t\t\t\t\t\t\t$$renderer.option({ value: \"\" }, ($$renderer) => {\n\t\t\t\t\t\t\t\t$$renderer.push(`— default —`);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\t\t\tconst each_array_2 = ensure_array_like(field.options);\n\t\t\t\t\t\t\tfor (let $$index = 0, $$length = each_array_2.length; $$index < $$length; $$index++) {\n\t\t\t\t\t\t\t\tlet opt = each_array_2[$$index];\n\t\t\t\t\t\t\t\t$$renderer.option({ value: opt }, ($$renderer) => {\n\t\t\t\t\t\t\t\t\t$$renderer.push(`${escape_html(opt)}`);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<input${attr(\"id\", `voice-${stringify(kind)}-${stringify(field.key)}`)}${attr(\"type\", field.key === \"baseURL\" ? \"url\" : \"text\")} class=\"form-input\"${attr(\"value\", value[field.key] ?? \"\")}${attr(\"placeholder\", field.placeholder ?? \"\")} autocomplete=\"off\"${attr(\"spellcheck\", field.key === \"baseURL\" ? false : void 0)}/>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\tif (field.hint) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"field-hint svelte-1e5u5jo\">${escape_html(field.hint)}</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div>`);\n\t});\n}\n//#endregion\n//#region src/lib/components/voice/VoiceProfileSelector.svelte\nfunction VoiceProfileSelector($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { profiles, selectedProfile, onchange, showDescription } = $$props;\n\t\tconst selectedInfo = derived(() => profiles.find((p) => p.id === selectedProfile) ?? profiles[0]);\n\t\tshowDescription ??= true;\n\t\tif (profiles.length === 0) $$renderer.push(\"<!--[0-->\");\n\t\telse if (profiles.length === 1) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`<p class=\"profile-single svelte-11ub9pr\">Using ${escape_html(selectedInfo()?.label ?? selectedInfo()?.id ?? \"selected\")}.</p>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\tif (showDescription) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"profile-desc svelte-11ub9pr\">Select the profile that matches your hardware. GPU profiles are auto-selected when available.</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> <div class=\"form-field\"><label class=\"form-label\" for=\"voice-profile\">Profile</label> `);\n\t\t\t$$renderer.select({\n\t\t\t\tid: \"voice-profile\",\n\t\t\t\tclass: \"form-input\",\n\t\t\t\tvalue: selectedProfile,\n\t\t\t\tonchange: (e) => onchange(e.currentTarget.value)\n\t\t\t}, ($$renderer) => {\n\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(profiles);\n\t\t\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet profile = each_array[$$index];\n\t\t\t\t\t$$renderer.option({\n\t\t\t\t\t\tvalue: profile.id,\n\t\t\t\t\t\tdisabled: profile.available === false,\n\t\t\t\t\t\ttitle: profile.available === false ? profile.reason ?? \"Not available on this host\" : void 0\n\t\t\t\t\t}, ($$renderer) => {\n\t\t\t\t\t\t$$renderer.push(`${escape_html(profile.label ?? profile.id)}${escape_html(profile.available === false ? \" — unavailable\" : \"\")}`);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t});\n\t\t\t$$renderer.push(` `);\n\t\t\tif (selectedInfo()?.requires) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"field-hint svelte-11ub9pr\">Requires: ${escape_html(selectedInfo().requires)}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (selectedInfo()?.available === false) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"field-hint field-hint--warning svelte-11ub9pr\">${escape_html(selectedInfo().reason ?? \"This profile is not available on the current host.\")}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\nexport { LOCAL_PROVIDERS as a, STEP_LABELS as c, KNOWN_EMB_DIMS as i, STT_OPTIONS as l, VoiceEngineSelector as n, PROVIDERS as o, CHANNELS as r, PROVIDER_GROUPS as s, VoiceProfileSelector as t, TTS_OPTIONS as u };\n","import { B as attr, V as escape_html, a as ensure_array_like, i as derived, l as stringify, n as attr_class, o as head, r as attr_style } from \"../../../chunks/dev.js\";\nimport \"../../../chunks/index-server.js\";\nimport { c as STEP_LABELS, i as KNOWN_EMB_DIMS, l as STT_OPTIONS, n as VoiceEngineSelector, o as PROVIDERS, r as CHANNELS, s as PROVIDER_GROUPS, t as VoiceProfileSelector, u as TTS_OPTIONS } from \"../../../chunks/VoiceProfileSelector.js\";\n//#region src/lib/wizard/error-messages.ts\nvar DOCKER_LINK = {\n\tlabel: \"Docker setup\",\n\thref: \"https://docs.docker.com/get-docker/\"\n};\nfunction rawText(raw) {\n\tif (!raw) return \"\";\n\tif (raw instanceof Error) return raw.message;\n\tif (typeof raw === \"string\") return raw;\n\ttry {\n\t\treturn JSON.stringify(raw);\n\t} catch {\n\t\treturn String(raw);\n\t}\n}\nfunction friendlyError(raw, context = \"generic\", opts = {}) {\n\tconst text = rawText(raw);\n\tconst lower = text.toLowerCase();\n\tconst providerLabel = opts.providerName ? `${opts.providerName} didn't accept that key` : \"API key rejected\";\n\tif (/\\b(401|403|unauthorized|forbidden|invalid.?api.?key)\\b/i.test(text)) return {\n\t\ttitle: providerLabel,\n\t\tbody: \"The provider rejected the API key.\",\n\t\thint: \"Common causes: extra spaces, wrong account, or the key was revoked. Double-check the key and that it has access to the model you selected. Most providers show the key in their dashboard.\",\n\t\traw: text\n\t};\n\tif (/\\b(ENOTFOUND|ECONNREFUSED|getaddrinfo|EAI_AGAIN|EHOSTUNREACH)\\b/i.test(text)) return {\n\t\ttitle: \"Couldn't reach the host\",\n\t\tbody: text,\n\t\thint: \"Confirm the URL is correct and the service is online. For local providers (Ollama, LM Studio) make sure the server is running on this machine.\",\n\t\traw: text\n\t};\n\tif (/(timeout|timed out|AbortError|ETIMEDOUT)/i.test(text)) return {\n\t\ttitle: \"Request timed out\",\n\t\tbody: \"The provider didn't respond in time.\",\n\t\thint: \"It may be slow or temporarily down. Try again in a moment.\",\n\t\traw: text\n\t};\n\tif (lower.includes(\"docker\") || lower.includes(\"compose\") || lower.includes(\"daemon\")) return {\n\t\ttitle: \"Docker isn't available\",\n\t\tbody: \"OpenPalm needs Docker (with Compose v2) installed and running.\",\n\t\thint: \"Start Docker Desktop (macOS/Windows) or the docker daemon (Linux), then retry.\",\n\t\tlinks: [DOCKER_LINK],\n\t\traw: text\n\t};\n\tif (/EADDRINUSE/i.test(text) || /port.*in.?use/i.test(lower)) return {\n\t\ttitle: \"A required port is already in use\",\n\t\tbody: text,\n\t\thint: \"Another program is using one of OpenPalm's default ports. Quit the conflicting app, or change OpenPalm's port from the Admin Dashboard after setup.\",\n\t\traw: text\n\t};\n\tif (/EACCES|EPERM|permission denied/i.test(text)) return {\n\t\ttitle: \"Permission denied\",\n\t\tbody: text,\n\t\thint: \"OpenPalm couldn't write to its data directory. Check that ~/.openpalm/ is writable by your user.\",\n\t\traw: text\n\t};\n\tswitch (context) {\n\t\tcase \"provider-verify\":\n\t\tcase \"model-fetch\": return {\n\t\t\ttitle: \"Couldn't connect to the provider\",\n\t\t\tbody: text || \"Verification failed.\",\n\t\t\thint: \"Check the API key and base URL, then click Verify again.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"setup-complete\": return {\n\t\t\ttitle: \"Setup couldn't finish\",\n\t\t\tbody: text || \"Writing configuration failed.\",\n\t\t\thint: \"Check the technical details below, then retry. If the issue persists, the admin dashboard logs may help.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"deploy\":\n\t\tcase \"deploy-poll\": return {\n\t\t\ttitle: \"Deployment ran into a problem\",\n\t\t\tbody: text || \"One or more services failed to start.\",\n\t\t\thint: \"Image pulls can take several minutes on first install. Retry to attempt again; check Docker logs if it keeps failing.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"system-check\": return {\n\t\t\ttitle: \"System check failed\",\n\t\t\tbody: text || \"A required dependency is missing.\",\n\t\t\thint: \"Resolve the failing check above, then click Retry.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"channel\": return {\n\t\t\ttitle: \"Channel credential issue\",\n\t\t\tbody: text || \"A required field is missing or invalid.\",\n\t\t\thint: \"Confirm the bot token and other required fields are correct.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"port-conflict\": return {\n\t\t\ttitle: \"A required port is already in use\",\n\t\t\tbody: text || \"Another process is using one of OpenPalm's ports.\",\n\t\t\thint: \"Another program is using one of OpenPalm's default ports. Quit the conflicting app, or change OpenPalm's port from the Admin Dashboard after setup.\",\n\t\t\traw: text\n\t\t};\n\t\tdefault: return {\n\t\t\ttitle: \"Something went wrong\",\n\t\t\tbody: text || \"An unexpected error occurred.\",\n\t\t\thint: \"Try again. If the problem persists, check the admin dashboard logs.\",\n\t\t\traw: text\n\t\t};\n\t}\n}\n//#endregion\n//#region src/routes/setup/ProgressBar.svelte\nfunction ProgressBar($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { currentStep, maxVisitedStep, onnavigate, canNavigateTo } = $$props;\n\t\t$$renderer.push(`<nav class=\"prog-bar\" aria-label=\"Wizard steps\"><div class=\"prog-segments\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(STEP_LABELS);\n\t\tfor (let i = 0, $$length = each_array.length; i < $$length; i++) {\n\t\t\teach_array[i];\n\t\t\t$$renderer.push(`<div${attr_class(`prog-seg ${i <= currentStep ? \"on\" : \"\"}`)}></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"prog-labels\"><!--[-->`);\n\t\tconst each_array_1 = ensure_array_like(STEP_LABELS);\n\t\tfor (let i = 0, $$length = each_array_1.length; i < $$length; i++) {\n\t\t\tlet label = each_array_1[i];\n\t\t\t$$renderer.push(`<span${attr_class(`prog-lbl ${i <= currentStep ? \"on\" : \"\"} ${i === currentStep ? \"active\" : \"\"}`)} role=\"button\"${attr(\"tabindex\", i <= maxVisitedStep && canNavigateTo(i) ? 0 : -1)}${attr(\"aria-label\", `Go to step ${stringify(label)}`)}>${escape_html(label)}</span>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></nav>`);\n\t});\n}\n//#endregion\n//#region src/lib/components/FriendlyError.svelte\nfunction FriendlyError($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\t/** Render compactly without the technical-details disclosure (inline forms). */\n\t\tlet { error, role = \"alert\", compact = false } = $$props;\n\t\tif (error) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"friendly-error svelte-l9z7ob\"${attr(\"role\", role)}><div class=\"friendly-error-header svelte-l9z7ob\"><svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line></svg> <strong class=\"friendly-error-title svelte-l9z7ob\">${escape_html(error.title)}</strong></div> `);\n\t\t\tif (error.body) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"friendly-error-body svelte-l9z7ob\">${escape_html(error.body)}</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (error.hint) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"friendly-error-hint svelte-l9z7ob\">${escape_html(error.hint)}</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (error.links && error.links.length > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"friendly-error-links svelte-l9z7ob\"><!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(error.links);\n\t\t\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet link = each_array[$$index];\n\t\t\t\t\t$$renderer.push(`<a${attr(\"href\", link.href)} target=\"_blank\" rel=\"noopener noreferrer\" class=\"friendly-error-link svelte-l9z7ob\">${escape_html(link.label)} →</a>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (!compact && error.raw && error.raw !== error.body) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<details class=\"friendly-error-details svelte-l9z7ob\"><summary class=\"svelte-l9z7ob\">Technical details</summary> <pre class=\"svelte-l9z7ob\">${escape_html(error.raw)}</pre></details>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/SystemCheckStep.svelte\nfunction SystemCheckStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\t/** True when re-running an existing install; suppresses misleading\n\t\t* port-conflict warnings that just reflect the running stack itself. */\n\t\tlet { onnext, onpass, ongpudetected, isRerun = false } = $$props;\n\t\tlet loading = true;\n\t\tlet result = null;\n\t\tconst portConflicts = derived(() => isRerun ? [] : []);\n\t\tconst blockingPortConflicts = derived(() => portConflicts().filter((p) => p.blocking));\n\t\tderived(() => blockingPortConflicts().length > 0);\n\t\tderived(() => false);\n\t\t$$renderer.push(`<h2>System Check</h2> <p class=\"step-description\">Let's make sure your machine has everything OpenPalm needs.</p> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"syscheck-list svelte-1txhq2p\" aria-live=\"polite\"><div${attr_class(\"syscheck-row svelte-1txhq2p\", void 0, {\n\t\t\t\"syscheck-row--ok\": void 0,\n\t\t\t\"syscheck-row--fail\": result\n\t\t})}><div class=\"syscheck-icon svelte-1txhq2p\">`);\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1txhq2p\"></span>`);\n\t\t$$renderer.push(`<!--]--></div> <div class=\"syscheck-body svelte-1txhq2p\"><div class=\"syscheck-title svelte-1txhq2p\">Docker is installed and running</div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div> <div${attr_class(\"syscheck-row svelte-1txhq2p\", void 0, {\n\t\t\t\"syscheck-row--ok\": void 0,\n\t\t\t\"syscheck-row--fail\": result\n\t\t})}><div class=\"syscheck-icon svelte-1txhq2p\">`);\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1txhq2p\"></span>`);\n\t\t$$renderer.push(`<!--]--></div> <div class=\"syscheck-body svelte-1txhq2p\"><div class=\"syscheck-title svelte-1txhq2p\">Docker can run multi-container apps</div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-syscheck-retry\"${attr(\"disabled\", loading, true)}>${escape_html(\"Checking…\")}</button> <button class=\"btn btn-primary\" id=\"btn-syscheck-next\"${attr(\"disabled\", loading, true)}>Continue</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/WelcomeStep.svelte\nfunction WelcomeStep($$renderer, $$props) {\n\tlet { errorMessage, detectionReady, autoModeImporting, onnext, onusedefaults } = $$props;\n\t$$renderer.push(`<div class=\"welcome-hero\" id=\"welcome-hero\"><div class=\"welcome-icon\">👋</div> <h2>Welcome to OpenPalm</h2> <p class=\"welcome-subtitle\">Your self-hosted AI assistant. Pick your providers, choose models, and you're up and running.</p> <div class=\"welcome-pills\"><span class=\"pill\">Cloud or local</span> <span class=\"pill\">Smart defaults</span> <span class=\"pill\">Privacy first</span></div> `);\n\tif (errorMessage) {\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<div class=\"field-error\" id=\"step0-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t} else $$renderer.push(\"<!--[-1-->\");\n\t$$renderer.push(`<!--]--> <div class=\"welcome-actions svelte-1d9o2de\"><button class=\"btn btn-primary-lg svelte-1d9o2de\" id=\"btn-use-defaults\"${attr(\"disabled\", !detectionReady || autoModeImporting, true)}>`);\n\tif (autoModeImporting) {\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1d9o2de\"></span> Importing providers…`);\n\t} else if (!detectionReady) {\n\t\t$$renderer.push(\"<!--[1-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1d9o2de\"></span> Detecting your system…`);\n\t} else {\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`Use recommended defaults`);\n\t}\n\t$$renderer.push(`<!--]--></button> <button class=\"btn btn-secondary svelte-1d9o2de\" id=\"btn-step0-next\">Continue</button></div></div>`);\n}\n//#endregion\n//#region src/routes/setup/steps/ProvidersStep.svelte\nfunction ProvidersStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tfunction friendlyProviderError(raw, providerName) {\n\t\t\tif (!raw) return \"Connection failed\";\n\t\t\tconst view = friendlyError(raw, \"provider-verify\", providerName ? { providerName } : {});\n\t\t\treturn view.hint ? `${view.title}. ${view.hint}` : view.title;\n\t\t}\n\t\t/** Number of providers detected on this host's OpenCode install (0 = none) */\n\t\t/** Called when user chooses Import and clicks Continue — parent calls import-host then advances */\n\t\t/** Optional warning to display (e.g. partial host import failures) */\n\t\t/** Whether the user has explicitly opted to install with no provider */\n\t\t/** Called when the \"install without provider\" checkbox flips */\n\t\tlet { opencodeAvailable, opencodeProviders, opencodeAuth, providerState, expandedProvider, detectedProviders, detecting, ocFilterQuery, verifiedCount, onback, onnext, ontogglefallback, ontoggleopencode, onverify, onapikey, onbaseurl, onollamamode, onoauthstart, onoauthcancel, onmarkready, ondeselect, onfilterchange, hostProviderCount = 0, onhostimport, hostStatusWarning = null, allowEmptyInstall = false, onallowemptyinstallchange } = $$props;\n\t\tconst importMode = derived(() => hostProviderCount > 0 ? \"import\" : \"manual\");\n\t\tlet filteredOcProviders = derived(() => {\n\t\t\tconst query = ocFilterQuery.toLowerCase().trim();\n\t\t\tlet list = opencodeProviders;\n\t\t\tif (query) list = list.filter((p) => p.name.toLowerCase().includes(query) || p.id.toLowerCase().includes(query));\n\t\t\treturn [...list].sort((a, b) => {\n\t\t\t\tconst aConn = providerState[a.id]?.verified ? 1 : 0;\n\t\t\t\tconst bConn = providerState[b.id]?.verified ? 1 : 0;\n\t\t\t\tif (aConn !== bConn) return bConn - aConn;\n\t\t\t\treturn (a.name ?? a.id).localeCompare(b.name ?? b.id);\n\t\t\t});\n\t\t});\n\t\tconst RECOMMENDED_IDS = new Set([\n\t\t\t\"ollama\",\n\t\t\t\"huggingface\",\n\t\t\t\"openai\",\n\t\t\t\"google\",\n\t\t\t\"model-runner\",\n\t\t\t\"lmstudio\"\n\t\t]);\n\t\tlet ocRecommended = derived(() => filteredOcProviders().filter((p) => providerState[p.id]?.verified || RECOMMENDED_IDS.has(p.id)));\n\t\tlet ocRest = derived(() => filteredOcProviders().filter((p) => !providerState[p.id]?.verified && !RECOMMENDED_IDS.has(p.id)));\n\t\tlet ocDisplayList = derived(() => ocFilterQuery ? filteredOcProviders() : ocRecommended());\n\t\tlet ocRestCount = derived(() => ocFilterQuery ? 0 : ocRest().length);\n\t\t$$renderer.push(`<h2>Where should your models run?</h2> <p class=\"step-description\">Select one or more providers. Click a card to configure it.</p> `);\n\t\tif (hostStatusWarning) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"host-status-warning svelte-1iuc968\" role=\"alert\">⚠ ${escape_html(hostStatusWarning)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (hostProviderCount > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"host-import-choice svelte-1iuc968\"><p class=\"host-import-desc svelte-1iuc968\">We found OpenCode on this host with <strong>${escape_html(hostProviderCount)}</strong> provider${escape_html(hostProviderCount !== 1 ? \"s\" : \"\")} configured.</p> <label class=\"host-radio svelte-1iuc968\"><input type=\"radio\" name=\"provider-source\" value=\"import\"${attr(\"checked\", importMode() === \"import\", true)} class=\"svelte-1iuc968\"/> <span><strong>Import from host OpenCode</strong> <em>(recommended)</em></span></label> <label class=\"host-radio svelte-1iuc968\"><input type=\"radio\" name=\"provider-source\" value=\"manual\"${attr(\"checked\", importMode() === \"manual\", true)} class=\"svelte-1iuc968\"/> <span>Configure providers manually</span></label></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (!hostProviderCount || importMode() === \"manual\") {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tif (detecting) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"loading-state\" id=\"conn-detecting\"><span class=\"spinner\"></span> Detecting local providers...</div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> <div class=\"provider-grid\" id=\"provider-grid\">`);\n\t\t\tif (opencodeAvailable) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"model-filter-row\" style=\"margin-bottom:12px\"><input type=\"text\" class=\"model-filter-input\" id=\"oc-provider-filter\"${attr(\"placeholder\", `Search ${stringify(opencodeProviders.length)} providers…`)}${attr(\"value\", ocFilterQuery)} autocomplete=\"off\"/></div> <!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(ocDisplayList());\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet ocp = each_array[$$index_1];\n\t\t\t\t\tconst st = providerState[ocp.id] ?? {\n\t\t\t\t\t\tselected: false,\n\t\t\t\t\t\tverified: false,\n\t\t\t\t\t\tverifying: false,\n\t\t\t\t\t\terror: false,\n\t\t\t\t\t\tapiKey: \"\",\n\t\t\t\t\t\tbaseUrl: \"\",\n\t\t\t\t\t\tmodels: [],\n\t\t\t\t\t\tollamaMode: null\n\t\t\t\t\t};\n\t\t\t\t\tconst modelCount = st.models && st.models.length > 0 ? st.models.length : Object.keys(ocp.models ?? {}).length;\n\t\t\t\t\tconst authMethods = opencodeAuth[ocp.id] ?? [];\n\t\t\t\t\tconst isExpanded = expandedProvider === ocp.id;\n\t\t\t\t\t$$renderer.push(`<div${attr_class(`pcard ${st.verified ? \"selected verified\" : isExpanded ? \"selected\" : \"\"} ${isExpanded ? \"wide\" : \"\"}`)}${attr(\"data-provider\", ocp.id)}><div class=\"pcard-header\" role=\"button\" tabindex=\"0\"><div class=\"pcard-info\"><div class=\"pcard-name\">${escape_html(ocp.name)} `);\n\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-ok\">✓</span>`);\n\t\t\t\t\t} else if (st.verifying) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-wait\">⟳</span>`);\n\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-err\">✗</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div> <div class=\"pcard-desc\">${escape_html(modelCount)} model${escape_html(modelCount !== 1 ? \"s\" : \"\")} `);\n\t\t\t\t\tif (authMethods.length > 0) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`· ${escape_html(authMethods.length)} auth method${escape_html(authMethods.length !== 1 ? \"s\" : \"\")}`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div></div> <div class=\"pcard-check\" aria-hidden=\"true\">${escape_html(st.verified ? \"✓\" : \"\")}</div></div> `);\n\t\t\t\t\tif (isExpanded) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Connected</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\tif (st.error) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-err\">${escape_html(friendlyProviderError(st.errorMessage, ocp.name))}</div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\tif (authMethods.length > 0) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\t\t\t\tconst each_array_1 = ensure_array_like(authMethods);\n\t\t\t\t\t\t\t\tfor (let idx = 0, $$length = each_array_1.length; idx < $$length; idx++) {\n\t\t\t\t\t\t\t\t\tlet method = each_array_1[idx];\n\t\t\t\t\t\t\t\t\tif (method.type === \"api\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"password\" placeholder=\"API key\"${attr(\"value\", st.apiKey ?? \"\")}/> <button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Connecting...\" : method.label)}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else if (method.type === \"oauth\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><button class=\"auth-btn auth-btn-detect\" style=\"width:100%\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Waiting...\" : method.label)}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t} else if ((ocp.env ?? []).length > 0) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"password\"${attr(\"placeholder\", (ocp.env ?? [])[0])}${attr(\"value\", st.apiKey ?? \"\")}/> <button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Connecting...\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t} else if (ocp.id === \"openai-compatible\") {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"url\" placeholder=\"https://your-server.example/v1\"${attr(\"value\", st.baseUrl ?? \"\")}/></div> <div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"password\" placeholder=\"API key (optional)\"${attr(\"value\", st.apiKey ?? \"\")}/></div> <div class=\"auth-row\"><button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t} else if (ocp.localUrl) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[3-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", ocp.localUrl)}${attr(\"value\", st.baseUrl || ocp.localUrl)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div style=\"padding:4px 0;color:var(--color-text-secondary);font-size:var(--text-xs)\">No authentication required</div> <button class=\"auth-btn auth-btn-detect\">Mark as ready</button>`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\tif (st.oauthPolling) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:8px\">`);\n\t\t\t\t\t\t\t\tif (st.oauthUrl) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<p style=\"margin-bottom:6px\"><a${attr(\"href\", st.oauthUrl)} target=\"_blank\" rel=\"noopener\" style=\"color:var(--color-accent)\">Open authorization page →</a></p>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\t\tif (st.oauthInstructions) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<p style=\"margin-bottom:6px;white-space:pre-wrap;font-size:var(--text-xs)\">${escape_html(st.oauthInstructions)}</p>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> <p><span class=\"spinner\"></span> Waiting for authorization...</p> <button class=\"auth-btn\" style=\"margin-top:6px\">Cancel</button></div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\tif (ocRestCount() > 0 && !ocFilterQuery) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<button class=\"btn-show-all-providers svelte-1iuc968\" id=\"btn-show-all-providers\">${escape_html(`Show all providers (${ocRestCount()} more)`)}</button>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\tif (filteredOcProviders().length === 0 && ocFilterQuery) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:24px;color:var(--color-text-secondary)\">No providers match \"${escape_html(ocFilterQuery)}\"</div>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\tconst each_array_4 = ensure_array_like(PROVIDER_GROUPS);\n\t\t\t\tfor (let $$index_5 = 0, $$length = each_array_4.length; $$index_5 < $$length; $$index_5++) {\n\t\t\t\t\tlet group = each_array_4[$$index_5];\n\t\t\t\t\tconst members = PROVIDERS.filter((p) => p.group === group.id).sort((a, b) => a.order - b.order);\n\t\t\t\t\tif (members.length > 0) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"provider-group\"><div class=\"provider-group-header\"><h3 class=\"provider-group-label\">${escape_html(group.label)}</h3> <span class=\"provider-group-desc\">${escape_html(group.desc)}</span></div> <div class=\"provider-group-cards\"><!--[-->`);\n\t\t\t\t\t\tconst each_array_5 = ensure_array_like(members);\n\t\t\t\t\t\tfor (let $$index_4 = 0, $$length = each_array_5.length; $$index_4 < $$length; $$index_4++) {\n\t\t\t\t\t\t\tlet p = each_array_5[$$index_4];\n\t\t\t\t\t\t\tconst st = providerState[p.id] ?? {\n\t\t\t\t\t\t\t\tselected: false,\n\t\t\t\t\t\t\t\tverified: false,\n\t\t\t\t\t\t\t\tverifying: false,\n\t\t\t\t\t\t\t\terror: false,\n\t\t\t\t\t\t\t\tapiKey: \"\",\n\t\t\t\t\t\t\t\tbaseUrl: \"\",\n\t\t\t\t\t\t\t\tmodels: [],\n\t\t\t\t\t\t\t\tollamaMode: null\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tconst isExpanded = expandedProvider === p.id && st.selected;\n\t\t\t\t\t\t\tconst badgeCls = p.kind === \"cloud\" ? \"badge-cloud\" : p.kind === \"local\" ? \"badge-local\" : \"badge-hybrid\";\n\t\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`pcard ${st.selected ? \"selected\" : \"\"} ${st.verified ? \"verified\" : \"\"} ${isExpanded ? \"wide\" : \"\"}`)}${attr(\"data-provider\", p.id)}><div class=\"pcard-header\" role=\"button\" tabindex=\"0\"${attr(\"data-toggle-provider\", p.id)}><div class=\"pcard-icon\">${escape_html(p.icon)}</div> <div class=\"pcard-info\"><div class=\"pcard-name\">${escape_html(p.name)} <span${attr_class(`badge ${badgeCls}`, \"svelte-1iuc968\")}>${escape_html(p.kind)}</span> `);\n\t\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-ok\">✓</span>`);\n\t\t\t\t\t\t\t} else if (st.verifying) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-wait\">⟳</span>`);\n\t\t\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-err\">✗</span>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div> <div class=\"pcard-desc\">${escape_html(p.desc)}</div></div> <div class=\"pcard-check\" aria-hidden=\"true\">${escape_html(st.selected ? \"✓\" : \"\")}</div></div> `);\n\t\t\t\t\t\t\tif (isExpanded) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\t\t\t\t\t\tif (p.id === \"ollama\") {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\tif (!st.ollamaMode) {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"ollama-mode-prompt\"><p>Is Ollama already running on this machine?</p> <div class=\"ollama-mode-buttons\"><button class=\"ollama-mode-btn ollama-mode-btn-detect\">Yes, detect it</button> <button class=\"ollama-mode-btn ollama-mode-btn-stack\">No, add to stack</button></div></div>`);\n\t\t\t\t\t\t\t\t\t} else if (st.ollamaMode === \"running\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", p.baseUrl)}${attr(\"value\", st.baseUrl || p.baseUrl)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Ollama will be added to your Docker stack with default models.</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"ollama-mode-prompt\"><p>Ollama runs as a container in your stack with recommended models pre-configured.</p> <button class=\"auth-btn auth-btn-detect\" style=\"margin-top:4px\">Enable Ollama</button></div>`);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t} else if (p.needsUrl) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\" placeholder=\"https://your-server.example/v1\"${attr(\"value\", st.baseUrl || \"\")}/></div> `);\n\t\t\t\t\t\t\t\t\tif (p.optionalKey) {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-top:6px\"><input type=\"password\"${attr(\"placeholder\", p.placeholder || \"API key (optional)\")}${attr(\"value\", st.apiKey)}/></div>`);\n\t\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> <div class=\"auth-row\" style=\"margin-top:6px\"><button${attr_class(`auth-btn ${st.verified ? \"auth-btn-verified\" : \"auth-btn-verify\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : st.verified ? \"Connected ✓\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t\t} else if (p.needsKey) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"password\"${attr(\"placeholder\", p.placeholder || \"API key\")}${attr(\"value\", st.apiKey)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-verified\" : \"auth-btn-verify\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : st.verified ? \"Verified ✓\" : \"Verify\")}</button></div>`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", p.baseUrl || \"http://localhost:8080\")}${attr(\"value\", st.baseUrl || p.baseUrl || \"\")}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\t\tif (st.verified && p.id !== \"ollama\") {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Credentials verified</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-err\">${escape_html(friendlyProviderError(st.errorMessage, p.name) || \"Verification failed — check your \" + (p.needsKey ? \"credentials\" : \"endpoint\"))}</div>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (verifiedCount === 0 && (!hostProviderCount || importMode() === \"manual\")) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<label class=\"allow-empty-row svelte-1iuc968\"><input type=\"checkbox\" id=\"allow-empty-install\"${attr(\"checked\", allowEmptyInstall, true)} class=\"svelte-1iuc968\"/> <span>Install without an AI provider (assistant won't be able to chat until I add one from the dashboard)</span></label>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\" id=\"step1-actions\"><button class=\"btn btn-secondary\" id=\"btn-step1-back\">Back</button> `);\n\t\tif (importMode() === \"import\" && hostProviderCount > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<span class=\"nav-info\">Import ${escape_html(hostProviderCount)} provider${escape_html(hostProviderCount !== 1 ? \"s\" : \"\")} from host</span> <button class=\"btn btn-primary\" id=\"btn-step1-next\">Continue</button>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<span class=\"nav-info\" id=\"provider-count-info\">`);\n\t\t\tif (verifiedCount > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<b>${escape_html(verifiedCount)}</b> provider${escape_html(verifiedCount > 1 ? \"s\" : \"\")} ready`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`Connect a provider to continue`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></span> <button class=\"btn btn-primary\" id=\"btn-step1-next\"${attr(\"disabled\", verifiedCount === 0 && !allowEmptyInstall, true)}>${escape_html(verifiedCount > 0 ? \"Choose Models\" : \"Skip for now\")}</button>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/ModelsStep.svelte\nfunction ModelsStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { verifiedProviders, providerState, modelSelection, errorMessage, onback, onnext, onselect, onselectnone } = $$props;\n\t\tconst roles = [\n\t\t\t{\n\t\t\t\tid: \"llm\",\n\t\t\t\tlabel: \"Chat Model\",\n\t\t\t\ttag: \"required\",\n\t\t\t\tdesc: \"Conversations, reasoning, and code\"\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"embedding\",\n\t\t\t\tlabel: \"Memory Model\",\n\t\t\t\ttag: \"optional\",\n\t\t\t\tdesc: \"Helps the assistant remember past conversations. Optional.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"small\",\n\t\t\t\tlabel: \"Small Model\",\n\t\t\t\ttag: \"optional\",\n\t\t\t\tdesc: \"Lightweight tasks like summarization\"\n\t\t\t}\n\t\t];\n\t\tlet filterQueries = {};\n\t\tlet collapsedRoles = /* @__PURE__ */ new Set();\n\t\tfunction getOptionsForRole(role) {\n\t\t\tconst options = [];\n\t\t\tfor (const p of verifiedProviders) {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\tconst defaultModel = role.id === \"embedding\" ? p.embModel : p.llmModel;\n\t\t\t\tconst models = st.models.length > 0 ? st.models : [];\n\t\t\t\tif (defaultModel && models.includes(defaultModel)) options.push({\n\t\t\t\t\tid: defaultModel,\n\t\t\t\t\tconnId: p.id,\n\t\t\t\t\tproviderName: p.name,\n\t\t\t\t\tbaseUrl: st.baseUrl || p.baseUrl,\n\t\t\t\t\tisDefault: true,\n\t\t\t\t\tdims: role.id === \"embedding\" ? KNOWN_EMB_DIMS[defaultModel] ?? KNOWN_EMB_DIMS[defaultModel.replace(/:.*$/, \"\")] ?? p.embDims ?? 0 : 0\n\t\t\t\t});\n\t\t\t\tfor (const m of models) {\n\t\t\t\t\tif (m === defaultModel) continue;\n\t\t\t\t\tconst dims = role.id === \"embedding\" ? KNOWN_EMB_DIMS[m] ?? KNOWN_EMB_DIMS[m.replace(/:.*$/, \"\")] ?? 0 : 0;\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tid: m,\n\t\t\t\t\t\tconnId: p.id,\n\t\t\t\t\t\tproviderName: p.name,\n\t\t\t\t\t\tbaseUrl: st.baseUrl || p.baseUrl,\n\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\tdims\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (role.id === \"embedding\") {\n\t\t\t\tconst embOptions = options.filter((o) => o.isDefault || o.dims > 0);\n\t\t\t\tif (embOptions.length > 0) return embOptions;\n\t\t\t}\n\t\t\tif (role.id === \"small\" && options.length === 0) {\n\t\t\t\tconst llmProvider = verifiedProviders[0];\n\t\t\t\tif (llmProvider) for (const m of providerState[llmProvider.id].models) options.push({\n\t\t\t\t\tid: m,\n\t\t\t\t\tconnId: llmProvider.id,\n\t\t\t\t\tproviderName: llmProvider.name,\n\t\t\t\t\tbaseUrl: providerState[llmProvider.id].baseUrl || llmProvider.baseUrl,\n\t\t\t\t\tisDefault: false,\n\t\t\t\t\tdims: 0\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn options;\n\t\t}\n\t\tfunction filteredOptions(role, options) {\n\t\t\tconst query = (filterQueries[role.id] ?? \"\").toLowerCase().trim();\n\t\t\tif (!query) return options;\n\t\t\treturn options.filter((o) => o.id.toLowerCase().includes(query) || o.providerName.toLowerCase().includes(query));\n\t\t}\n\t\t$$renderer.push(`<h2>Choose Your Models</h2> <p class=\"step-description\">Pre-selected from your providers. Adjust if needed.</p> `);\n\t\tif (verifiedProviders.length === 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" style=\"margin-bottom:16px\">No providers configured. You can skip to complete setup and add providers from the admin panel later.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"model-groups\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(roles);\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet role = each_array[$$index_1];\n\t\t\tconst options = getOptionsForRole(role);\n\t\t\tif (options.length > 0 || role.id === \"small\") {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tconst hasOverflow = options.length > 6;\n\t\t\t\tconst query = filterQueries[role.id] ?? \"\";\n\t\t\t\tconst visible = filteredOptions(role, options);\n\t\t\t\t$$renderer.push(`<div class=\"model-group\"><div class=\"model-group-header\" role=\"button\" tabindex=\"0\" style=\"cursor:pointer;user-select:none\"><span class=\"model-group-title\">${escape_html(role.label)}</span> <span${attr_class(`model-group-tag ${role.tag === \"required\" ? \"model-group-tag-required\" : \"model-group-tag-optional\"}`)}>${escape_html(role.tag)}</span> `);\n\t\t\t\tif (collapsedRoles.has(role.id)) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\tconst sel = modelSelection[role.id];\n\t\t\t\t\t$$renderer.push(`<span style=\"flex:1;font-size:var(--text-xs);color:var(--color-text-secondary);margin-left:8px\">${escape_html(sel?.model ?? \"(none)\")}</span> <span style=\"font-size:var(--text-xs);color:var(--color-text-secondary)\">▶</span>`);\n\t\t\t\t} else {\n\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<span style=\"margin-left:auto;font-size:var(--text-xs);color:var(--color-text-secondary)\">▼</span>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div> `);\n\t\t\t\tif (!collapsedRoles.has(role.id)) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<div class=\"model-group-desc\">${escape_html(role.desc)}</div> `);\n\t\t\t\t\tif (role.id === \"small\") {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\tconst noneOn = !modelSelection.small?.model;\n\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`model-opt ${noneOn ? \"on\" : \"\"}`)} role=\"button\" tabindex=\"0\"><div class=\"model-opt-dot\"><div class=\"model-opt-dot-inner\"></div></div> <div style=\"flex:1\"><div class=\"model-opt-name\">(same as chat model)</div> <div class=\"model-opt-meta\">No separate small model</div></div> <span class=\"model-opt-badge model-opt-badge-auto\">Default</span></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\tif (options.length > 3) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"model-filter-row\"><input type=\"text\" class=\"model-filter-input\"${attr(\"placeholder\", `Search ${stringify(options.length)} models…`)}${attr(\"value\", query)} autocomplete=\"off\"/></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--> <!--[-->`);\n\t\t\t\t\tconst each_array_1 = ensure_array_like(query ? visible : options);\n\t\t\t\t\tfor (let idx = 0, $$length = each_array_1.length; idx < $$length; idx++) {\n\t\t\t\t\t\tlet opt = each_array_1[idx];\n\t\t\t\t\t\tconst firstDefaultIdx = options.findIndex((o) => o.isDefault);\n\t\t\t\t\t\tconst sel = modelSelection[role.id];\n\t\t\t\t\t\tconst isOn = !!sel && sel.model === opt.id && sel.connId === opt.connId;\n\t\t\t\t\t\tconst isHidden = !query && hasOverflow && idx >= 6 && !isOn;\n\t\t\t\t\t\tconst meta = \"via \" + opt.providerName + (opt.dims > 0 ? \" · \" + opt.dims + \"d\" : \"\");\n\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`model-opt ${isOn ? \"on\" : \"\"} ${isHidden ? \"model-opt-filtered\" : \"\"}`)} role=\"button\" tabindex=\"0\"${attr(\"data-model-select\", `${stringify(role.id)}:${stringify(opt.connId)}:${stringify(opt.id)}:${stringify(opt.dims)}`)}${attr(\"data-model-name\", opt.id.toLowerCase())}><div class=\"model-opt-dot\"><div class=\"model-opt-dot-inner\"></div></div> <div style=\"flex:1;min-width:0\"><div class=\"model-opt-name\">${escape_html(opt.id)}</div> <div class=\"model-opt-meta\">${escape_html(meta)}</div></div> `);\n\t\t\t\t\t\tif (idx === firstDefaultIdx && opt.isDefault) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<span class=\"model-opt-badge model-opt-badge-top\">Top Pick</span>`);\n\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <input type=\"hidden\" id=\"llm-connection\"${attr(\"value\", modelSelection.llm?.connId ?? \"\")}/> <input type=\"hidden\" id=\"llm-model\"${attr(\"value\", modelSelection.llm?.model ?? \"\")}/> <input type=\"hidden\" id=\"llm-small-model\"${attr(\"value\", modelSelection.small?.model ?? \"\")}/> <input type=\"hidden\" id=\"emb-connection\"${attr(\"value\", modelSelection.embedding?.connId ?? \"\")}/> <input type=\"hidden\" id=\"emb-model\"${attr(\"value\", modelSelection.embedding?.model ?? \"\")}/> <input type=\"hidden\" id=\"emb-dims\"${attr(\"value\", String(modelSelection.embedding?.dims ?? 1536))}/> `);\n\t\tif (errorMessage) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" id=\"step2-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step2-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step2-next\">${escape_html(verifiedProviders.length === 0 ? \"Skip for now\" : \"Voice Setup\")}</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/VoiceStep.svelte\nfunction VoiceStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { tts, stt, hasOpenAI, unknownTts = false, unknownStt = false, profiles = [], selectedVoiceProfile = \"\", onback, onnext, onchangetts, onchangestt, onprofilechange } = $$props;\n\t\tlet configureOpen = false;\n\t\tconst ttsLabel = derived(() => TTS_OPTIONS.find((o) => o.id === tts.engine)?.name ?? \"Browser Built-in\");\n\t\tconst sttLabel = derived(() => STT_OPTIONS.find((o) => o.id === stt.engine)?.name ?? \"Browser Built-in\");\n\t\tconst usesBundledVoice = derived(() => tts.engine === \"openpalm-voice\" || stt.engine === \"openpalm-voice\");\n\t\tconst selectedProfileLabel = derived(() => {\n\t\t\tif (!selectedVoiceProfile) return \"\";\n\t\t\tconst profile = profiles.find((p) => p.id === selectedVoiceProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedVoiceProfile;\n\t\t});\n\t\t$$renderer.push(`<h2>Voice Capabilities</h2> <p class=\"step-description\">Browser voice is ready out of the box — no setup needed.</p> `);\n\t\tif (unknownTts || unknownStt) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-unknown svelte-jxtfqg\" role=\"alert\">Your previous voice settings couldn't be loaded. Please pick an engine.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (usesBundledVoice()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-download-notice svelte-jxtfqg\" role=\"note\"><strong class=\"svelte-jxtfqg\">First install will download the OpenPalm Voice image.</strong> <ul class=\"svelte-jxtfqg\"><li>CPU build: ~2.4 GB (5–15 min on a typical home connection)</li> <li>CUDA build: ~7.6 GB (15–45 min — chosen later from the admin tab)</li></ul> The wizard's final Install step will show a progress indicator and\n wait for the download to finish before completing.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"voice-summary\" class=\"voice-summary svelte-jxtfqg\"><div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Text-to-Speech</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(ttsLabel())}</span></div> <div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Speech-to-Text</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(sttLabel())}</span></div> `);\n\t\tif (usesBundledVoice() && selectedProfileLabel()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Voice Container</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(selectedProfileLabel())}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> `);\n\t\tif (usesBundledVoice()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-profile-inline svelte-jxtfqg\"><div class=\"voice-profile-inline-title svelte-jxtfqg\">Voice container profile</div> `);\n\t\t\tif (profiles.length > 0 && onprofilechange) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\t\tprofiles,\n\t\t\t\t\tselectedProfile: selectedVoiceProfile,\n\t\t\t\t\tonchange: onprofilechange,\n\t\t\t\t\tshowDescription: false\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<p class=\"voice-profile-inline-loading svelte-jxtfqg\">Checking available hardware profiles…</p>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <details${attr(\"open\", configureOpen, true)} id=\"voice-configure-details\" class=\"svelte-jxtfqg\"><summary class=\"voice-configure-summary svelte-jxtfqg\" id=\"voice-configure-toggle\">Configure voice…</summary> <div id=\"voice-groups\" style=\"margin-top:12px\">`);\n\t\tif (hasOpenAI) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<p class=\"voice-hint svelte-jxtfqg\">OpenAI is available. You can use OpenAI TTS/STT or keep browser voice.</p>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<p class=\"voice-hint svelte-jxtfqg\">Kokoro and Whisper give higher quality. Browser voice works without extra setup.</p>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--> <div class=\"model-group\"><div class=\"model-group-header\"><span class=\"model-group-title\">Text-to-Speech</span> <span class=\"model-group-tag model-group-tag-optional\">Optional</span></div> <div class=\"model-group-desc\">How your assistant speaks</div> `);\n\t\tVoiceEngineSelector($$renderer, {\n\t\t\tkind: \"tts\",\n\t\t\tvalue: tts,\n\t\t\tonchange: onchangetts\n\t\t});\n\t\t$$renderer.push(`<!----></div> <div class=\"model-group\"><div class=\"model-group-header\"><span class=\"model-group-title\">Speech-to-Text</span> <span class=\"model-group-tag model-group-tag-optional\">Optional</span></div> <div class=\"model-group-desc\">How your assistant hears you</div> `);\n\t\tVoiceEngineSelector($$renderer, {\n\t\t\tkind: \"stt\",\n\t\t\tvalue: stt,\n\t\t\tonchange: onchangestt\n\t\t});\n\t\t$$renderer.push(`<!----></div></div></details> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step3-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step3-next\">Continue</button></div>`);\n\t});\n}\n//#endregion\n//#region src/lib/wizard/helpers.ts\nfunction isChannelEnabled(channelSelection, chId, locked) {\n\tif (locked) return true;\n\tconst sel = channelSelection[chId];\n\tif (typeof sel === \"object\" && sel !== null) return sel.enabled;\n\treturn !!sel;\n}\nfunction getCredValue(channelSelection, chId, key) {\n\tconst sel = channelSelection[chId];\n\tif (typeof sel === \"object\" && sel !== null) return String(sel[key] ?? \"\");\n\treturn \"\";\n}\n//#endregion\n//#region src/routes/setup/steps/OptionsStep.svelte\nfunction OptionsStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { channelSelection, imageTag, hostAkmEnabled, hostAkmAvailable, enableVoice, voiceProfiles, selectedVoiceProfile, ollamaEnabled, ollamaProfiles, selectedOllamaProfile, errorMessage, onback, onnext, onchanneltoggle, oncredentialchange, onimagtagchange, onhostakmchange, onenablevoicechange, onvoiceprofilechange, onollamachange, onollamaprofilechange } = $$props;\n\t\tfunction isChannelEnabled$2(chId, locked) {\n\t\t\treturn isChannelEnabled(channelSelection, chId, locked);\n\t\t}\n\t\tfunction getCredValue$2(chId, key) {\n\t\t\treturn getCredValue(channelSelection, chId, key);\n\t\t}\n\t\t$$renderer.push(`<h2>Options</h2> <p class=\"step-description\">Configure channels and deployment options.</p> <div class=\"options-section\"><h3 class=\"options-section-title\">Channels</h3> <p class=\"options-section-desc\">Additional ways to reach your assistant.</p> <div class=\"toggle-grid\" id=\"channels-grid\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(CHANNELS);\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet ch = each_array[$$index_1];\n\t\t\tconst isOn = isChannelEnabled$2(ch.id, ch.locked);\n\t\t\t$$renderer.push(`<div${attr_class(`toggle-card ${isOn ? \"on\" : \"\"} ${ch.locked ? \"locked\" : \"\"} ${ch.credentials && isOn ? \"wide\" : \"\"}`)}${attr(\"data-channel\", ch.id)}><div class=\"toggle-card-header\" role=\"button\"${attr(\"tabindex\", ch.locked ? -1 : 0)}><div class=\"toggle-card-icon\">${escape_html(ch.icon)}</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">${escape_html(ch.name)} `);\n\t\t\tif (ch.locked) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"badge badge-local\">Always on</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div> <div class=\"toggle-card-desc\">${escape_html(ch.desc)}</div></div> <div class=\"toggle-card-switch\">`);\n\t\t\tif (ch.locked) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"toggle-track on locked\"><div class=\"toggle-thumb\"></div></div>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<div${attr_class(`toggle-track ${isOn ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\t\tif (ch.credentials && isOn) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(ch.credentials);\n\t\t\t\tfor (let $$index = 0, $$length = each_array_1.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet cred = each_array_1[$$index];\n\t\t\t\t\tconst inputType = cred.secret === false ? \"text\" : \"password\";\n\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><label class=\"channel-cred-label\"${attr(\"for\", `cred-${stringify(ch.id)}-${stringify(cred.key)}`)}>${escape_html(cred.label)} `);\n\t\t\t\t\tif (cred.required) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"channel-cred-required\">*</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></label> <input${attr(\"id\", `cred-${stringify(ch.id)}-${stringify(cred.key)}`)}${attr(\"type\", inputType)}${attr(\"placeholder\", cred.placeholder ?? \"\")}${attr(\"value\", getCredValue$2(ch.id, cred.key))}/></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></div> <div class=\"options-section\"><h3 class=\"options-section-title\">Add-ons</h3> <p class=\"options-section-desc\">Optional features to extend your assistant.</p> <div class=\"toggle-grid\" id=\"addons-grid\"><div${attr_class(`toggle-card ${enableVoice ? \"on\" : \"\"} ${enableVoice && voiceProfiles.length > 0 ? \"wide\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🎙️</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Voice</div> <div class=\"toggle-card-desc\">Bundled text-to-speech and speech-to-text. Requires a one-time local model download.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${enableVoice ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div> `);\n\t\tif (enableVoice && voiceProfiles.length > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\tprofiles: voiceProfiles,\n\t\t\t\tselectedProfile: selectedVoiceProfile,\n\t\t\t\tonchange: onvoiceprofilechange,\n\t\t\t\tshowDescription: false\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div${attr_class(`toggle-card ${ollamaEnabled ? \"on\" : \"\"} ${ollamaEnabled && ollamaProfiles.length > 0 ? \"wide\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🦙</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Ollama</div> <div class=\"toggle-card-desc\">Run local AI models inside the stack. Downloads and serves models via Docker.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${ollamaEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div> `);\n\t\tif (ollamaEnabled && ollamaProfiles.length > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\tprofiles: ollamaProfiles,\n\t\t\t\tselectedProfile: selectedOllamaProfile,\n\t\t\t\tonchange: onollamaprofilechange,\n\t\t\t\tshowDescription: false\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div></div> <details id=\"options-advanced-details\" class=\"svelte-1q1mmx4\"><summary class=\"options-advanced-summary svelte-1q1mmx4\" id=\"options-advanced-toggle\">Advanced settings</summary> <div class=\"options-section\"><h3 class=\"options-section-title\">Container Image</h3> <p class=\"options-section-desc\">Tag or version of the OpenPalm images to deploy.</p> <div class=\"field-group\"><label for=\"image-tag\">Image tag</label> <div class=\"field-hint svelte-1q1mmx4\">Advanced — leave blank to use the default.</div> <input id=\"image-tag\" type=\"text\" placeholder=\"dev\"${attr(\"value\", imageTag)}/></div></div> `);\n\t\tif (hostAkmAvailable) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"options-section\"><h3 class=\"options-section-title\">Share knowledge with my host AKM</h3> <p class=\"options-section-desc\">Adds a source entry to your personal <code>~/.config/akm/config.json</code> and mounts <code>~/akm</code> into the assistant as a secondary source. Your files' ownership is not changed and your primary stash is unchanged — your <code>~/akm</code> data and cache stay yours.</p> <div class=\"toggle-grid\"><div${attr_class(`toggle-card ${hostAkmEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🧠</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Share knowledge with my host AKM (read + contribute)</div> <div class=\"toggle-card-desc\">The assistant reads your personal knowledge and can contribute back. Each side keeps its own primary stash, database, and cache — only the knowledge files are shared.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${hostAkmEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div></div></div></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></details> `);\n\t\tif (errorMessage) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step4-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step4-next\">Review</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/ReviewStep.svelte\nfunction ReviewStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { uiLoginPassword, verifiedProviders, modelSelection, activeTts, activeStt, voiceProfileLabel = \"\", ollamaProfileLabel = \"\", channelSelection, ollamaEnabled, payload, installError, installing, isRerun = false, onback, oninstall, ongostepedit } = $$props;\n\t\tfunction maskSecret(value) {\n\t\t\tif (!value || value.length < 8) return \"(not set)\";\n\t\t\treturn value.slice(0, 4) + \"...\" + value.slice(-4);\n\t\t}\n\t\tfunction isChannelEnabled$1(chId, locked) {\n\t\t\treturn isChannelEnabled(channelSelection, chId, locked);\n\t\t}\n\t\tfunction getCredValue$1(chId, key) {\n\t\t\treturn getCredValue(channelSelection, chId, key);\n\t\t}\n\t\tconst ttsOpt = derived(() => TTS_OPTIONS.find((o) => o.id === activeTts));\n\t\tconst sttOpt = derived(() => STT_OPTIONS.find((o) => o.id === activeStt));\n\t\tconst activeChannels = derived(() => CHANNELS.filter((ch) => isChannelEnabled$1(ch.id, ch.locked)));\n\t\tfunction findProvider(connId) {\n\t\t\treturn PROVIDERS.find((p) => p.id === connId);\n\t\t}\n\t\t$$renderer.push(`<h2>Review &amp; Install</h2> <p class=\"step-description\">Confirm your settings, then install.</p> `);\n\t\tif (verifiedProviders.length === 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-warning svelte-1q74f52\" role=\"alert\">⚠ No AI provider connected — your assistant won't be able to chat until you add one from the dashboard.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"review-summary\"><div class=\"review-card\"><div class=\"review-card-title\"><span>Account</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (!isRerun) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row review-row--alert svelte-1q74f52\"><span class=\"review-row-label\">UI Login Password</span> <span class=\"review-row-value\">`);\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<span class=\"token-save-box svelte-1q74f52\">${escape_html(uiLoginPassword.substring(0, 2))}*********</span>`);\n\t\t\t$$renderer.push(`<!--]--></span></div> <div class=\"review-row review-row--alert svelte-1q74f52\"><span class=\"review-row-label\"><span class=\"token-save-hint svelte-1q74f52\">You'll need this to sign in. Also saved in <code class=\"svelte-1q74f52\">stack.env</code>.</span></span> <span class=\"review-row-value\"><button type=\"button\" class=\"btn btn-secondary btn-sm\">${escape_html(\"Copy password\")}</button></span></div>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">UI Login Password</span> <span class=\"review-row-value\">${escape_html(maskSecret(uiLoginPassword))}</span></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Models</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (modelSelection.llm) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst llmProv = findProvider(modelSelection.llm.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Chat Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.llm.model)}${escape_html(llmProv ? \" (\" + llmProv.name + \")\" : \"\")}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (modelSelection.small?.model) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst smallProv = findProvider(modelSelection.small.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Small Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.small.model)}${escape_html(smallProv ? \" (\" + smallProv.name + \")\" : \"\")}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (modelSelection.embedding) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst embProv = findProvider(modelSelection.embedding.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Memory Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.embedding.model)}${escape_html(embProv ? \" (\" + embProv.name + \")\" : \"\")}</span></div> <div class=\"review-row\" style=\"padding:4px 0\"><span class=\"review-row-label\">Embedding Dims</span> <span class=\"review-row-value\">${escape_html(modelSelection.embedding.dims ?? 1536)}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Channels</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <!--[-->`);\n\t\tconst each_array = ensure_array_like(activeChannels());\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet ch = each_array[$$index_1];\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">${escape_html(ch.icon)} ${escape_html(ch.name)}</span> <span class=\"review-row-value review-row-value-ok\">Enabled ✓</span></div> `);\n\t\t\tif (ch.credentials) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (typeof sel === \"object\" && sel !== null && sel.enabled) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\tconst each_array_1 = ensure_array_like(ch.credentials);\n\t\t\t\t\tfor (let $$index = 0, $$length = each_array_1.length; $$index < $$length; $$index++) {\n\t\t\t\t\t\tlet cred = each_array_1[$$index];\n\t\t\t\t\t\tconst val = getCredValue$1(ch.id, cred.key);\n\t\t\t\t\t\tif (val) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\" style=\"padding-left:24px\">${escape_html(cred.label)}</span> <span class=\"review-row-value\">${escape_html(maskSecret(val))}</span></div>`);\n\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Voice</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <div class=\"review-row\"><span class=\"review-row-label\">Text-to-Speech</span> <span class=\"review-row-value\">${escape_html(ttsOpt() ? ttsOpt().name : \"Disabled\")}</span></div> <div class=\"review-row\"><span class=\"review-row-label\">Speech-to-Text</span> <span class=\"review-row-value\">${escape_html(sttOpt() ? sttOpt().name : \"Disabled\")}</span></div> `);\n\t\tif (voiceProfileLabel && (activeTts === \"openpalm-voice\" || activeStt === \"openpalm-voice\")) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Voice Container</span> <span class=\"review-row-value\">${escape_html(voiceProfileLabel)}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Options</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (ollamaEnabled) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Ollama In-Stack</span> <span class=\"review-row-value\">Enabled</span></div> `);\n\t\t\tif (ollamaProfileLabel) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Ollama Profile</span> <span class=\"review-row-value\">${escape_html(ollamaProfileLabel)}</span></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Providers</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <!--[-->`);\n\t\tconst each_array_2 = ensure_array_like(verifiedProviders);\n\t\tfor (let $$index_2 = 0, $$length = each_array_2.length; $$index_2 < $$length; $$index_2++) {\n\t\t\tlet p = each_array_2[$$index_2];\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">${escape_html(p.icon)} ${escape_html(p.name)}</span> <span class=\"review-row-value review-row-value-ok\">Connected ✓</span></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\tif (installError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tFriendlyError($$renderer, { error: friendlyError(installError, \"setup-complete\") });\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\" id=\"review-actions\"><button type=\"button\" class=\"btn btn-info\">Save configuration</button> <button class=\"btn btn-secondary\">Back</button> <button class=\"btn btn-primary\" id=\"btn-install\"${attr(\"disabled\", installing, true)}>`);\n\t\tif (installing) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<span class=\"spinner\"></span> Installing...`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`Install`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/DeployStep.svelte\nfunction DeployStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { deployData, deployDone, deployError, onback, onretry } = $$props;\n\t\tconst isElectron = typeof window !== \"undefined\" && !!window.openpalm;\n\t\tconst windowPort = typeof window !== \"undefined\" ? Number(window.location.port) || 3880 : 3880;\n\t\tconst adminPort = derived(() => deployData.ports?.admin ?? windowPort);\n\t\tconst assistantPort = derived(() => deployData.ports?.assistant ?? 3800);\n\t\tconst serviceLinks = derived(() => ({\n\t\t\tassistant: {\n\t\t\t\tport: assistantPort(),\n\t\t\t\tlabel: \"Assistant (OpenCode)\",\n\t\t\t\tpath: \"\"\n\t\t\t},\n\t\t\tadmin: {\n\t\t\t\tport: adminPort(),\n\t\t\t\tlabel: \"Admin Dashboard\",\n\t\t\t\tpath: \"\"\n\t\t\t}\n\t\t}));\n\t\tconst services = derived(() => deployData.deployStatus ?? []);\n\t\tconst total = derived(() => services().length);\n\t\tconst running = derived(() => services().filter((s) => s.status === \"running\").length);\n\t\tconst pct = derived(() => total() > 0 ? Math.round(running() / total() * 100) : 0);\n\t\tconst phase = derived(() => deployData.phase ?? \"writing-config\");\n\t\tconst voiceEnabled = derived(() => services().some((s) => /^voice(-cuda|-rocm)?$/.test(s.service ?? \"\")));\n\t\tconst deployTitle = derived(() => {\n\t\t\tif (deployDone) return \"Setup Complete\";\n\t\t\tif (deployError) return \"Deployment Issue\";\n\t\t\tswitch (phase()) {\n\t\t\t\tcase \"writing-config\": return \"Preparing Configuration…\";\n\t\t\t\tcase \"pulling-images\": return voiceEnabled() ? \"Downloading Images (incl. Voice ~2.4 GB)…\" : \"Downloading Images…\";\n\t\t\t\tcase \"starting\": return \"Starting Services…\";\n\t\t\t\tcase \"starting-voice\": return \"Starting Voice Addon…\";\n\t\t\t\tcase \"ready\": return \"Setup Complete\";\n\t\t\t}\n\t\t\treturn \"Deploying…\";\n\t\t});\n\t\tconst deploySubtitle = derived(() => {\n\t\t\tif (deployDone) return \"Your OpenPalm stack is up and running.\";\n\t\t\tif (deployError) return \"Setup could not finish starting the stack.\";\n\t\t\tswitch (phase()) {\n\t\t\t\tcase \"writing-config\": return \"Writing config files and validating settings.\";\n\t\t\t\tcase \"pulling-images\": return voiceEnabled() ? \"Downloading container images. The voice model (~2.4 GB) is the largest — on a typical home connection this step can take 10–30 minutes. The wizard will wait — keep this tab open.\" : \"Downloading container images — first install can take 3–8 minutes depending on connection.\";\n\t\t\t\tcase \"starting\": return `${running()} of ${total()} services running.`;\n\t\t\t\tcase \"starting-voice\": return \"Pulling the voice image (~2.4 GB) and warming up Kokoro + Whisper models. First launch can take 5–30 minutes on slow connections — the wizard will wait.\";\n\t\t\t\tcase \"ready\": return \"All services are up.\";\n\t\t\t}\n\t\t\treturn \"Writing configuration and starting services.\";\n\t\t});\n\t\tconst noStartMode = derived(() => deployDone && services().length === 0);\n\t\t$$renderer.push(`<div class=\"deploy-header\"><h2 id=\"deploy-title\">${escape_html(deployTitle())}</h2> <p class=\"step-description\" id=\"deploy-subtitle\">${escape_html(deploySubtitle())}</p></div> <div class=\"deploy-progress-summary\"><div class=\"deploy-progress-meta\"><span class=\"deploy-progress-label\">Progress</span> <span${attr_class(`deploy-progress-value ${deployError ? \"deploy-progress-value--error\" : \"\"}`)} id=\"deploy-progress-value\">`);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`Error`);\n\t\t} else if (deployDone) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`${escape_html(services().length > 0 ? \"100%\" : \"\")}`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`${escape_html(pct())}%`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></span></div> <div class=\"deploy-progress-bar\"><div class=\"deploy-progress-fill\" id=\"deploy-progress-fill\"${attr_style(`width:${stringify(deployDone && services().length > 0 ? 100 : deployDone ? 0 : pct())}%`)}></div></div></div> <div class=\"deploy-services\" id=\"deploy-services\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(services());\n\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\tlet svc = each_array[$$index];\n\t\t\t$$renderer.push(`<div class=\"deploy-service-row\"><div class=\"deploy-service-indicator\">`);\n\t\t\tif (svc.status === \"running\") {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-check\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--color-success)\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg></span>`);\n\t\t\t} else if (svc.status === \"error\") {\n\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-warning\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d97706\" stroke-width=\"2.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"></path><path d=\"M12 17h.01\"></path><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path></svg></span>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-spinner\"><span class=\"spinner\"></span></span>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div> <div class=\"deploy-service-info\"><span class=\"deploy-service-name\">${escape_html(svc.service || svc.label || \"\")}</span> <span class=\"deploy-service-status\">${escape_html(svc.label || svc.status)}</span></div> <div class=\"deploy-service-bar\"><div${attr_class(`deploy-bar-fill ${svc.status === \"running\" ? \"complete\" : svc.status === \"ready\" ? \"ready\" : svc.status === \"error\" ? \"stopped\" : \"indeterminate\"}`)}></div></div></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> `);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div id=\"deploy-failure\">`);\n\t\t\tFriendlyError($$renderer, { error: friendlyError(deployError, \"deploy\") });\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (!deployDone && !deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<aside class=\"deploy-tips\" id=\"deploy-tips\"><div class=\"deploy-tips-header\"><span class=\"deploy-tips-kicker\">Tips</span> <h3>${escape_html(voiceEnabled() ? \"First install may take 10–30 minutes\" : \"First startup takes a few minutes\")}</h3></div> <ul>`);\n\t\t\tif (voiceEnabled()) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<li>The OpenPalm Voice image is ~2.4 GB — the largest piece by far. Download speed depends on your internet connection.</li> <li>The wizard waits as long as the download takes. Progress bars below show each service's state.</li>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<li>Container images are being downloaded for the first time.</li>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--> <li>The admin console will be available once all services are healthy.</li> `);\n\t\t\tif (isElectron) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<li>You can leave this window — we'll let you know when it's ready.</li>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<li><strong>Keep this tab open while installation runs.</strong></li>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></ul></aside>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (deployDone) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"done-state\" id=\"deploy-done\"><div class=\"done-icon\"><svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--color-success)\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"></path><polyline points=\"22 4 12 14.01 9 11.01\"></polyline></svg></div> <h2>Setup Complete</h2> `);\n\t\t\tif (noStartMode()) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"done-subtitle\">Configuration saved. Run 'openpalm start' to start services.</p>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<p class=\"done-subtitle\">Your OpenPalm stack is up and running.</p> `);\n\t\t\t\tif (!isElectron) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<p class=\"done-close-hint svelte-1orw49v\">Setup is complete. You can safely close this tab now.</p>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> <ul class=\"service-list\" id=\"deploy-service-list\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(services());\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet svc = each_array_1[$$index_1];\n\t\t\t\t\tconst name = svc.service || svc.label || \"\";\n\t\t\t\t\tconst linkInfo = serviceLinks()[name];\n\t\t\t\t\t$$renderer.push(`<li>`);\n\t\t\t\t\tif (linkInfo) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\tconst url = \"http://localhost:\" + linkInfo.port + linkInfo.path;\n\t\t\t\t\t\t$$renderer.push(`<span class=\"deploy-svc-name\">${escape_html(linkInfo.label)}</span> <a${attr(\"href\", url)} target=\"_blank\" rel=\"noopener\" class=\"deploy-svc-link\">${escape_html(url)}</a> <span class=\"deploy-svc-status\">✓ Running</span>`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"deploy-svc-name\">${escape_html(name)}</span> <span class=\"deploy-svc-status\">✓ Running</span>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]--></li>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></ul> <div class=\"done-links\"><a${attr(\"href\", `http://localhost:${stringify(adminPort())}/chat`)} class=\"btn btn-primary\">Open Chat</a> <a${attr(\"href\", `http://localhost:${stringify(assistantPort())}`)} target=\"_blank\" rel=\"noopener\" class=\"btn btn-secondary\">OpenCode UI</a> <a${attr(\"href\", `http://localhost:${stringify(adminPort())}`)} class=\"btn btn-secondary\">Admin Dashboard</a></div>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"step-actions\" id=\"deploy-error-actions\"><button class=\"btn btn-secondary\" id=\"btn-deploy-back\">Back to Review</button> <button class=\"btn btn-primary\" id=\"btn-deploy-retry\">Retry</button></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/+page.svelte\nfunction _page($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet currentStep = 0;\n\t\tlet maxVisitedStep = 0;\n\t\tlet showDeploy = false;\n\t\tlet systemCheckPassed = false;\n\t\tlet uiLoginPassword = \"\";\n\t\tlet step0Error = \"\";\n\t\tlet detectionReady = false;\n\t\tlet autoModeImporting = false;\n\t\tlet enableVoice = false;\n\t\tlet gpuDetected = false;\n\t\tlet providerState = {};\n\t\tlet expandedProvider = null;\n\t\tlet detectedProviders = [];\n\t\tlet detecting = false;\n\t\tlet opencodeAvailable = false;\n\t\tlet opencodeProviders = [];\n\t\tlet opencodeAuth = {};\n\t\tlet ocFilterQuery = \"\";\n\t\tlet hostProviderCount = 0;\n\t\tlet hostStatusWarning = null;\n\t\tlet allowEmptyInstall = false;\n\t\tlet voiceEngineUnknownTts = false;\n\t\tlet voiceEngineUnknownStt = false;\n\t\t/** Generation counter per provider — discard stale verify results */\n\t\tconst verifyGeneration = {};\n\t\t/** AbortControllers for in-flight OAuth long-poll requests */\n\t\tconst oauthAbortControllers = {};\n\t\tlet modelSelection = {};\n\t\tlet step2Error = \"\";\n\t\tlet step2EmbDimWarning = \"\";\n\t\tlet voiceTts = { engine: \"\" };\n\t\tlet voiceStt = { engine: \"\" };\n\t\tlet voiceProfiles = [];\n\t\tlet selectedVoiceProfile = \"\";\n\t\tlet channelSelection = {\n\t\t\tdiscord: {\n\t\t\t\tenabled: false,\n\t\t\t\tbotToken: \"\",\n\t\t\t\tapplicationId: \"\"\n\t\t\t},\n\t\t\tslack: {\n\t\t\t\tenabled: false,\n\t\t\t\tslackBotToken: \"\",\n\t\t\t\tslackAppToken: \"\"\n\t\t\t}\n\t\t};\n\t\tlet ollamaEnabled = false;\n\t\tlet ollamaProfiles = [];\n\t\tlet selectedOllamaProfile = \"\";\n\t\tlet imageTag = \"\";\n\t\tlet hostAkmEnabled = false;\n\t\tlet hostAkmAvailable = false;\n\t\tlet step4Error = \"\";\n\t\tlet installError = \"\";\n\t\tlet installing = false;\n\t\tlet deployData = {};\n\t\tlet deployDone = false;\n\t\tlet deployError = null;\n\t\tlet deployTimer = null;\n\t\tlet deployPollErrors = 0;\n\t\tconst verifiedCount = derived(() => {\n\t\t\treturn PROVIDERS.map((p) => p.id).filter((id) => providerState[id]?.verified).length;\n\t\t});\n\t\tconst verifiedProviders = derived(() => {\n\t\t\treturn PROVIDERS.filter((p) => providerState[p.id]?.verified);\n\t\t});\n\t\tconst hasOllamaVerified = derived(() => PROVIDERS.some((p) => p.id === \"ollama\" && providerState[p.id]?.verified));\n\t\tconst hasOpenAI = derived(() => PROVIDERS.some((p) => p.id === \"openai\" && providerState[p.id]?.verified));\n\t\tconst voiceDefaults = derived(() => hasOpenAI() ? {\n\t\t\ttts: \"openai-tts\",\n\t\t\tstt: \"openai-stt\"\n\t\t} : {\n\t\t\ttts: \"browser-tts\",\n\t\t\tstt: \"browser-stt\"\n\t\t});\n\t\tconst displayedVoiceTts = derived(() => {\n\t\t\tif (voiceTts.engine) return voiceTts;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: voiceDefaults().tts };\n\t\t});\n\t\tconst displayedVoiceStt = derived(() => {\n\t\t\tif (voiceStt.engine) return voiceStt;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: voiceDefaults().stt };\n\t\t});\n\t\tconst persistedVoiceTts = derived(() => {\n\t\t\tif (voiceTts.engine) return voiceTts;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: \"\" };\n\t\t});\n\t\tconst persistedVoiceStt = derived(() => {\n\t\t\tif (voiceStt.engine) return voiceStt;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: \"\" };\n\t\t});\n\t\tconst selectedVoiceProfileLabel = derived(() => {\n\t\t\tif (!selectedVoiceProfile) return \"\";\n\t\t\tconst profile = voiceProfiles.find((p) => p.id === selectedVoiceProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedVoiceProfile;\n\t\t});\n\t\tconst selectedOllamaProfileLabel = derived(() => {\n\t\t\tif (!selectedOllamaProfile) return \"\";\n\t\t\tconst profile = ollamaProfiles.find((p) => p.id === selectedOllamaProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedOllamaProfile;\n\t\t});\n\t\tfunction addonProfileId(addon, variant) {\n\t\t\treturn `addon.${addon}.${variant}`;\n\t\t}\n\t\tconst payload = derived(() => {\n\t\t\tconst llm = modelSelection.llm;\n\t\t\tconst emb = modelSelection.embedding;\n\t\t\tconst small = modelSelection.small;\n\t\t\tconst capabilityProviderIds = {};\n\t\t\tif (llm) capabilityProviderIds[llm.connId] = true;\n\t\t\tif (emb) capabilityProviderIds[emb.connId] = true;\n\t\t\tif (small?.model) capabilityProviderIds[small.connId] = true;\n\t\t\tconst capabilities = verifiedProviders().filter((p) => capabilityProviderIds[p.id]).map((p) => {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\treturn {\n\t\t\t\t\tid: p.id,\n\t\t\t\t\tname: p.name,\n\t\t\t\t\tprovider: p.id,\n\t\t\t\t\tbaseUrl: st?.baseUrl ?? p.baseUrl,\n\t\t\t\t\tapiKey: st?.apiKey ?? \"\"\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst llmConnId = llm?.connId ?? \"\";\n\t\t\tconst embConnId = emb?.connId ?? \"\";\n\t\t\tconst llmCap = capabilities.find((c) => c.id === llmConnId);\n\t\t\tconst embCap = capabilities.find((c) => c.id === embConnId);\n\t\t\tconst llmProvider = llmCap?.provider ?? \"\";\n\t\t\tconst embProvider = embCap?.provider ?? \"\";\n\t\t\tconst addons = {};\n\t\t\tif (ollamaEnabled) addons.ollama = true;\n\t\t\tif (persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") addons.voice = true;\n\t\t\tconst channelCredentials = {};\n\t\t\tconst channelsConfig = buildChannelsConfig();\n\t\t\tfor (const chId of Object.keys(channelsConfig)) {\n\t\t\t\tconst chVal = channelsConfig[chId];\n\t\t\t\tif (chVal === true) addons[chId] = true;\n\t\t\t\telse if (typeof chVal === \"object\" && chVal !== null) {\n\t\t\t\t\taddons[chId] = true;\n\t\t\t\t\tconst creds = {};\n\t\t\t\t\tfor (const key of Object.keys(chVal)) if (key !== \"enabled\" && chVal[key]) creds[key] = String(chVal[key]);\n\t\t\t\t\tif (Object.keys(creds).length > 0) channelCredentials[chId] = creds;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst result = {\n\t\t\t\tversion: 2,\n\t\t\t\taddons,\n\t\t\t\tsecurity: { uiLoginPassword },\n\t\t\t\tconnections: capabilities\n\t\t\t};\n\t\t\tif (llmProvider && llm?.model) result.llm = {\n\t\t\t\tprovider: llmProvider,\n\t\t\t\tmodel: llm.model,\n\t\t\t\tbaseUrl: llmCap?.baseUrl ?? \"\"\n\t\t\t};\n\t\t\tif (embProvider && emb?.model) result.embedding = {\n\t\t\t\tprovider: embProvider,\n\t\t\t\tmodel: emb.model,\n\t\t\t\tdims: emb.dims ?? 1536,\n\t\t\t\tbaseUrl: embCap?.baseUrl ?? \"\"\n\t\t\t};\n\t\t\tconst voicePayload = (v) => {\n\t\t\t\tif (!v.engine || v.engine.startsWith(\"skip-\")) return void 0;\n\t\t\t\tconst out = {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tengine: v.engine\n\t\t\t\t};\n\t\t\t\tif (v.provider) out.provider = v.provider;\n\t\t\t\tif (v.baseURL) out.baseURL = v.baseURL;\n\t\t\t\tif (v.model) out.model = v.model;\n\t\t\t\tif (v.voice) out.voice = v.voice;\n\t\t\t\tif (v.language) out.language = v.language;\n\t\t\t\treturn out;\n\t\t\t};\n\t\t\tconst ttsCap = voicePayload(persistedVoiceTts());\n\t\t\tif (ttsCap) result.tts = ttsCap;\n\t\t\tconst sttCap = voicePayload(persistedVoiceStt());\n\t\t\tif (sttCap) result.stt = sttCap;\n\t\t\tif ((persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") && selectedVoiceProfile) result.voiceProfile = selectedVoiceProfile;\n\t\t\tif (ollamaEnabled && selectedOllamaProfile) result.ollamaProfile = selectedOllamaProfile;\n\t\t\tif (Object.keys(channelCredentials).length > 0) result.channelCredentials = channelCredentials;\n\t\t\tif (imageTag.trim()) result.imageTag = imageTag.trim();\n\t\t\tif (hostAkmEnabled) result.hostAkm = true;\n\t\t\treturn result;\n\t\t});\n\t\tfunction buildChannelsConfig() {\n\t\t\tconst result = {};\n\t\t\tfor (const ch of CHANNELS) {\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (ch.locked) result[ch.id] = true;\n\t\t\t\telse if (typeof sel === \"object\" && sel !== null) {\n\t\t\t\t\tif (sel.enabled) {\n\t\t\t\t\t\tconst entry = { enabled: true };\n\t\t\t\t\t\tif (ch.credentials) for (const cred of ch.credentials) {\n\t\t\t\t\t\t\tconst v = sel[cred.key];\n\t\t\t\t\t\t\tif (v) entry[cred.key] = v;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult[ch.id] = entry;\n\t\t\t\t\t}\n\t\t\t\t} else if (sel) result[ch.id] = true;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tfunction validateStep0() {\n\t\t\tif (uiLoginPassword.trim().length < 8) {\n\t\t\t\tstep0Error = \"UI login password must be at least 8 characters.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep0Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction enableRecommendedOllama() {\n\t\t\tollamaEnabled = true;\n\t\t\tconst st = providerState[\"ollama\"];\n\t\t\tif (st) {\n\t\t\t\tst.selected = true;\n\t\t\t\tst.verified = true;\n\t\t\t\tst.ollamaMode = \"instack\";\n\t\t\t\tst.baseUrl = \"http://ollama:11434\";\n\t\t\t\tif (st.models.length === 0) st.models = [\"nomic-embed-text\", \"qwen3:4b\"];\n\t\t\t}\n\t\t\tconst preferred = addonProfileId(\"ollama\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\tselectedOllamaProfile = (ollamaProfiles.find((p) => p.id === preferred && p.available !== false) ?? ollamaProfiles.find((p) => p.available !== false))?.id ?? preferred;\n\t\t}\n\t\tasync function handleUseDefaults() {\n\t\t\tif (verifiedProviders().length >= 1) {\n\t\t\t\tenableRecommendedOllama();\n\t\t\t\tautoSelectModels();\n\t\t\t\tgoToStep(5);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tenableRecommendedOllama();\n\t\t\tautoSelectModels();\n\t\t\tallowEmptyInstall = true;\n\t\t\tgoToStep(5);\n\t\t}\n\t\tfunction handleEnableVoiceChange(v) {\n\t\t\tenableVoice = v;\n\t\t\tif (v && !selectedVoiceProfile) {\n\t\t\t\tconst preferred = addonProfileId(\"voice\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\t\tconst match = voiceProfiles.find((p) => p.id === preferred && p.available !== false) ?? voiceProfiles.find((p) => p.available !== false);\n\t\t\t\tif (match) selectedVoiceProfile = match.id;\n\t\t\t}\n\t\t}\n\t\tfunction handleOptionsOllamaChange(v) {\n\t\t\tif (v) enableRecommendedOllama();\n\t\t\telse {\n\t\t\t\tollamaEnabled = false;\n\t\t\t\tconst st = providerState[\"ollama\"];\n\t\t\t\tif (st && st.ollamaMode !== \"running\") {\n\t\t\t\t\tst.selected = false;\n\t\t\t\t\tst.verified = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction validateStep2() {\n\t\t\tif (verifiedProviders().length === 0) {\n\t\t\t\tif (allowEmptyInstall) {\n\t\t\t\t\tstep2Error = \"\";\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tstep2Error = \"Connect at least one provider, or check \\\"Install without an AI provider\\\" on the previous step.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!modelSelection.llm?.model) {\n\t\t\t\tstep2Error = \"Select a chat model.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep2Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction validateStep4() {\n\t\t\tconst errors = [];\n\t\t\tfor (const ch of CHANNELS) {\n\t\t\t\tif (!ch.credentials) continue;\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (typeof sel !== \"object\" || sel === null) continue;\n\t\t\t\tif (!sel.enabled) continue;\n\t\t\t\tfor (const cred of ch.credentials) if (cred.required && !String(sel[cred.key] ?? \"\").trim()) errors.push(ch.name + \": \" + cred.label + \" is required.\");\n\t\t\t}\n\t\t\tif (errors.length > 0) {\n\t\t\t\tstep4Error = errors.join(\" \");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep4Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction canNavigateTo(step) {\n\t\t\tif (step > maxVisitedStep) return false;\n\t\t\treturn true;\n\t\t}\n\t\tfunction goToStep(n) {\n\t\t\tif (n < 0 || n > 6) return;\n\t\t\tif (n > 0 && !systemCheckPassed) return;\n\t\t\tcurrentStep = n;\n\t\t\tif (n > maxVisitedStep) maxVisitedStep = n;\n\t\t\tshowDeploy = false;\n\t\t\tif (n === 3) autoSelectModels();\n\t\t\tif (n === 5 && hasOllamaVerified()) ollamaEnabled = providerState.ollama?.ollamaMode === \"instack\";\n\t\t}\n\t\tfunction autoSelectModels() {\n\t\t\tfor (const roleId of [\n\t\t\t\t\"llm\",\n\t\t\t\t\"embedding\",\n\t\t\t\t\"small\"\n\t\t\t]) {\n\t\t\t\tif (modelSelection[roleId]) continue;\n\t\t\t\tconst options = getModelOptionsForRole(roleId);\n\t\t\t\tif (options.length === 0) continue;\n\t\t\t\tconst defaultOpt = roleId === \"embedding\" && ollamaEnabled ? options.find((o) => o.connId === \"ollama\") ?? options.find((o) => o.isDefault) ?? options[0] : options.find((o) => o.isDefault) ?? options[0];\n\t\t\t\tmodelSelection[roleId] = {\n\t\t\t\t\tconnId: defaultOpt.connId,\n\t\t\t\t\tmodel: defaultOpt.id,\n\t\t\t\t\tdims: defaultOpt.dims\n\t\t\t\t};\n\t\t\t\tif (roleId === \"embedding\" && defaultOpt.dims <= 0) step2EmbDimWarning = \"Unknown embedding model dimensions — set manually in akm config after install.\";\n\t\t\t}\n\t\t}\n\t\tfunction getModelOptionsForRole(roleId) {\n\t\t\tconst options = [];\n\t\t\tfor (const p of verifiedProviders()) {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\tconst defaultModel = roleId === \"embedding\" ? p.embModel : p.llmModel;\n\t\t\t\tconst models = st.models.length > 0 ? st.models : [];\n\t\t\t\tif (defaultModel && models.includes(defaultModel)) options.push({\n\t\t\t\t\tid: defaultModel,\n\t\t\t\t\tconnId: p.id,\n\t\t\t\t\tisDefault: true,\n\t\t\t\t\tdims: roleId === \"embedding\" ? KNOWN_EMB_DIMS[defaultModel] ?? KNOWN_EMB_DIMS[defaultModel.replace(/:.*$/, \"\")] ?? p.embDims ?? 0 : 0\n\t\t\t\t});\n\t\t\t\tfor (const m of models) {\n\t\t\t\t\tif (m === defaultModel) continue;\n\t\t\t\t\tconst dims = roleId === \"embedding\" ? KNOWN_EMB_DIMS[m] ?? KNOWN_EMB_DIMS[m.replace(/:.*$/, \"\")] ?? 0 : 0;\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tid: m,\n\t\t\t\t\t\tconnId: p.id,\n\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\tdims\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (roleId === \"embedding\" && ollamaEnabled) {\n\t\t\t\tconst ollamaSt = providerState[\"ollama\"];\n\t\t\t\tif (ollamaSt?.verified && !options.some((o) => o.connId === \"ollama\")) {\n\t\t\t\t\tconst embModel = \"nomic-embed-text\";\n\t\t\t\t\tif (ollamaSt.models.includes(embModel) || ollamaSt.models.length > 0) {\n\t\t\t\t\t\tconst dims = KNOWN_EMB_DIMS[embModel] ?? 768;\n\t\t\t\t\t\toptions.unshift({\n\t\t\t\t\t\t\tid: embModel,\n\t\t\t\t\t\t\tconnId: \"ollama\",\n\t\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\t\tdims\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (roleId === \"embedding\") {\n\t\t\t\tconst filtered = options.filter((o) => o.isDefault || o.dims > 0);\n\t\t\t\tif (filtered.length > 0) return filtered;\n\t\t\t}\n\t\t\treturn options;\n\t\t}\n\t\tasync function apiFetchModels(provider, baseUrl, apiKey) {\n\t\t\tconst url = \"/api/setup/models/\" + encodeURIComponent(provider);\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tapiKey: apiKey ?? \"\",\n\t\t\t\t\tbaseUrl: baseUrl ?? \"\"\n\t\t\t\t})\n\t\t\t});\n\t\t\tconst data = await res.json();\n\t\t\tif (!res.ok || data.status === \"recoverable_error\") throw new Error(data.error ?? \"Failed to fetch models (HTTP \" + res.status + \")\");\n\t\t\treturn data;\n\t\t}\n\t\tasync function verifyProvider(id) {\n\t\t\tconst p = PROVIDERS.find((x) => x.id === id);\n\t\t\tif (!p) return;\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tif (id === \"ollama\" && st.ollamaMode === \"instack\") {\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst gen = (verifyGeneration[id] ?? 0) + 1;\n\t\t\tverifyGeneration[id] = gen;\n\t\t\tst.verifying = true;\n\t\t\tst.error = false;\n\t\t\tconst baseUrl = (st.baseUrl || p.baseUrl).trim();\n\t\t\tconst apiKey = (st.apiKey ?? \"\").trim();\n\t\t\ttry {\n\t\t\t\tconst result = await apiFetchModels(id, baseUrl, apiKey);\n\t\t\t\tif (verifyGeneration[id] !== gen) return;\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t\tst.models = result.models ?? [];\n\t\t\t} catch (e) {\n\t\t\t\tif (verifyGeneration[id] !== gen) return;\n\t\t\t\tst.verified = false;\n\t\t\t\tst.error = true;\n\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"\";\n\t\t\t\tst.models = [];\n\t\t\t}\n\t\t\tst.verifying = false;\n\t\t}\n\t\tasync function startOpenCodeOAuth(providerId, methodIndex) {\n\t\t\tconst st = providerState[providerId];\n\t\t\tif (!st) return;\n\t\t\tst.verifying = true;\n\t\t\tst.error = false;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/opencode/provider/\" + encodeURIComponent(providerId) + \"/oauth/authorize\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ method: methodIndex })\n\t\t\t\t});\n\t\t\t\tconst oauthRes = await res.json();\n\t\t\t\tif (!res.ok) throw new Error(oauthRes.message ?? \"OAuth failed\");\n\t\t\t\tst.oauthPolling = true;\n\t\t\t\tst.oauthUrl = oauthRes.url ?? \"\";\n\t\t\t\tst.oauthInstructions = oauthRes.instructions ?? \"\";\n\t\t\t\tif (oauthRes.url && oauthRes.method === \"auto\") window.open(oauthRes.url, \"_blank\");\n\t\t\t\tawait pollOpenCodeOAuth(providerId, methodIndex);\n\t\t\t} catch (e) {\n\t\t\t\tst.verifying = false;\n\t\t\t\tst.error = true;\n\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"OAuth failed\";\n\t\t\t\tst.oauthPolling = false;\n\t\t\t}\n\t\t}\n\t\tasync function pollOpenCodeOAuth(providerId, methodIndex) {\n\t\t\tconst st = providerState[providerId];\n\t\t\tconst ac = new AbortController();\n\t\t\toauthAbortControllers[providerId] = ac;\n\t\t\tconst timeoutSignal = AbortSignal.timeout(10 * 6e4);\n\t\t\tconst combinedSignal = AbortSignal.any ? AbortSignal.any([ac.signal, timeoutSignal]) : ac.signal;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/opencode/provider/\" + encodeURIComponent(providerId) + \"/oauth/callback\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ method: methodIndex }),\n\t\t\t\t\tsignal: combinedSignal\n\t\t\t\t});\n\t\t\t\tconst data = await res.json().catch(() => null);\n\t\t\t\tif (res.ok && data?.ok) {\n\t\t\t\t\tst.verified = true;\n\t\t\t\t\tst.error = false;\n\t\t\t\t} else {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = data?.message ?? \"Authorization failed\";\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof Error && e.name === \"AbortError\" && ac.signal.aborted) return;\n\t\t\t\tif (e instanceof Error && e.name === \"AbortError\") {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = \"Authorization timed out. Try again.\";\n\t\t\t\t} else {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"Authorization failed\";\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tdelete oauthAbortControllers[providerId];\n\t\t\t\tst.oauthPolling = false;\n\t\t\t\tst.verifying = false;\n\t\t\t}\n\t\t}\n\t\tasync function handleInstall() {\n\t\t\tif (installing) return;\n\t\t\tinstallError = \"\";\n\t\t\tinstalling = true;\n\t\t\tif ((persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") && !selectedVoiceProfile) {\n\t\t\t\tconst preferred = addonProfileId(\"voice\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\t\tselectedVoiceProfile = (voiceProfiles.find((p) => p.id === preferred && p.available !== false) ?? voiceProfiles.find((p) => p.id === addonProfileId(\"voice\", \"cpu\") && p.available !== false) ?? voiceProfiles.find((p) => p.available !== false))?.id ?? addonProfileId(\"voice\", \"cpu\");\n\t\t\t}\n\t\t\tif (ollamaEnabled && !selectedOllamaProfile) selectedOllamaProfile = addonProfileId(\"ollama\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/complete\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify(payload())\n\t\t\t\t});\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (!res.ok || !data.ok) {\n\t\t\t\t\tinstallError = data.error ?? data.message ?? \"Install failed.\";\n\t\t\t\t\tinstalling = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshowDeploy = true;\n\t\t\t\tstartDeployPolling();\n\t\t\t} catch (e) {\n\t\t\t\tinstallError = \"Network error: \" + (e instanceof Error ? e.message : \"unable to reach server.\");\n\t\t\t\tinstalling = false;\n\t\t\t}\n\t\t}\n\t\tfunction startDeployPolling() {\n\t\t\tstopDeployPolling();\n\t\t\tpollDeployStatus();\n\t\t\tdeployTimer = setInterval(() => {\n\t\t\t\tpollDeployStatus();\n\t\t\t}, 2500);\n\t\t}\n\t\tfunction stopDeployPolling() {\n\t\t\tif (deployTimer) {\n\t\t\t\tclearInterval(deployTimer);\n\t\t\t\tdeployTimer = null;\n\t\t\t}\n\t\t}\n\t\tasync function pollDeployStatus() {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/deploy-status\");\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tdeployPollErrors++;\n\t\t\t\t\tif (deployPollErrors >= 5) {\n\t\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\t\tdeployError = \"Lost contact with the installer. Services may still be starting in the background.\";\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst data = await res.json();\n\t\t\t\tdeployPollErrors = 0;\n\t\t\t\tif (data.deployStatus && data.deployStatus.length > 0) data.deployStatus.map((s) => ({\n\t\t\t\t\tservice: s.service,\n\t\t\t\t\tstatus: s.status,\n\t\t\t\t\tlabel: s.label\n\t\t\t\t}));\n\t\t\t\tdeployData = data;\n\t\t\t\tif (data.deployError) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployError = data.deployError;\n\t\t\t\t} else if (data.setupComplete && data.deployStatus && data.deployStatus.length > 0) {\n\t\t\t\t\tif (data.deployStatus.every((s) => s.status === \"running\")) {\n\t\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\t\tdeployDone = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (data.setupComplete && !data.deploying && (!data.deployStatus || data.deployStatus.length === 0)) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployDone = true;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tdeployPollErrors++;\n\t\t\t\tif (deployPollErrors >= 5) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployError = err instanceof Error ? `Lost contact with the installer: ${err.message}` : \"Lost contact with the installer.\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction handleToggleFallback(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tif (st.selected) expandedProvider = expandedProvider === id ? null : id;\n\t\t\telse {\n\t\t\t\tst.selected = true;\n\t\t\t\texpandedProvider = id;\n\t\t\t\tconst detected = detectedProviders.find((d) => d.provider === id && d.available);\n\t\t\t\tif (detected) st.baseUrl = detected.url;\n\t\t\t}\n\t\t}\n\t\tfunction handleToggleOpenCode(id) {\n\t\t\texpandedProvider = expandedProvider === id ? null : id;\n\t\t}\n\t\tfunction handleDeselect(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tst.selected = false;\n\t\t\tst.verified = false;\n\t\t\tst.verifying = false;\n\t\t\tst.error = false;\n\t\t\tst.apiKey = \"\";\n\t\t\tst.models = [];\n\t\t\tif (id === \"ollama\") st.ollamaMode = null;\n\t\t\tif (expandedProvider === id) expandedProvider = null;\n\t\t}\n\t\tfunction handleMarkReady(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) {\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t}\n\t\t}\n\t\tfunction handleVerify(id) {\n\t\t\tverifyProvider(id);\n\t\t}\n\t\tfunction handleApiKey(id, key) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) st.apiKey = key;\n\t\t}\n\t\tfunction handleBaseUrl(id, url) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) st.baseUrl = url;\n\t\t}\n\t\tfunction handleOllamaMode(mode) {\n\t\t\tconst st = providerState.ollama;\n\t\t\tif (st) st.ollamaMode = mode;\n\t\t}\n\t\tfunction handleChannelToggle(id) {\n\t\t\tconst sel = channelSelection[id];\n\t\t\tif (typeof sel === \"object\" && sel !== null) sel.enabled = !sel.enabled;\n\t\t\telse channelSelection[id] = !sel;\n\t\t}\n\t\tfunction handleCredentialChange(chId, credKey, value) {\n\t\t\tconst sel = channelSelection[chId];\n\t\t\tif (typeof sel === \"object\" && sel !== null) sel[credKey] = value;\n\t\t}\n\t\tfunction handleSelectModel(role, connId, modelId, dims) {\n\t\t\tmodelSelection[role] = {\n\t\t\t\tconnId,\n\t\t\t\tmodel: modelId,\n\t\t\t\tdims\n\t\t\t};\n\t\t\tif (role === \"embedding\" && (dims <= 0 || dims === void 0)) step2EmbDimWarning = \"Unknown embedding model dimensions — set manually in akm config after install.\";\n\t\t\telse if (role === \"embedding\") step2EmbDimWarning = \"\";\n\t\t}\n\t\tfunction handleSelectNone(role) {\n\t\t\tdelete modelSelection[role];\n\t\t}\n\t\tfunction handleDeployRetry() {\n\t\t\tinstalling = false;\n\t\t\tdeployError = null;\n\t\t\tdeployDone = false;\n\t\t\tdeployData = {};\n\t\t\tdeployPollErrors = 0;\n\t\t\thandleInstall();\n\t\t}\n\t\tfunction handleDeployBack() {\n\t\t\tinstalling = false;\n\t\t\tdeployError = null;\n\t\t\tdeployDone = false;\n\t\t\tdeployData = {};\n\t\t\tdeployPollErrors = 0;\n\t\t\tshowDeploy = false;\n\t\t\tcurrentStep = 6;\n\t\t}\n\t\tlet hostImporting = false;\n\t\tasync function handleHostImport() {\n\t\t\thostImporting = true;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/import-host\", { method: \"POST\" });\n\t\t\t\tif (res.ok) {\n\t\t\t\t\tif ((await res.json()).ok) {\n\t\t\t\t\t\tfor (const id of Object.keys(providerState)) if (!providerState[id].verified && PROVIDERS.some((p) => p.id === id)) verifyProvider(id);\n\t\t\t\t\t\thostImporting = false;\n\t\t\t\t\t\tif (!isRerun) goToStep(3);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t\thostImporting = false;\n\t\t}\n\t\tlet isRerun = false;\n\t\thead(\"g40i6i\", $$renderer, ($$renderer) => {\n\t\t\t$$renderer.title(($$renderer) => {\n\t\t\t\t$$renderer.push(`<title>OpenPalm Setup</title>`);\n\t\t\t});\n\t\t\t$$renderer.push(`<link rel=\"stylesheet\" href=\"/setup/wizard.css\"/>`);\n\t\t});\n\t\t$$renderer.push(`<main class=\"setup-page\" aria-label=\"Setup wizard\"><div class=\"wizard-card\">`);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"wizard-header\"><div class=\"hdr-logo\">OP</div> <h1>OpenPalm <span class=\"hdr-suffix\">${escape_html(\"Setup\")}</span></h1></div> <div class=\"wizard-body\">`);\n\t\tif (!showDeploy) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tProgressBar($$renderer, {\n\t\t\t\tcurrentStep,\n\t\t\t\tmaxVisitedStep,\n\t\t\t\tonnavigate: goToStep,\n\t\t\t\tcanNavigateTo\n\t\t\t});\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (showDeploy) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tDeployStep($$renderer, {\n\t\t\t\tdeployData,\n\t\t\t\tdeployDone,\n\t\t\t\tdeployError,\n\t\t\t\tonback: handleDeployBack,\n\t\t\t\tonretry: handleDeployRetry\n\t\t\t});\n\t\t} else if (currentStep === 0) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-0\" data-testid=\"step-system-check\">`);\n\t\t\tSystemCheckStep($$renderer, {\n\t\t\t\tisRerun,\n\t\t\t\tonpass: () => {\n\t\t\t\t\tsystemCheckPassed = true;\n\t\t\t\t},\n\t\t\t\tonnext: () => {\n\t\t\t\t\tsystemCheckPassed = true;\n\t\t\t\t\tgoToStep(1);\n\t\t\t\t},\n\t\t\t\tongpudetected: (_gpu) => {\n\t\t\t\t\tgpuDetected = true;\n\t\t\t\t\tif (voiceProfiles.length > 0 && selectedVoiceProfile !== addonProfileId(\"voice\", \"cuda\")) {\n\t\t\t\t\t\tconst cuda = voiceProfiles.find((p) => p.id === addonProfileId(\"voice\", \"cuda\") && p.available !== false);\n\t\t\t\t\t\tif (cuda) selectedVoiceProfile = cuda.id;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 1) {\n\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-1\" data-testid=\"step-welcome\">`);\n\t\t\tWelcomeStep($$renderer, {\n\t\t\t\terrorMessage: step0Error,\n\t\t\t\tdetectionReady,\n\t\t\t\tautoModeImporting,\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep0()) goToStep(2);\n\t\t\t\t},\n\t\t\t\tonusedefaults: () => {\n\t\t\t\t\tif (validateStep0()) handleUseDefaults();\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 2) {\n\t\t\t$$renderer.push(\"<!--[3-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-2\" data-testid=\"step-capabilities\">`);\n\t\t\tif (hostImporting) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:48px 0\"><div class=\"loading-state\"><span class=\"spinner\"></span> Importing providers from host OpenCode…</div></div>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\tProvidersStep($$renderer, {\n\t\t\t\t\topencodeAvailable,\n\t\t\t\t\topencodeProviders,\n\t\t\t\t\topencodeAuth,\n\t\t\t\t\tproviderState,\n\t\t\t\t\texpandedProvider,\n\t\t\t\t\tdetectedProviders,\n\t\t\t\t\tdetecting,\n\t\t\t\t\tocFilterQuery,\n\t\t\t\t\tverifiedCount: verifiedCount(),\n\t\t\t\t\thostProviderCount,\n\t\t\t\t\thostStatusWarning,\n\t\t\t\t\tallowEmptyInstall,\n\t\t\t\t\tonback: () => goToStep(1),\n\t\t\t\t\tonnext: () => goToStep(3),\n\t\t\t\t\tontogglefallback: handleToggleFallback,\n\t\t\t\t\tontoggleopencode: handleToggleOpenCode,\n\t\t\t\t\tonverify: handleVerify,\n\t\t\t\t\tonapikey: handleApiKey,\n\t\t\t\t\tonbaseurl: handleBaseUrl,\n\t\t\t\t\tonollamamode: handleOllamaMode,\n\t\t\t\t\tonoauthstart: startOpenCodeOAuth,\n\t\t\t\t\tonoauthcancel: (id) => {\n\t\t\t\t\t\tconst ac = oauthAbortControllers[id];\n\t\t\t\t\t\tif (ac) {\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t\tdelete oauthAbortControllers[id];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst st = providerState[id];\n\t\t\t\t\t\tif (st) {\n\t\t\t\t\t\t\tst.oauthPolling = false;\n\t\t\t\t\t\t\tst.verifying = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonmarkready: handleMarkReady,\n\t\t\t\t\tondeselect: handleDeselect,\n\t\t\t\t\tonfilterchange: (q) => ocFilterQuery = q,\n\t\t\t\t\tonhostimport: () => void handleHostImport(),\n\t\t\t\t\tonallowemptyinstallchange: (v) => allowEmptyInstall = v\n\t\t\t\t});\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></section>`);\n\t\t} else if (currentStep === 3) {\n\t\t\t$$renderer.push(\"<!--[4-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-3\" data-testid=\"step-models\">`);\n\t\t\tif (step2EmbDimWarning) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"field-warning\" role=\"alert\">${escape_html(step2EmbDimWarning)}</div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tModelsStep($$renderer, {\n\t\t\t\tverifiedProviders: verifiedProviders(),\n\t\t\t\tproviderState,\n\t\t\t\tmodelSelection,\n\t\t\t\terrorMessage: step2Error,\n\t\t\t\tonback: () => goToStep(2),\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep2()) goToStep(4);\n\t\t\t\t},\n\t\t\t\tonselect: handleSelectModel,\n\t\t\t\tonselectnone: handleSelectNone\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 4) {\n\t\t\t$$renderer.push(\"<!--[5-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-4\" data-testid=\"step-voice\">`);\n\t\t\tVoiceStep($$renderer, {\n\t\t\t\ttts: displayedVoiceTts(),\n\t\t\t\tstt: displayedVoiceStt(),\n\t\t\t\thasOpenAI: hasOpenAI(),\n\t\t\t\tunknownTts: voiceEngineUnknownTts,\n\t\t\t\tunknownStt: voiceEngineUnknownStt,\n\t\t\t\tprofiles: voiceProfiles,\n\t\t\t\tselectedVoiceProfile,\n\t\t\t\tonback: () => goToStep(3),\n\t\t\t\tonnext: () => goToStep(5),\n\t\t\t\tonchangetts: (v) => {\n\t\t\t\t\tvoiceTts = v;\n\t\t\t\t\tvoiceEngineUnknownTts = false;\n\t\t\t\t},\n\t\t\t\tonchangestt: (v) => {\n\t\t\t\t\tvoiceStt = v;\n\t\t\t\t\tvoiceEngineUnknownStt = false;\n\t\t\t\t},\n\t\t\t\tonprofilechange: (id) => {\n\t\t\t\t\tselectedVoiceProfile = id;\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 5) {\n\t\t\t$$renderer.push(\"<!--[6-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-5\" data-testid=\"step-options\">`);\n\t\t\tOptionsStep($$renderer, {\n\t\t\t\tchannelSelection,\n\t\t\t\timageTag,\n\t\t\t\thostAkmEnabled,\n\t\t\t\thostAkmAvailable,\n\t\t\t\tenableVoice,\n\t\t\t\tvoiceProfiles,\n\t\t\t\tselectedVoiceProfile,\n\t\t\t\tollamaEnabled,\n\t\t\t\tollamaProfiles,\n\t\t\t\tselectedOllamaProfile,\n\t\t\t\terrorMessage: step4Error,\n\t\t\t\tonback: () => goToStep(4),\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep4()) goToStep(6);\n\t\t\t\t},\n\t\t\t\tonchanneltoggle: handleChannelToggle,\n\t\t\t\toncredentialchange: handleCredentialChange,\n\t\t\t\tonimagtagchange: (v) => imageTag = v,\n\t\t\t\tonhostakmchange: (v) => hostAkmEnabled = v,\n\t\t\t\tonenablevoicechange: handleEnableVoiceChange,\n\t\t\t\tonvoiceprofilechange: (id) => {\n\t\t\t\t\tselectedVoiceProfile = id;\n\t\t\t\t},\n\t\t\t\tonollamachange: handleOptionsOllamaChange,\n\t\t\t\tonollamaprofilechange: (id) => {\n\t\t\t\t\tselectedOllamaProfile = id;\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 6) {\n\t\t\t$$renderer.push(\"<!--[7-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-6\" data-testid=\"step-review\">`);\n\t\t\tReviewStep($$renderer, {\n\t\t\t\tuiLoginPassword,\n\t\t\t\tverifiedProviders: verifiedProviders(),\n\t\t\t\tmodelSelection,\n\t\t\t\tactiveTts: persistedVoiceTts().engine,\n\t\t\t\tactiveStt: persistedVoiceStt().engine,\n\t\t\t\tvoiceProfileLabel: selectedVoiceProfileLabel(),\n\t\t\t\tollamaProfileLabel: selectedOllamaProfileLabel(),\n\t\t\t\tchannelSelection,\n\t\t\t\tollamaEnabled,\n\t\t\t\tpayload: payload(),\n\t\t\t\tinstallError,\n\t\t\t\tinstalling,\n\t\t\t\tisRerun,\n\t\t\t\tonback: () => goToStep(5),\n\t\t\t\toninstall: handleInstall,\n\t\t\t\tongostepedit: goToStep\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div></main>`);\n\t});\n}\n//#endregion\nexport { _page as default };\n"],"names":[],"mappings":";;;AAkOA,IAAI,WAAW,GAAG;AAClB,CAAC,cAAc;AACf,CAAC,aAAa;AACd,CAAC,WAAW;AACZ,CAAC,QAAQ;AACT,CAAC,OAAO;AACR,CAAC,SAAS;AACV,CAAC;AACD,CAAC;;AChID;AACA;AACA,SAAS,WAAW,CAAC,UAAU,EAAE,OAAO,EAAE;AAC1C,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AACtC,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAc,aAAa,EAAE,GAAG,OAAO;AAC1E,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,mFAAmF,CAAC,CAAC;AACxG,EAAE,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACnD,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE;AACnE,GAAG,UAAU,CAAC,CAAC,CAAC;AAChB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC1F,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,gDAAgD,CAAC,CAAC;AACrE,EAAE,MAAM,YAAY,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACrD,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE;AACrE,GAAG,IAAI,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC;AAC9B,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,WAAW,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,cAAc,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;AAChS,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AACH;AAwCA;AACA;AACA,SAAS,eAAe,CAAC,UAAU,EAAE,OAAO,EAAE;AAC9C,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AAItC,EAAE,IAAI,OAAO,GAAG,IAAI;AACpB,EAAE,IAAI,MAAM,GAAG,IAAI;AAKnB,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,kHAAkH,CAAC,CAAC;AACvI,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,0EAA0E,EAAE,UAAU,CAAC,6BAA6B,EAAE,MAAM,EAAE;AACjJ,GAAG,kBAAkB,EAAE,MAAM;AAC7B,GAAG,oBAAoB,EAAE;AACzB,GAAG,CAAC,CAAC,2CAA2C,CAAC,CAAC;AAClD,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,0IAA0I,CAAC,CAAC;AAC/J,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,yBAAyB,EAAE,UAAU,CAAC,6BAA6B,EAAE,MAAM,EAAE;AAChG,GAAG,kBAAkB,EAAE,MAAM;AAC7B,GAAG,oBAAoB,EAAE;AACzB,GAAG,CAAC,CAAC,2CAA2C,CAAC,CAAC;AAClD,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,8IAA8I,CAAC,CAAC;AACnK,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,CAAC;AAC1C,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,kGAAkG,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,gEAAgE,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,wBAAwB,CAAC,CAAC;AAC/S,CAAC,CAAC,CAAC;AACH;AA83BA;AACA;AACA,SAAS,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE;AACpC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AACtC,EAAE,IAAI,WAAW,GAAG,CAAC;AACrB,EAAE,IAAI,cAAc,GAAG,CAAC;AAiSxB,EAAE,SAAS,aAAa,CAAC,IAAI,EAAE;AAC/B,GAAG,IAAI,IAAI,GAAG,cAAc,EAAE,OAAO,KAAK;AAC1C,GAAG,OAAO,IAAI;AACd,EAAE;AAyWF,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,UAAU,KAAK;AAC7C,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,UAAU,KAAK;AACpC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,6BAA6B,CAAC,CAAC;AACpD,GAAG,CAAC,CAAC;AACL,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,iDAAiD,CAAC,CAAC;AACvE,EAAE,CAAC,CAAC;AACJ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4EAA4E,CAAC,CAAC;AACjG,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,yGAAyG,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjM,EAAmB;AACnB,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/B,GAAG,WAAW,CAAC,UAAU,EAAE;AAC3B,IAAI,WAAW;AACf,IAAI,cAAc;AAClB,IACI;AACJ,IAAI,CAAC;AACL,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;AAC9B,EASgC;AAChC,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/B,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,0EAA0E,CAAC,CAAC;AAChG,GAAG,eAAe,CAAC,UAgBf,CAAC;AACL,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,CAAC;AACvC,EAAE;AAwKF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,2BAA2B,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AACH;;;;"}
1
+ {"version":3,"file":"_page.svelte-D0gMlmzQ.js","sources":["../../../.svelte-kit/adapter-node/chunks/VoiceProfileSelector.js","../../../.svelte-kit/adapter-node/entries/pages/setup/_page.svelte.js"],"sourcesContent":["import { B as attr, V as escape_html, a as ensure_array_like, i as derived, l as stringify, n as attr_class } from \"./dev.js\";\n//#region src/lib/wizard/constants.ts\nvar PROVIDER_GROUPS = [\n\t{\n\t\tid: \"recommended\",\n\t\tlabel: \"Recommended\",\n\t\tdesc: \"Best options to get started quickly\"\n\t},\n\t{\n\t\tid: \"local\",\n\t\tlabel: \"Local\",\n\t\tdesc: \"Run models on your own hardware\"\n\t},\n\t{\n\t\tid: \"cloud\",\n\t\tlabel: \"Cloud\",\n\t\tdesc: \"Hosted inference providers\"\n\t},\n\t{\n\t\tid: \"advanced\",\n\t\tlabel: \"Advanced\",\n\t\tdesc: \"Additional providers\"\n\t}\n];\nvar PROVIDERS = [\n\t{\n\t\tid: \"ollama\",\n\t\tname: \"Ollama\",\n\t\tkind: \"local\",\n\t\tgroup: \"recommended\",\n\t\torder: 1,\n\t\ticon: \"🦙\",\n\t\tdesc: \"Run open models on your hardware\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:11434\",\n\t\tllmModel: \"llama3.2\",\n\t\tembModel: \"nomic-embed-text\",\n\t\tembDims: 768,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"huggingface\",\n\t\tname: \"Hugging Face\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 2,\n\t\ticon: \"🤗\",\n\t\tdesc: \"10,000+ open models via Inference Providers\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"hf_...\",\n\t\tbaseUrl: \"https://router.huggingface.co/v1\",\n\t\tllmModel: \"Qwen/Qwen3-32B\",\n\t\tembModel: \"intfloat/multilingual-e5-large\",\n\t\tembDims: 1024,\n\t\tkeyPrefix: \"hf_\"\n\t},\n\t{\n\t\tid: \"openai\",\n\t\tname: \"OpenAI\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 3,\n\t\ticon: \"◐\",\n\t\tdesc: \"GPT and o-series reasoning models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"sk-...\",\n\t\tbaseUrl: \"https://api.openai.com\",\n\t\tllmModel: \"gpt-4o\",\n\t\tembModel: \"text-embedding-3-small\",\n\t\tembDims: 1536\n\t},\n\t{\n\t\tid: \"google\",\n\t\tname: \"Google\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"recommended\",\n\t\torder: 4,\n\t\ticon: \"◆\",\n\t\tdesc: \"Gemini models with large context\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"AIza...\",\n\t\tbaseUrl: \"https://generativelanguage.googleapis.com\",\n\t\tllmModel: \"gemini-2.5-flash\",\n\t\tembModel: \"\",\n\t\tembDims: 0,\n\t\tkeyPrefix: \"AI\"\n\t},\n\t{\n\t\tid: \"model-runner\",\n\t\tname: \"Docker Model Runner\",\n\t\tkind: \"local\",\n\t\tgroup: \"local\",\n\t\torder: 1,\n\t\ticon: \"🐳\",\n\t\tdesc: \"Docker-managed model runtime\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:12434\",\n\t\tllmModel: \"ai/llama3.2\",\n\t\tembModel: \"ai/mxbai-embed-large-v1\",\n\t\tembDims: 1024,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"lmstudio\",\n\t\tname: \"LM Studio\",\n\t\tkind: \"local\",\n\t\tgroup: \"local\",\n\t\torder: 2,\n\t\ticon: \"🔬\",\n\t\tdesc: \"Desktop app for local inference\",\n\t\tneedsKey: false,\n\t\tplaceholder: \"\",\n\t\tbaseUrl: \"http://localhost:1234\",\n\t\tllmModel: \"loaded-model\",\n\t\tembModel: \"\",\n\t\tembDims: 0,\n\t\tcanDetect: true\n\t},\n\t{\n\t\tid: \"groq\",\n\t\tname: \"Groq\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 1,\n\t\ticon: \"⚡\",\n\t\tdesc: \"Ultra-fast inference\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"gsk_...\",\n\t\tbaseUrl: \"https://api.groq.com/openai\",\n\t\tllmModel: \"llama-3.3-70b-versatile\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"mistral\",\n\t\tname: \"Mistral\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 2,\n\t\ticon: \"◆\",\n\t\tdesc: \"Mistral & Codestral models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"...\",\n\t\tbaseUrl: \"https://api.mistral.ai\",\n\t\tllmModel: \"mistral-large-latest\",\n\t\tembModel: \"mistral-embed\",\n\t\tembDims: 1024\n\t},\n\t{\n\t\tid: \"together\",\n\t\tname: \"Together AI\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"cloud\",\n\t\torder: 3,\n\t\ticon: \"✦\",\n\t\tdesc: \"Open models at scale\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"...\",\n\t\tbaseUrl: \"https://api.together.xyz\",\n\t\tllmModel: \"meta-llama/Llama-3.3-70B-Instruct-Turbo\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"deepseek\",\n\t\tname: \"DeepSeek\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 1,\n\t\ticon: \"◎\",\n\t\tdesc: \"DeepSeek chat & reasoning\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"sk-...\",\n\t\tbaseUrl: \"https://api.deepseek.com\",\n\t\tllmModel: \"deepseek-chat\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"xai\",\n\t\tname: \"xAI (Grok)\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 2,\n\t\ticon: \"✦\",\n\t\tdesc: \"Grok models\",\n\t\tneedsKey: true,\n\t\tplaceholder: \"xai-...\",\n\t\tbaseUrl: \"https://api.x.ai\",\n\t\tllmModel: \"grok-2\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t},\n\t{\n\t\tid: \"openai-compatible\",\n\t\tname: \"Custom API server\",\n\t\tkind: \"cloud\",\n\t\tgroup: \"advanced\",\n\t\torder: 3,\n\t\ticon: \"🔧\",\n\t\tdesc: \"Connect any AI server that uses the standard OpenAI API format.\",\n\t\tneedsKey: false,\n\t\tneedsUrl: true,\n\t\toptionalKey: true,\n\t\tplaceholder: \"API key (optional)\",\n\t\tbaseUrl: \"\",\n\t\tllmModel: \"\",\n\t\tembModel: \"\",\n\t\tembDims: 0\n\t}\n];\nvar KNOWN_EMB_DIMS = {\n\t\"text-embedding-3-small\": 1536,\n\t\"text-embedding-3-large\": 3072,\n\t\"text-embedding-ada-002\": 1536,\n\t\"nomic-embed-text\": 768,\n\t\"mxbai-embed-large\": 1024,\n\t\"mxbai-embed-large-v1\": 1024,\n\t\"ai/mxbai-embed-large-v1\": 1024,\n\t\"mistral-embed\": 1024,\n\t\"all-minilm\": 384,\n\t\"snowflake-arctic-embed\": 1024,\n\t\"intfloat/multilingual-e5-large\": 1024\n};\nvar STEP_LABELS = [\n\t\"System Check\",\n\t\"Get Started\",\n\t\"Providers\",\n\t\"Models\",\n\t\"Voice\",\n\t\"Options\",\n\t\"Review\"\n];\nvar TTS_OPTIONS = [\n\t{\n\t\tid: \"openpalm-voice\",\n\t\tname: \"OpenPalm Voice\",\n\t\ttype: \"local\",\n\t\trecommended: true,\n\t\tdesc: \"Bundled Kokoro TTS + Whisper STT — runs locally, no cloud. First install downloads ~2.4 GB.\"\n\t},\n\t{\n\t\tid: \"openai-tts\",\n\t\tname: \"OpenAI TTS\",\n\t\ttype: \"cloud\",\n\t\tdesc: \"Cloud voices. Uses your OpenAI API key\"\n\t},\n\t{\n\t\tid: \"browser-tts\",\n\t\tname: \"Browser Built-in\",\n\t\ttype: \"builtin\",\n\t\tdesc: \"Native speech synthesis. No setup needed\"\n\t},\n\t{\n\t\tid: \"skip-tts\",\n\t\tname: \"Skip — text only\",\n\t\ttype: \"skip\",\n\t\tdesc: \"Add TTS later from the dashboard\"\n\t}\n];\nvar STT_OPTIONS = [\n\t{\n\t\tid: \"openpalm-voice\",\n\t\tname: \"OpenPalm Voice\",\n\t\ttype: \"local\",\n\t\trecommended: true,\n\t\tdesc: \"Bundled Kokoro TTS + Whisper STT — runs locally, no cloud. First install downloads ~2.4 GB.\"\n\t},\n\t{\n\t\tid: \"openai-stt\",\n\t\tname: \"OpenAI Whisper\",\n\t\ttype: \"cloud\",\n\t\tdesc: \"Cloud Whisper API. Uses OpenAI key\"\n\t},\n\t{\n\t\tid: \"browser-stt\",\n\t\tname: \"Browser Built-in\",\n\t\ttype: \"builtin\",\n\t\tdesc: \"Web Speech API. No setup\"\n\t},\n\t{\n\t\tid: \"skip-stt\",\n\t\tname: \"Skip — text only\",\n\t\ttype: \"skip\",\n\t\tdesc: \"Add STT later from the dashboard\"\n\t}\n];\n/**\n* Per-engine configuration fields. Empty `fields` means \"no extra settings\".\n* `provider` is written to stack.env as OP_TTS_PROVIDER / OP_STT_PROVIDER\n* so the voice channel can resolve the runtime URL.\n*\n* Shared between the setup wizard's VoiceStep and the admin Capabilities tab.\n*/\nvar BASE_URL_FIELD = (placeholder, hint) => ({\n\tkey: \"baseURL\",\n\tlabel: \"Endpoint URL\",\n\tplaceholder,\n\thint\n});\nvar TTS_ENGINES = {\n\t\"openpalm-voice\": {\n\t\tid: \"openpalm-voice\",\n\t\tprovider: \"openpalm-voice\",\n\t\tfields: []\n\t},\n\t\"openai-tts\": {\n\t\tid: \"openai-tts\",\n\t\tprovider: \"openai\",\n\t\tfields: [\n\t\t\tBASE_URL_FIELD(\"https://api.openai.com/v1\", \"Leave empty to use the default OpenAI endpoint. Override for proxies / Azure-compat.\"),\n\t\t\t{\n\t\t\t\tkey: \"model\",\n\t\t\t\tlabel: \"Model\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"tts-1\",\n\t\t\t\t\t\"tts-1-hd\",\n\t\t\t\t\t\"gpt-4o-mini-tts\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"voice\",\n\t\t\t\tlabel: \"Voice\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"alloy\",\n\t\t\t\t\t\"echo\",\n\t\t\t\t\t\"fable\",\n\t\t\t\t\t\"onyx\",\n\t\t\t\t\t\"nova\",\n\t\t\t\t\t\"shimmer\"\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t},\n\t\"browser-tts\": {\n\t\tid: \"browser-tts\",\n\t\tfields: []\n\t},\n\t\"skip-tts\": {\n\t\tid: \"skip-tts\",\n\t\tfields: []\n\t}\n};\nvar STT_ENGINES = {\n\t\"openpalm-voice\": {\n\t\tid: \"openpalm-voice\",\n\t\tprovider: \"openpalm-voice\",\n\t\tfields: []\n\t},\n\t\"openai-stt\": {\n\t\tid: \"openai-stt\",\n\t\tprovider: \"openai\",\n\t\tfields: [\n\t\t\tBASE_URL_FIELD(\"https://api.openai.com/v1\", \"Leave empty to use the default OpenAI endpoint.\"),\n\t\t\t{\n\t\t\t\tkey: \"model\",\n\t\t\t\tlabel: \"Model\",\n\t\t\t\toptions: [\n\t\t\t\t\t\"whisper-1\",\n\t\t\t\t\t\"gpt-4o-mini-transcribe\",\n\t\t\t\t\t\"gpt-4o-transcribe\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: \"language\",\n\t\t\t\tlabel: \"Language\",\n\t\t\t\tplaceholder: \"en\",\n\t\t\t\thint: \"A language code like `en` or `fr`, or leave blank to detect automatically.\"\n\t\t\t}\n\t\t]\n\t},\n\t\"browser-stt\": {\n\t\tid: \"browser-stt\",\n\t\tfields: [{\n\t\t\tkey: \"language\",\n\t\t\tlabel: \"Language\",\n\t\t\tplaceholder: \"en-US\",\n\t\t\thint: \"A language code like `en` or `fr`, or leave blank to detect automatically.\"\n\t\t}]\n\t},\n\t\"skip-stt\": {\n\t\tid: \"skip-stt\",\n\t\tfields: []\n\t}\n};\nvar CHANNELS = [\n\t{\n\t\tid: \"api\",\n\t\tname: \"API\",\n\t\ticon: \"🔌\",\n\t\tdesc: \"OpenAI-compatible REST API endpoint\"\n\t},\n\t{\n\t\tid: \"discord\",\n\t\tname: \"Discord\",\n\t\ticon: \"🎮\",\n\t\tdesc: \"Connect to a Discord server\",\n\t\tcredentials: [{\n\t\t\tkey: \"botToken\",\n\t\t\tlabel: \"Bot Token\",\n\t\t\tplaceholder: \"Paste Discord bot token\",\n\t\t\trequired: true\n\t\t}, {\n\t\t\tkey: \"applicationId\",\n\t\t\tlabel: \"Application ID\",\n\t\t\tplaceholder: \"Discord application ID\",\n\t\t\tsecret: false\n\t\t}]\n\t},\n\t{\n\t\tid: \"slack\",\n\t\tname: \"Slack\",\n\t\ticon: \"💼\",\n\t\tdesc: \"Access via Slack bot\",\n\t\tcredentials: [{\n\t\t\tkey: \"slackBotToken\",\n\t\t\tlabel: \"Bot Token\",\n\t\t\tplaceholder: \"xoxb-...\",\n\t\t\trequired: true\n\t\t}, {\n\t\t\tkey: \"slackAppToken\",\n\t\t\tlabel: \"App Token\",\n\t\t\tplaceholder: \"xapp-...\",\n\t\t\trequired: true\n\t\t}]\n\t}\n];\nvar LOCAL_PROVIDERS = [\n\t{\n\t\tid: \"ollama\",\n\t\tname: \"Ollama\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:11434\"\n\t},\n\t{\n\t\tid: \"model-runner\",\n\t\tname: \"Docker Model Runner\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:12434\"\n\t},\n\t{\n\t\tid: \"lmstudio\",\n\t\tname: \"LM Studio\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"http://localhost:1234\"\n\t},\n\t{\n\t\tid: \"openai-compatible\",\n\t\tname: \"Custom API server\",\n\t\tenv: [],\n\t\tmodels: {},\n\t\tlocalUrl: \"\"\n\t}\n];\n//#endregion\n//#region src/lib/components/voice/VoiceEngineSelector.svelte\nfunction VoiceEngineSelector($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { kind, value, onchange, reachable, reachabilityEngineId, disabledEngines, hiddenEngines, engineOptions, engineConfigs } = $$props;\n\t\tconst allOptions = derived(() => engineOptions ?? (kind === \"tts\" ? TTS_OPTIONS : STT_OPTIONS));\n\t\tconst engines = derived(() => engineConfigs ?? (kind === \"tts\" ? TTS_ENGINES : STT_ENGINES));\n\t\tconst options = derived(() => hiddenEngines ? allOptions().filter((o) => !hiddenEngines.has(o.id)) : allOptions());\n\t\tfunction updateField(key, val) {\n\t\t\tconst next = { ...value };\n\t\t\tif (val) next[key] = val;\n\t\t\telse delete next[key];\n\t\t\tonchange(next);\n\t\t}\n\t\t$$renderer.push(`<div class=\"engine-list svelte-1e5u5jo\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(options());\n\t\tfor (let $$index_2 = 0, $$length = each_array.length; $$index_2 < $$length; $$index_2++) {\n\t\t\tlet o = each_array[$$index_2];\n\t\t\tconst selected = value.engine === o.id;\n\t\t\tconst config = engines()[o.id];\n\t\t\tconst engineState = disabledEngines?.[o.id];\n\t\t\tconst isDisabled = engineState?.disabled ?? false;\n\t\t\t$$renderer.push(`<button type=\"button\"${attr_class(\"engine-card svelte-1e5u5jo\", void 0, {\n\t\t\t\t\"engine-card--selected\": selected,\n\t\t\t\t\"engine-card--disabled\": isDisabled\n\t\t\t})}${attr(\"disabled\", isDisabled, true)}><div class=\"engine-body svelte-1e5u5jo\"><span class=\"engine-name svelte-1e5u5jo\">${escape_html(o.name)}</span> <span class=\"engine-desc svelte-1e5u5jo\">${escape_html(o.desc)}</span> `);\n\t\t\tif (isDisabled && engineState?.reason) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"engine-subtitle svelte-1e5u5jo\">${escape_html(engineState.reason)}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (o.id === (reachabilityEngineId ?? (kind === \"tts\" ? \"openai-tts\" : \"openai-stt\")) && reachable?.remoteConfigured) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span${attr_class(\"engine-reachability svelte-1e5u5jo\", void 0, { \"engine-reachability--ok\": reachable.remoteReachable })}>${escape_html(reachable.remoteReachable ? \"● Endpoint reachable\" : \"○ Endpoint not reachable\")}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div> `);\n\t\t\tif (o.recommended) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"badge badge-recommended\">Recommended</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></button> `);\n\t\t\tif (selected && config && config.fields.length > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"engine-config svelte-1e5u5jo\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(config.fields);\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet field = each_array_1[$$index_1];\n\t\t\t\t\t$$renderer.push(`<div class=\"form-field\"><label class=\"form-label\"${attr(\"for\", `voice-${stringify(kind)}-${stringify(field.key)}`)}>${escape_html(field.label)}</label> `);\n\t\t\t\t\tif (field.options) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.select({\n\t\t\t\t\t\t\tid: `voice-${stringify(kind)}-${stringify(field.key)}`,\n\t\t\t\t\t\t\tclass: \"form-input\",\n\t\t\t\t\t\t\tvalue: value[field.key] ?? \"\",\n\t\t\t\t\t\t\tonchange: (e) => updateField(field.key, e.currentTarget.value)\n\t\t\t\t\t\t}, ($$renderer) => {\n\t\t\t\t\t\t\t$$renderer.option({ value: \"\" }, ($$renderer) => {\n\t\t\t\t\t\t\t\t$$renderer.push(`— default —`);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\t\t\tconst each_array_2 = ensure_array_like(field.options);\n\t\t\t\t\t\t\tfor (let $$index = 0, $$length = each_array_2.length; $$index < $$length; $$index++) {\n\t\t\t\t\t\t\t\tlet opt = each_array_2[$$index];\n\t\t\t\t\t\t\t\t$$renderer.option({ value: opt }, ($$renderer) => {\n\t\t\t\t\t\t\t\t\t$$renderer.push(`${escape_html(opt)}`);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<input${attr(\"id\", `voice-${stringify(kind)}-${stringify(field.key)}`)}${attr(\"type\", field.key === \"baseURL\" ? \"url\" : \"text\")} class=\"form-input\"${attr(\"value\", value[field.key] ?? \"\")}${attr(\"placeholder\", field.placeholder ?? \"\")} autocomplete=\"off\"${attr(\"spellcheck\", field.key === \"baseURL\" ? false : void 0)}/>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\tif (field.hint) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"field-hint svelte-1e5u5jo\">${escape_html(field.hint)}</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div>`);\n\t});\n}\n//#endregion\n//#region src/lib/components/voice/VoiceProfileSelector.svelte\nfunction VoiceProfileSelector($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { profiles, selectedProfile, onchange, showDescription } = $$props;\n\t\tconst selectedInfo = derived(() => profiles.find((p) => p.id === selectedProfile) ?? profiles[0]);\n\t\tshowDescription ??= true;\n\t\tif (profiles.length === 0) $$renderer.push(\"<!--[0-->\");\n\t\telse if (profiles.length === 1) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`<p class=\"profile-single svelte-11ub9pr\">Using ${escape_html(selectedInfo()?.label ?? selectedInfo()?.id ?? \"selected\")}.</p>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\tif (showDescription) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"profile-desc svelte-11ub9pr\">Select the profile that matches your hardware. GPU profiles are auto-selected when available.</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> <div class=\"form-field\"><label class=\"form-label\" for=\"voice-profile\">Profile</label> `);\n\t\t\t$$renderer.select({\n\t\t\t\tid: \"voice-profile\",\n\t\t\t\tclass: \"form-input\",\n\t\t\t\tvalue: selectedProfile,\n\t\t\t\tonchange: (e) => onchange(e.currentTarget.value)\n\t\t\t}, ($$renderer) => {\n\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(profiles);\n\t\t\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet profile = each_array[$$index];\n\t\t\t\t\t$$renderer.option({\n\t\t\t\t\t\tvalue: profile.id,\n\t\t\t\t\t\tdisabled: profile.available === false,\n\t\t\t\t\t\ttitle: profile.available === false ? profile.reason ?? \"Not available on this host\" : void 0\n\t\t\t\t\t}, ($$renderer) => {\n\t\t\t\t\t\t$$renderer.push(`${escape_html(profile.label ?? profile.id)}${escape_html(profile.available === false ? \" — unavailable\" : \"\")}`);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t});\n\t\t\t$$renderer.push(` `);\n\t\t\tif (selectedInfo()?.requires) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"field-hint svelte-11ub9pr\">Requires: ${escape_html(selectedInfo().requires)}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (selectedInfo()?.available === false) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"field-hint field-hint--warning svelte-11ub9pr\">${escape_html(selectedInfo().reason ?? \"This profile is not available on the current host.\")}</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\nexport { LOCAL_PROVIDERS as a, STEP_LABELS as c, KNOWN_EMB_DIMS as i, STT_OPTIONS as l, VoiceEngineSelector as n, PROVIDERS as o, CHANNELS as r, PROVIDER_GROUPS as s, VoiceProfileSelector as t, TTS_OPTIONS as u };\n","import { B as attr, V as escape_html, a as ensure_array_like, i as derived, l as stringify, n as attr_class, o as head, r as attr_style } from \"../../../chunks/dev.js\";\nimport \"../../../chunks/index-server.js\";\nimport { c as STEP_LABELS, i as KNOWN_EMB_DIMS, l as STT_OPTIONS, n as VoiceEngineSelector, o as PROVIDERS, r as CHANNELS, s as PROVIDER_GROUPS, t as VoiceProfileSelector, u as TTS_OPTIONS } from \"../../../chunks/VoiceProfileSelector.js\";\n//#region src/lib/wizard/error-messages.ts\nvar DOCKER_LINK = {\n\tlabel: \"Docker setup\",\n\thref: \"https://docs.docker.com/get-docker/\"\n};\nfunction rawText(raw) {\n\tif (!raw) return \"\";\n\tif (raw instanceof Error) return raw.message;\n\tif (typeof raw === \"string\") return raw;\n\ttry {\n\t\treturn JSON.stringify(raw);\n\t} catch {\n\t\treturn String(raw);\n\t}\n}\nfunction friendlyError(raw, context = \"generic\", opts = {}) {\n\tconst text = rawText(raw);\n\tconst lower = text.toLowerCase();\n\tconst providerLabel = opts.providerName ? `${opts.providerName} didn't accept that key` : \"API key rejected\";\n\tif (/\\b(401|403|unauthorized|forbidden|invalid.?api.?key)\\b/i.test(text)) return {\n\t\ttitle: providerLabel,\n\t\tbody: \"The provider rejected the API key.\",\n\t\thint: \"Common causes: extra spaces, wrong account, or the key was revoked. Double-check the key and that it has access to the model you selected. Most providers show the key in their dashboard.\",\n\t\traw: text\n\t};\n\tif (/\\b(ENOTFOUND|ECONNREFUSED|getaddrinfo|EAI_AGAIN|EHOSTUNREACH)\\b/i.test(text)) return {\n\t\ttitle: \"Couldn't reach the host\",\n\t\tbody: text,\n\t\thint: \"Confirm the URL is correct and the service is online. For local providers (Ollama, LM Studio) make sure the server is running on this machine.\",\n\t\traw: text\n\t};\n\tif (/(timeout|timed out|AbortError|ETIMEDOUT)/i.test(text)) return {\n\t\ttitle: \"Request timed out\",\n\t\tbody: \"The provider didn't respond in time.\",\n\t\thint: \"It may be slow or temporarily down. Try again in a moment.\",\n\t\traw: text\n\t};\n\tif (lower.includes(\"docker\") || lower.includes(\"compose\") || lower.includes(\"daemon\")) return {\n\t\ttitle: \"Docker isn't available\",\n\t\tbody: \"OpenPalm needs Docker (with Compose v2) installed and running.\",\n\t\thint: \"Start Docker Desktop (macOS/Windows) or the docker daemon (Linux), then retry.\",\n\t\tlinks: [DOCKER_LINK],\n\t\traw: text\n\t};\n\tif (/EADDRINUSE/i.test(text) || /port.*in.?use/i.test(lower)) return {\n\t\ttitle: \"A required port is already in use\",\n\t\tbody: text,\n\t\thint: \"Another program is using one of OpenPalm's default ports. Quit the conflicting app, or change OpenPalm's port from the Admin Dashboard after setup.\",\n\t\traw: text\n\t};\n\tif (/EACCES|EPERM|permission denied/i.test(text)) return {\n\t\ttitle: \"Permission denied\",\n\t\tbody: text,\n\t\thint: \"OpenPalm couldn't write to its data directory. Check that ~/.openpalm/ is writable by your user.\",\n\t\traw: text\n\t};\n\tswitch (context) {\n\t\tcase \"provider-verify\":\n\t\tcase \"model-fetch\": return {\n\t\t\ttitle: \"Couldn't connect to the provider\",\n\t\t\tbody: text || \"Verification failed.\",\n\t\t\thint: \"Check the API key and base URL, then click Verify again.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"setup-complete\": return {\n\t\t\ttitle: \"Setup couldn't finish\",\n\t\t\tbody: text || \"Writing configuration failed.\",\n\t\t\thint: \"Check the technical details below, then retry. If the issue persists, the admin dashboard logs may help.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"deploy\":\n\t\tcase \"deploy-poll\": return {\n\t\t\ttitle: \"Deployment ran into a problem\",\n\t\t\tbody: text || \"One or more services failed to start.\",\n\t\t\thint: \"Image pulls can take several minutes on first install. Retry to attempt again; check Docker logs if it keeps failing.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"system-check\": return {\n\t\t\ttitle: \"System check failed\",\n\t\t\tbody: text || \"A required dependency is missing.\",\n\t\t\thint: \"Resolve the failing check above, then click Retry.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"channel\": return {\n\t\t\ttitle: \"Channel credential issue\",\n\t\t\tbody: text || \"A required field is missing or invalid.\",\n\t\t\thint: \"Confirm the bot token and other required fields are correct.\",\n\t\t\traw: text\n\t\t};\n\t\tcase \"port-conflict\": return {\n\t\t\ttitle: \"A required port is already in use\",\n\t\t\tbody: text || \"Another process is using one of OpenPalm's ports.\",\n\t\t\thint: \"Another program is using one of OpenPalm's default ports. Quit the conflicting app, or change OpenPalm's port from the Admin Dashboard after setup.\",\n\t\t\traw: text\n\t\t};\n\t\tdefault: return {\n\t\t\ttitle: \"Something went wrong\",\n\t\t\tbody: text || \"An unexpected error occurred.\",\n\t\t\thint: \"Try again. If the problem persists, check the admin dashboard logs.\",\n\t\t\traw: text\n\t\t};\n\t}\n}\n//#endregion\n//#region src/routes/setup/ProgressBar.svelte\nfunction ProgressBar($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { currentStep, maxVisitedStep, onnavigate, canNavigateTo } = $$props;\n\t\t$$renderer.push(`<nav class=\"prog-bar\" aria-label=\"Wizard steps\"><div class=\"prog-segments\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(STEP_LABELS);\n\t\tfor (let i = 0, $$length = each_array.length; i < $$length; i++) {\n\t\t\teach_array[i];\n\t\t\t$$renderer.push(`<div${attr_class(`prog-seg ${i <= currentStep ? \"on\" : \"\"}`)}></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"prog-labels\"><!--[-->`);\n\t\tconst each_array_1 = ensure_array_like(STEP_LABELS);\n\t\tfor (let i = 0, $$length = each_array_1.length; i < $$length; i++) {\n\t\t\tlet label = each_array_1[i];\n\t\t\t$$renderer.push(`<span${attr_class(`prog-lbl ${i <= currentStep ? \"on\" : \"\"} ${i === currentStep ? \"active\" : \"\"}`)} role=\"button\"${attr(\"tabindex\", i <= maxVisitedStep && canNavigateTo(i) ? 0 : -1)}${attr(\"aria-label\", `Go to step ${stringify(label)}`)}>${escape_html(label)}</span>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></nav>`);\n\t});\n}\n//#endregion\n//#region src/lib/components/FriendlyError.svelte\nfunction FriendlyError($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\t/** Render compactly without the technical-details disclosure (inline forms). */\n\t\tlet { error, role = \"alert\", compact = false } = $$props;\n\t\tif (error) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"friendly-error svelte-l9z7ob\"${attr(\"role\", role)}><div class=\"friendly-error-header svelte-l9z7ob\"><svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line></svg> <strong class=\"friendly-error-title svelte-l9z7ob\">${escape_html(error.title)}</strong></div> `);\n\t\t\tif (error.body) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"friendly-error-body svelte-l9z7ob\">${escape_html(error.body)}</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (error.hint) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"friendly-error-hint svelte-l9z7ob\">${escape_html(error.hint)}</p>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (error.links && error.links.length > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"friendly-error-links svelte-l9z7ob\"><!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(error.links);\n\t\t\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet link = each_array[$$index];\n\t\t\t\t\t$$renderer.push(`<a${attr(\"href\", link.href)} target=\"_blank\" rel=\"noopener noreferrer\" class=\"friendly-error-link svelte-l9z7ob\">${escape_html(link.label)} →</a>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tif (!compact && error.raw && error.raw !== error.body) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<details class=\"friendly-error-details svelte-l9z7ob\"><summary class=\"svelte-l9z7ob\">Technical details</summary> <pre class=\"svelte-l9z7ob\">${escape_html(error.raw)}</pre></details>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/SystemCheckStep.svelte\nfunction SystemCheckStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\t/** True when re-running an existing install; suppresses misleading\n\t\t* port-conflict warnings that just reflect the running stack itself. */\n\t\tlet { onnext, onpass, ongpudetected, isRerun = false } = $$props;\n\t\tlet loading = true;\n\t\tlet result = null;\n\t\tconst portConflicts = derived(() => isRerun ? [] : []);\n\t\tconst blockingPortConflicts = derived(() => portConflicts().filter((p) => p.blocking));\n\t\tderived(() => blockingPortConflicts().length > 0);\n\t\tderived(() => false);\n\t\t$$renderer.push(`<h2>System Check</h2> <p class=\"step-description\">Let's make sure your machine has everything OpenPalm needs.</p> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"syscheck-list svelte-1txhq2p\" aria-live=\"polite\"><div${attr_class(\"syscheck-row svelte-1txhq2p\", void 0, {\n\t\t\t\"syscheck-row--ok\": void 0,\n\t\t\t\"syscheck-row--fail\": result\n\t\t})}><div class=\"syscheck-icon svelte-1txhq2p\">`);\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1txhq2p\"></span>`);\n\t\t$$renderer.push(`<!--]--></div> <div class=\"syscheck-body svelte-1txhq2p\"><div class=\"syscheck-title svelte-1txhq2p\">Docker is installed and running</div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div> <div${attr_class(\"syscheck-row svelte-1txhq2p\", void 0, {\n\t\t\t\"syscheck-row--ok\": void 0,\n\t\t\t\"syscheck-row--fail\": result\n\t\t})}><div class=\"syscheck-icon svelte-1txhq2p\">`);\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1txhq2p\"></span>`);\n\t\t$$renderer.push(`<!--]--></div> <div class=\"syscheck-body svelte-1txhq2p\"><div class=\"syscheck-title svelte-1txhq2p\">Docker can run multi-container apps</div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-syscheck-retry\"${attr(\"disabled\", loading, true)}>${escape_html(\"Checking…\")}</button> <button class=\"btn btn-primary\" id=\"btn-syscheck-next\"${attr(\"disabled\", loading, true)}>Continue</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/WelcomeStep.svelte\nfunction WelcomeStep($$renderer, $$props) {\n\tlet { errorMessage, detectionReady, autoModeImporting, onnext, onusedefaults } = $$props;\n\t$$renderer.push(`<div class=\"welcome-hero\" id=\"welcome-hero\"><div class=\"welcome-icon\">👋</div> <h2>Welcome to OpenPalm</h2> <p class=\"welcome-subtitle\">Your self-hosted AI assistant. Pick your providers, choose models, and you're up and running.</p> <div class=\"welcome-pills\"><span class=\"pill\">Cloud or local</span> <span class=\"pill\">Smart defaults</span> <span class=\"pill\">Privacy first</span></div> `);\n\tif (errorMessage) {\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<div class=\"field-error\" id=\"step0-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t} else $$renderer.push(\"<!--[-1-->\");\n\t$$renderer.push(`<!--]--> <div class=\"welcome-actions svelte-1d9o2de\"><button class=\"btn btn-primary-lg svelte-1d9o2de\" id=\"btn-use-defaults\"${attr(\"disabled\", !detectionReady || autoModeImporting, true)}>`);\n\tif (autoModeImporting) {\n\t\t$$renderer.push(\"<!--[0-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1d9o2de\"></span> Importing providers…`);\n\t} else if (!detectionReady) {\n\t\t$$renderer.push(\"<!--[1-->\");\n\t\t$$renderer.push(`<span class=\"spinner svelte-1d9o2de\"></span> Detecting your system…`);\n\t} else {\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`Use recommended defaults`);\n\t}\n\t$$renderer.push(`<!--]--></button> <button class=\"btn btn-secondary svelte-1d9o2de\" id=\"btn-step0-next\">Continue</button></div></div>`);\n}\n//#endregion\n//#region src/routes/setup/steps/ProvidersStep.svelte\nfunction ProvidersStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tfunction friendlyProviderError(raw, providerName) {\n\t\t\tif (!raw) return \"Connection failed\";\n\t\t\tconst view = friendlyError(raw, \"provider-verify\", providerName ? { providerName } : {});\n\t\t\treturn view.hint ? `${view.title}. ${view.hint}` : view.title;\n\t\t}\n\t\t/** Number of providers detected on this host's OpenCode install (0 = none) */\n\t\t/** Called when user chooses Import and clicks Continue — parent calls import-host then advances */\n\t\t/** Optional warning to display (e.g. partial host import failures) */\n\t\t/** Whether the user has explicitly opted to install with no provider */\n\t\t/** Called when the \"install without provider\" checkbox flips */\n\t\tlet { opencodeAvailable, opencodeProviders, opencodeAuth, providerState, expandedProvider, detectedProviders, detecting, ocFilterQuery, verifiedCount, onback, onnext, ontogglefallback, ontoggleopencode, onverify, onapikey, onbaseurl, onollamamode, onoauthstart, onoauthcancel, onmarkready, ondeselect, onfilterchange, hostProviderCount = 0, onhostimport, hostStatusWarning = null, allowEmptyInstall = false, onallowemptyinstallchange } = $$props;\n\t\tconst importMode = derived(() => hostProviderCount > 0 ? \"import\" : \"manual\");\n\t\tlet filteredOcProviders = derived(() => {\n\t\t\tconst query = ocFilterQuery.toLowerCase().trim();\n\t\t\tlet list = opencodeProviders;\n\t\t\tif (query) list = list.filter((p) => p.name.toLowerCase().includes(query) || p.id.toLowerCase().includes(query));\n\t\t\treturn [...list].sort((a, b) => {\n\t\t\t\tconst aConn = providerState[a.id]?.verified ? 1 : 0;\n\t\t\t\tconst bConn = providerState[b.id]?.verified ? 1 : 0;\n\t\t\t\tif (aConn !== bConn) return bConn - aConn;\n\t\t\t\treturn (a.name ?? a.id).localeCompare(b.name ?? b.id);\n\t\t\t});\n\t\t});\n\t\tconst RECOMMENDED_IDS = new Set([\n\t\t\t\"ollama\",\n\t\t\t\"huggingface\",\n\t\t\t\"openai\",\n\t\t\t\"google\",\n\t\t\t\"model-runner\",\n\t\t\t\"lmstudio\"\n\t\t]);\n\t\tlet ocRecommended = derived(() => filteredOcProviders().filter((p) => providerState[p.id]?.verified || RECOMMENDED_IDS.has(p.id)));\n\t\tlet ocRest = derived(() => filteredOcProviders().filter((p) => !providerState[p.id]?.verified && !RECOMMENDED_IDS.has(p.id)));\n\t\tlet ocDisplayList = derived(() => ocFilterQuery ? filteredOcProviders() : ocRecommended());\n\t\tlet ocRestCount = derived(() => ocFilterQuery ? 0 : ocRest().length);\n\t\t$$renderer.push(`<h2>Where should your models run?</h2> <p class=\"step-description\">Select one or more providers. Click a card to configure it.</p> `);\n\t\tif (hostStatusWarning) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"host-status-warning svelte-1iuc968\" role=\"alert\">⚠ ${escape_html(hostStatusWarning)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (hostProviderCount > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"host-import-choice svelte-1iuc968\"><p class=\"host-import-desc svelte-1iuc968\">We found OpenCode on this host with <strong>${escape_html(hostProviderCount)}</strong> provider${escape_html(hostProviderCount !== 1 ? \"s\" : \"\")} configured.</p> <label class=\"host-radio svelte-1iuc968\"><input type=\"radio\" name=\"provider-source\" value=\"import\"${attr(\"checked\", importMode() === \"import\", true)} class=\"svelte-1iuc968\"/> <span><strong>Import from host OpenCode</strong> <em>(recommended)</em></span></label> <label class=\"host-radio svelte-1iuc968\"><input type=\"radio\" name=\"provider-source\" value=\"manual\"${attr(\"checked\", importMode() === \"manual\", true)} class=\"svelte-1iuc968\"/> <span>Configure providers manually</span></label></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (!hostProviderCount || importMode() === \"manual\") {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tif (detecting) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"loading-state\" id=\"conn-detecting\"><span class=\"spinner\"></span> Detecting local providers...</div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> <div class=\"provider-grid\" id=\"provider-grid\">`);\n\t\t\tif (opencodeAvailable) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"model-filter-row\" style=\"margin-bottom:12px\"><input type=\"text\" class=\"model-filter-input\" id=\"oc-provider-filter\"${attr(\"placeholder\", `Search ${stringify(opencodeProviders.length)} providers…`)}${attr(\"value\", ocFilterQuery)} autocomplete=\"off\"/></div> <!--[-->`);\n\t\t\t\tconst each_array = ensure_array_like(ocDisplayList());\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet ocp = each_array[$$index_1];\n\t\t\t\t\tconst st = providerState[ocp.id] ?? {\n\t\t\t\t\t\tselected: false,\n\t\t\t\t\t\tverified: false,\n\t\t\t\t\t\tverifying: false,\n\t\t\t\t\t\terror: false,\n\t\t\t\t\t\tapiKey: \"\",\n\t\t\t\t\t\tbaseUrl: \"\",\n\t\t\t\t\t\tmodels: [],\n\t\t\t\t\t\tollamaMode: null\n\t\t\t\t\t};\n\t\t\t\t\tconst modelCount = st.models && st.models.length > 0 ? st.models.length : Object.keys(ocp.models ?? {}).length;\n\t\t\t\t\tconst authMethods = opencodeAuth[ocp.id] ?? [];\n\t\t\t\t\tconst isExpanded = expandedProvider === ocp.id;\n\t\t\t\t\t$$renderer.push(`<div${attr_class(`pcard ${st.verified ? \"selected verified\" : isExpanded ? \"selected\" : \"\"} ${isExpanded ? \"wide\" : \"\"}`)}${attr(\"data-provider\", ocp.id)}><div class=\"pcard-header\" role=\"button\" tabindex=\"0\"><div class=\"pcard-info\"><div class=\"pcard-name\">${escape_html(ocp.name)} `);\n\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-ok\">✓</span>`);\n\t\t\t\t\t} else if (st.verifying) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-wait\">⟳</span>`);\n\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-err\">✗</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div> <div class=\"pcard-desc\">${escape_html(modelCount)} model${escape_html(modelCount !== 1 ? \"s\" : \"\")} `);\n\t\t\t\t\tif (authMethods.length > 0) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`· ${escape_html(authMethods.length)} auth method${escape_html(authMethods.length !== 1 ? \"s\" : \"\")}`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div></div> <div class=\"pcard-check\" aria-hidden=\"true\">${escape_html(st.verified ? \"✓\" : \"\")}</div></div> `);\n\t\t\t\t\tif (isExpanded) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Connected</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\tif (st.error) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-err\">${escape_html(friendlyProviderError(st.errorMessage, ocp.name))}</div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\tif (authMethods.length > 0) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\t\t\t\tconst each_array_1 = ensure_array_like(authMethods);\n\t\t\t\t\t\t\t\tfor (let idx = 0, $$length = each_array_1.length; idx < $$length; idx++) {\n\t\t\t\t\t\t\t\t\tlet method = each_array_1[idx];\n\t\t\t\t\t\t\t\t\tif (method.type === \"api\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"password\" placeholder=\"API key\"${attr(\"value\", st.apiKey ?? \"\")}/> <button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Connecting...\" : method.label)}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else if (method.type === \"oauth\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><button class=\"auth-btn auth-btn-detect\" style=\"width:100%\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Waiting...\" : method.label)}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t} else if ((ocp.env ?? []).length > 0) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"password\"${attr(\"placeholder\", (ocp.env ?? [])[0])}${attr(\"value\", st.apiKey ?? \"\")}/> <button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Connecting...\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t} else if (ocp.id === \"openai-compatible\") {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"url\" placeholder=\"https://your-server.example/v1\"${attr(\"value\", st.baseUrl ?? \"\")}/></div> <div class=\"auth-row\" style=\"margin-bottom:6px\"><input type=\"password\" placeholder=\"API key (optional)\"${attr(\"value\", st.apiKey ?? \"\")}/></div> <div class=\"auth-row\"><button class=\"auth-btn auth-btn-verify\"${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t} else if (ocp.localUrl) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[3-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", ocp.localUrl)}${attr(\"value\", st.baseUrl || ocp.localUrl)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div style=\"padding:4px 0;color:var(--color-text-secondary);font-size:var(--text-xs)\">No authentication required</div> <button class=\"auth-btn auth-btn-detect\">Mark as ready</button>`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\tif (st.oauthPolling) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:8px\">`);\n\t\t\t\t\t\t\t\tif (st.oauthUrl) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<p style=\"margin-bottom:6px\"><a${attr(\"href\", st.oauthUrl)} target=\"_blank\" rel=\"noopener\" style=\"color:var(--color-accent)\">Open authorization page →</a></p>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\t\tif (st.oauthInstructions) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<p style=\"margin-bottom:6px;white-space:pre-wrap;font-size:var(--text-xs)\">${escape_html(st.oauthInstructions)}</p>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> <p><span class=\"spinner\"></span> Waiting for authorization...</p> <button class=\"auth-btn\" style=\"margin-top:6px\">Cancel</button></div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\tif (ocRestCount() > 0 && !ocFilterQuery) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<button class=\"btn-show-all-providers svelte-1iuc968\" id=\"btn-show-all-providers\">${escape_html(`Show all providers (${ocRestCount()} more)`)}</button>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\tif (filteredOcProviders().length === 0 && ocFilterQuery) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:24px;color:var(--color-text-secondary)\">No providers match \"${escape_html(ocFilterQuery)}\"</div>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\tconst each_array_4 = ensure_array_like(PROVIDER_GROUPS);\n\t\t\t\tfor (let $$index_5 = 0, $$length = each_array_4.length; $$index_5 < $$length; $$index_5++) {\n\t\t\t\t\tlet group = each_array_4[$$index_5];\n\t\t\t\t\tconst members = PROVIDERS.filter((p) => p.group === group.id).sort((a, b) => a.order - b.order);\n\t\t\t\t\tif (members.length > 0) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"provider-group\"><div class=\"provider-group-header\"><h3 class=\"provider-group-label\">${escape_html(group.label)}</h3> <span class=\"provider-group-desc\">${escape_html(group.desc)}</span></div> <div class=\"provider-group-cards\"><!--[-->`);\n\t\t\t\t\t\tconst each_array_5 = ensure_array_like(members);\n\t\t\t\t\t\tfor (let $$index_4 = 0, $$length = each_array_5.length; $$index_4 < $$length; $$index_4++) {\n\t\t\t\t\t\t\tlet p = each_array_5[$$index_4];\n\t\t\t\t\t\t\tconst st = providerState[p.id] ?? {\n\t\t\t\t\t\t\t\tselected: false,\n\t\t\t\t\t\t\t\tverified: false,\n\t\t\t\t\t\t\t\tverifying: false,\n\t\t\t\t\t\t\t\terror: false,\n\t\t\t\t\t\t\t\tapiKey: \"\",\n\t\t\t\t\t\t\t\tbaseUrl: \"\",\n\t\t\t\t\t\t\t\tmodels: [],\n\t\t\t\t\t\t\t\tollamaMode: null\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tconst isExpanded = expandedProvider === p.id && st.selected;\n\t\t\t\t\t\t\tconst badgeCls = p.kind === \"cloud\" ? \"badge-cloud\" : p.kind === \"local\" ? \"badge-local\" : \"badge-hybrid\";\n\t\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`pcard ${st.selected ? \"selected\" : \"\"} ${st.verified ? \"verified\" : \"\"} ${isExpanded ? \"wide\" : \"\"}`)}${attr(\"data-provider\", p.id)}><div class=\"pcard-header\" role=\"button\" tabindex=\"0\"${attr(\"data-toggle-provider\", p.id)}><div class=\"pcard-icon\">${escape_html(p.icon)}</div> <div class=\"pcard-info\"><div class=\"pcard-name\">${escape_html(p.name)} <span${attr_class(`badge ${badgeCls}`, \"svelte-1iuc968\")}>${escape_html(p.kind)}</span> `);\n\t\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-ok\">✓</span>`);\n\t\t\t\t\t\t\t} else if (st.verifying) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-wait\">⟳</span>`);\n\t\t\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<span class=\"vs vs-err\">✗</span>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div> <div class=\"pcard-desc\">${escape_html(p.desc)}</div></div> <div class=\"pcard-check\" aria-hidden=\"true\">${escape_html(st.selected ? \"✓\" : \"\")}</div></div> `);\n\t\t\t\t\t\t\tif (isExpanded) {\n\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\t\t\t\t\t\tif (p.id === \"ollama\") {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\tif (!st.ollamaMode) {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"ollama-mode-prompt\"><p>Is Ollama already running on this machine?</p> <div class=\"ollama-mode-buttons\"><button class=\"ollama-mode-btn ollama-mode-btn-detect\">Yes, detect it</button> <button class=\"ollama-mode-btn ollama-mode-btn-stack\">No, add to stack</button></div></div>`);\n\t\t\t\t\t\t\t\t\t} else if (st.ollamaMode === \"running\") {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", p.baseUrl)}${attr(\"value\", st.baseUrl || p.baseUrl)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t\tif (st.verified) {\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Ollama will be added to your Docker stack with default models.</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"ollama-mode-prompt\"><p>Ollama runs as a container in your stack with recommended models pre-configured.</p> <button class=\"auth-btn auth-btn-detect\" style=\"margin-top:4px\">Enable Ollama</button></div>`);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t\t\t\t} else if (p.needsUrl) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\" placeholder=\"https://your-server.example/v1\"${attr(\"value\", st.baseUrl || \"\")}/></div> `);\n\t\t\t\t\t\t\t\t\tif (p.optionalKey) {\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\" style=\"margin-top:6px\"><input type=\"password\"${attr(\"placeholder\", p.placeholder || \"API key (optional)\")}${attr(\"value\", st.apiKey)}/></div>`);\n\t\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> <div class=\"auth-row\" style=\"margin-top:6px\"><button${attr_class(`auth-btn ${st.verified ? \"auth-btn-verified\" : \"auth-btn-verify\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : st.verified ? \"Connected ✓\" : \"Connect\")}</button></div>`);\n\t\t\t\t\t\t\t\t} else if (p.needsKey) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"password\"${attr(\"placeholder\", p.placeholder || \"API key\")}${attr(\"value\", st.apiKey)}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-verified\" : \"auth-btn-verify\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Checking...\" : st.verified ? \"Verified ✓\" : \"Verify\")}</button></div>`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><input type=\"url\"${attr(\"placeholder\", p.baseUrl || \"http://localhost:8080\")}${attr(\"value\", st.baseUrl || p.baseUrl || \"\")}/> <button${attr_class(`auth-btn ${st.verified ? \"auth-btn-detected\" : \"auth-btn-detect\"}`)}${attr(\"disabled\", st.verifying, true)}>${escape_html(st.verifying ? \"Detecting...\" : st.verified ? \"Connected ✓\" : \"Detect\")}</button></div>`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\t\t\t\tif (st.verified && p.id !== \"ollama\") {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-ok\"><span>Credentials verified</span> <button class=\"auth-disconnect\" type=\"button\">Disconnect</button></div>`);\n\t\t\t\t\t\t\t\t} else if (st.error) {\n\t\t\t\t\t\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t\t\t\t\t\t$$renderer.push(`<div class=\"auth-feedback auth-feedback-err\">${escape_html(friendlyProviderError(st.errorMessage, p.name) || \"Verification failed — check your \" + (p.needsKey ? \"credentials\" : \"endpoint\"))}</div>`);\n\t\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (verifiedCount === 0 && (!hostProviderCount || importMode() === \"manual\")) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<label class=\"allow-empty-row svelte-1iuc968\"><input type=\"checkbox\" id=\"allow-empty-install\"${attr(\"checked\", allowEmptyInstall, true)} class=\"svelte-1iuc968\"/> <span>Install without an AI provider (assistant won't be able to chat until I add one from the dashboard)</span></label>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\" id=\"step1-actions\"><button class=\"btn btn-secondary\" id=\"btn-step1-back\">Back</button> `);\n\t\tif (importMode() === \"import\" && hostProviderCount > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<span class=\"nav-info\">Import ${escape_html(hostProviderCount)} provider${escape_html(hostProviderCount !== 1 ? \"s\" : \"\")} from host</span> <button class=\"btn btn-primary\" id=\"btn-step1-next\">Continue</button>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<span class=\"nav-info\" id=\"provider-count-info\">`);\n\t\t\tif (verifiedCount > 0) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<b>${escape_html(verifiedCount)}</b> provider${escape_html(verifiedCount > 1 ? \"s\" : \"\")} ready`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`Connect a provider to continue`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></span> <button class=\"btn btn-primary\" id=\"btn-step1-next\"${attr(\"disabled\", verifiedCount === 0 && !allowEmptyInstall, true)}>${escape_html(verifiedCount > 0 ? \"Choose Models\" : \"Skip for now\")}</button>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/ModelsStep.svelte\nfunction ModelsStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { verifiedProviders, providerState, modelSelection, errorMessage, onback, onnext, onselect, onselectnone } = $$props;\n\t\tconst roles = [\n\t\t\t{\n\t\t\t\tid: \"llm\",\n\t\t\t\tlabel: \"Chat Model\",\n\t\t\t\ttag: \"required\",\n\t\t\t\tdesc: \"Conversations, reasoning, and code\"\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"embedding\",\n\t\t\t\tlabel: \"Memory Model\",\n\t\t\t\ttag: \"optional\",\n\t\t\t\tdesc: \"Helps the assistant remember past conversations. Optional.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"small\",\n\t\t\t\tlabel: \"Small Model\",\n\t\t\t\ttag: \"optional\",\n\t\t\t\tdesc: \"Lightweight tasks like summarization\"\n\t\t\t}\n\t\t];\n\t\tlet filterQueries = {};\n\t\tlet collapsedRoles = /* @__PURE__ */ new Set();\n\t\tfunction getOptionsForRole(role) {\n\t\t\tconst options = [];\n\t\t\tfor (const p of verifiedProviders) {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\tconst defaultModel = role.id === \"embedding\" ? p.embModel : p.llmModel;\n\t\t\t\tconst models = st.models.length > 0 ? st.models : [];\n\t\t\t\tif (defaultModel && models.includes(defaultModel)) options.push({\n\t\t\t\t\tid: defaultModel,\n\t\t\t\t\tconnId: p.id,\n\t\t\t\t\tproviderName: p.name,\n\t\t\t\t\tbaseUrl: st.baseUrl || p.baseUrl,\n\t\t\t\t\tisDefault: true,\n\t\t\t\t\tdims: role.id === \"embedding\" ? KNOWN_EMB_DIMS[defaultModel] ?? KNOWN_EMB_DIMS[defaultModel.replace(/:.*$/, \"\")] ?? p.embDims ?? 0 : 0\n\t\t\t\t});\n\t\t\t\tfor (const m of models) {\n\t\t\t\t\tif (m === defaultModel) continue;\n\t\t\t\t\tconst dims = role.id === \"embedding\" ? KNOWN_EMB_DIMS[m] ?? KNOWN_EMB_DIMS[m.replace(/:.*$/, \"\")] ?? 0 : 0;\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tid: m,\n\t\t\t\t\t\tconnId: p.id,\n\t\t\t\t\t\tproviderName: p.name,\n\t\t\t\t\t\tbaseUrl: st.baseUrl || p.baseUrl,\n\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\tdims\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (role.id === \"embedding\") {\n\t\t\t\tconst embOptions = options.filter((o) => o.isDefault || o.dims > 0);\n\t\t\t\tif (embOptions.length > 0) return embOptions;\n\t\t\t}\n\t\t\tif (role.id === \"small\" && options.length === 0) {\n\t\t\t\tconst llmProvider = verifiedProviders[0];\n\t\t\t\tif (llmProvider) for (const m of providerState[llmProvider.id].models) options.push({\n\t\t\t\t\tid: m,\n\t\t\t\t\tconnId: llmProvider.id,\n\t\t\t\t\tproviderName: llmProvider.name,\n\t\t\t\t\tbaseUrl: providerState[llmProvider.id].baseUrl || llmProvider.baseUrl,\n\t\t\t\t\tisDefault: false,\n\t\t\t\t\tdims: 0\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn options;\n\t\t}\n\t\tfunction filteredOptions(role, options) {\n\t\t\tconst query = (filterQueries[role.id] ?? \"\").toLowerCase().trim();\n\t\t\tif (!query) return options;\n\t\t\treturn options.filter((o) => o.id.toLowerCase().includes(query) || o.providerName.toLowerCase().includes(query));\n\t\t}\n\t\t$$renderer.push(`<h2>Choose Your Models</h2> <p class=\"step-description\">Pre-selected from your providers. Adjust if needed.</p> `);\n\t\tif (verifiedProviders.length === 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" style=\"margin-bottom:16px\">No providers configured. You can skip to complete setup and add providers from the admin panel later.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"model-groups\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(roles);\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet role = each_array[$$index_1];\n\t\t\tconst options = getOptionsForRole(role);\n\t\t\tif (options.length > 0 || role.id === \"small\") {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tconst hasOverflow = options.length > 6;\n\t\t\t\tconst query = filterQueries[role.id] ?? \"\";\n\t\t\t\tconst visible = filteredOptions(role, options);\n\t\t\t\t$$renderer.push(`<div class=\"model-group\"><div class=\"model-group-header\" role=\"button\" tabindex=\"0\" style=\"cursor:pointer;user-select:none\"><span class=\"model-group-title\">${escape_html(role.label)}</span> <span${attr_class(`model-group-tag ${role.tag === \"required\" ? \"model-group-tag-required\" : \"model-group-tag-optional\"}`)}>${escape_html(role.tag)}</span> `);\n\t\t\t\tif (collapsedRoles.has(role.id)) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\tconst sel = modelSelection[role.id];\n\t\t\t\t\t$$renderer.push(`<span style=\"flex:1;font-size:var(--text-xs);color:var(--color-text-secondary);margin-left:8px\">${escape_html(sel?.model ?? \"(none)\")}</span> <span style=\"font-size:var(--text-xs);color:var(--color-text-secondary)\">▶</span>`);\n\t\t\t\t} else {\n\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<span style=\"margin-left:auto;font-size:var(--text-xs);color:var(--color-text-secondary)\">▼</span>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div> `);\n\t\t\t\tif (!collapsedRoles.has(role.id)) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<div class=\"model-group-desc\">${escape_html(role.desc)}</div> `);\n\t\t\t\t\tif (role.id === \"small\") {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\tconst noneOn = !modelSelection.small?.model;\n\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`model-opt ${noneOn ? \"on\" : \"\"}`)} role=\"button\" tabindex=\"0\"><div class=\"model-opt-dot\"><div class=\"model-opt-dot-inner\"></div></div> <div style=\"flex:1\"><div class=\"model-opt-name\">(same as chat model)</div> <div class=\"model-opt-meta\">No separate small model</div></div> <span class=\"model-opt-badge model-opt-badge-auto\">Default</span></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\t\t\tif (options.length > 3) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<div class=\"model-filter-row\"><input type=\"text\" class=\"model-filter-input\"${attr(\"placeholder\", `Search ${stringify(options.length)} models…`)}${attr(\"value\", query)} autocomplete=\"off\"/></div>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--> <!--[-->`);\n\t\t\t\t\tconst each_array_1 = ensure_array_like(query ? visible : options);\n\t\t\t\t\tfor (let idx = 0, $$length = each_array_1.length; idx < $$length; idx++) {\n\t\t\t\t\t\tlet opt = each_array_1[idx];\n\t\t\t\t\t\tconst firstDefaultIdx = options.findIndex((o) => o.isDefault);\n\t\t\t\t\t\tconst sel = modelSelection[role.id];\n\t\t\t\t\t\tconst isOn = !!sel && sel.model === opt.id && sel.connId === opt.connId;\n\t\t\t\t\t\tconst isHidden = !query && hasOverflow && idx >= 6 && !isOn;\n\t\t\t\t\t\tconst meta = \"via \" + opt.providerName + (opt.dims > 0 ? \" · \" + opt.dims + \"d\" : \"\");\n\t\t\t\t\t\t$$renderer.push(`<div${attr_class(`model-opt ${isOn ? \"on\" : \"\"} ${isHidden ? \"model-opt-filtered\" : \"\"}`)} role=\"button\" tabindex=\"0\"${attr(\"data-model-select\", `${stringify(role.id)}:${stringify(opt.connId)}:${stringify(opt.id)}:${stringify(opt.dims)}`)}${attr(\"data-model-name\", opt.id.toLowerCase())}><div class=\"model-opt-dot\"><div class=\"model-opt-dot-inner\"></div></div> <div style=\"flex:1;min-width:0\"><div class=\"model-opt-name\">${escape_html(opt.id)}</div> <div class=\"model-opt-meta\">${escape_html(meta)}</div></div> `);\n\t\t\t\t\t\tif (idx === firstDefaultIdx && opt.isDefault) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<span class=\"model-opt-badge model-opt-badge-top\">Top Pick</span>`);\n\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <input type=\"hidden\" id=\"llm-connection\"${attr(\"value\", modelSelection.llm?.connId ?? \"\")}/> <input type=\"hidden\" id=\"llm-model\"${attr(\"value\", modelSelection.llm?.model ?? \"\")}/> <input type=\"hidden\" id=\"llm-small-model\"${attr(\"value\", modelSelection.small?.model ?? \"\")}/> <input type=\"hidden\" id=\"emb-connection\"${attr(\"value\", modelSelection.embedding?.connId ?? \"\")}/> <input type=\"hidden\" id=\"emb-model\"${attr(\"value\", modelSelection.embedding?.model ?? \"\")}/> <input type=\"hidden\" id=\"emb-dims\"${attr(\"value\", String(modelSelection.embedding?.dims ?? 1536))}/> `);\n\t\tif (errorMessage) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" id=\"step2-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step2-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step2-next\">${escape_html(verifiedProviders.length === 0 ? \"Skip for now\" : \"Voice Setup\")}</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/VoiceStep.svelte\nfunction VoiceStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { tts, stt, hasOpenAI, unknownTts = false, unknownStt = false, profiles = [], selectedVoiceProfile = \"\", onback, onnext, onchangetts, onchangestt, onprofilechange } = $$props;\n\t\tlet configureOpen = false;\n\t\tconst ttsLabel = derived(() => TTS_OPTIONS.find((o) => o.id === tts.engine)?.name ?? \"Browser Built-in\");\n\t\tconst sttLabel = derived(() => STT_OPTIONS.find((o) => o.id === stt.engine)?.name ?? \"Browser Built-in\");\n\t\tconst usesBundledVoice = derived(() => tts.engine === \"openpalm-voice\" || stt.engine === \"openpalm-voice\");\n\t\tconst selectedProfileLabel = derived(() => {\n\t\t\tif (!selectedVoiceProfile) return \"\";\n\t\t\tconst profile = profiles.find((p) => p.id === selectedVoiceProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedVoiceProfile;\n\t\t});\n\t\t$$renderer.push(`<h2>Voice Capabilities</h2> <p class=\"step-description\">Browser voice is ready out of the box — no setup needed.</p> `);\n\t\tif (unknownTts || unknownStt) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-unknown svelte-jxtfqg\" role=\"alert\">Your previous voice settings couldn't be loaded. Please pick an engine.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (usesBundledVoice()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-download-notice svelte-jxtfqg\" role=\"note\"><strong class=\"svelte-jxtfqg\">First install will download the OpenPalm Voice image.</strong> <ul class=\"svelte-jxtfqg\"><li>CPU build: ~2.4 GB (5–15 min on a typical home connection)</li> <li>CUDA build: ~7.6 GB (15–45 min — chosen later from the admin tab)</li></ul> The wizard's final Install step will show a progress indicator and\n wait for the download to finish before completing.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"voice-summary\" class=\"voice-summary svelte-jxtfqg\"><div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Text-to-Speech</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(ttsLabel())}</span></div> <div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Speech-to-Text</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(sttLabel())}</span></div> `);\n\t\tif (usesBundledVoice() && selectedProfileLabel()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-summary-row svelte-jxtfqg\"><span class=\"voice-summary-label svelte-jxtfqg\">Voice Container</span> <span class=\"voice-summary-value svelte-jxtfqg\">${escape_html(selectedProfileLabel())}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> `);\n\t\tif (usesBundledVoice()) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"voice-profile-inline svelte-jxtfqg\"><div class=\"voice-profile-inline-title svelte-jxtfqg\">Voice container profile</div> `);\n\t\t\tif (profiles.length > 0 && onprofilechange) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\t\tprofiles,\n\t\t\t\t\tselectedProfile: selectedVoiceProfile,\n\t\t\t\t\tonchange: onprofilechange,\n\t\t\t\t\tshowDescription: false\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<p class=\"voice-profile-inline-loading svelte-jxtfqg\">Checking available hardware profiles…</p>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <details${attr(\"open\", configureOpen, true)} id=\"voice-configure-details\" class=\"svelte-jxtfqg\"><summary class=\"voice-configure-summary svelte-jxtfqg\" id=\"voice-configure-toggle\">Configure voice…</summary> <div id=\"voice-groups\" style=\"margin-top:12px\">`);\n\t\tif (hasOpenAI) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<p class=\"voice-hint svelte-jxtfqg\">OpenAI is available. You can use OpenAI TTS/STT or keep browser voice.</p>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<p class=\"voice-hint svelte-jxtfqg\">Kokoro and Whisper give higher quality. Browser voice works without extra setup.</p>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--> <div class=\"model-group\"><div class=\"model-group-header\"><span class=\"model-group-title\">Text-to-Speech</span> <span class=\"model-group-tag model-group-tag-optional\">Optional</span></div> <div class=\"model-group-desc\">How your assistant speaks</div> `);\n\t\tVoiceEngineSelector($$renderer, {\n\t\t\tkind: \"tts\",\n\t\t\tvalue: tts,\n\t\t\tonchange: onchangetts\n\t\t});\n\t\t$$renderer.push(`<!----></div> <div class=\"model-group\"><div class=\"model-group-header\"><span class=\"model-group-title\">Speech-to-Text</span> <span class=\"model-group-tag model-group-tag-optional\">Optional</span></div> <div class=\"model-group-desc\">How your assistant hears you</div> `);\n\t\tVoiceEngineSelector($$renderer, {\n\t\t\tkind: \"stt\",\n\t\t\tvalue: stt,\n\t\t\tonchange: onchangestt\n\t\t});\n\t\t$$renderer.push(`<!----></div></div></details> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step3-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step3-next\">Continue</button></div>`);\n\t});\n}\n//#endregion\n//#region src/lib/wizard/helpers.ts\nfunction isChannelEnabled(channelSelection, chId, locked) {\n\tif (locked) return true;\n\tconst sel = channelSelection[chId];\n\tif (typeof sel === \"object\" && sel !== null) return sel.enabled;\n\treturn !!sel;\n}\nfunction getCredValue(channelSelection, chId, key) {\n\tconst sel = channelSelection[chId];\n\tif (typeof sel === \"object\" && sel !== null) return String(sel[key] ?? \"\");\n\treturn \"\";\n}\n//#endregion\n//#region src/routes/setup/steps/OptionsStep.svelte\nfunction OptionsStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { channelSelection, imageTag, hostAkmEnabled, hostAkmAvailable, enableVoice, voiceProfiles, selectedVoiceProfile, ollamaEnabled, ollamaProfiles, selectedOllamaProfile, errorMessage, onback, onnext, onchanneltoggle, oncredentialchange, onimagtagchange, onhostakmchange, onenablevoicechange, onvoiceprofilechange, onollamachange, onollamaprofilechange } = $$props;\n\t\tfunction isChannelEnabled$2(chId, locked) {\n\t\t\treturn isChannelEnabled(channelSelection, chId, locked);\n\t\t}\n\t\tfunction getCredValue$2(chId, key) {\n\t\t\treturn getCredValue(channelSelection, chId, key);\n\t\t}\n\t\t$$renderer.push(`<h2>Options</h2> <p class=\"step-description\">Configure channels and deployment options.</p> <div class=\"options-section\"><h3 class=\"options-section-title\">Channels</h3> <p class=\"options-section-desc\">Additional ways to reach your assistant.</p> <div class=\"toggle-grid\" id=\"channels-grid\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(CHANNELS);\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet ch = each_array[$$index_1];\n\t\t\tconst isOn = isChannelEnabled$2(ch.id, ch.locked);\n\t\t\t$$renderer.push(`<div${attr_class(`toggle-card ${isOn ? \"on\" : \"\"} ${ch.locked ? \"locked\" : \"\"} ${ch.credentials && isOn ? \"wide\" : \"\"}`)}${attr(\"data-channel\", ch.id)}><div class=\"toggle-card-header\" role=\"button\"${attr(\"tabindex\", ch.locked ? -1 : 0)}><div class=\"toggle-card-icon\">${escape_html(ch.icon)}</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">${escape_html(ch.name)} `);\n\t\t\tif (ch.locked) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"badge badge-local\">Always on</span>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div> <div class=\"toggle-card-desc\">${escape_html(ch.desc)}</div></div> <div class=\"toggle-card-switch\">`);\n\t\t\tif (ch.locked) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"toggle-track on locked\"><div class=\"toggle-thumb\"></div></div>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<div${attr_class(`toggle-track ${isOn ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\t\tif (ch.credentials && isOn) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"pcard-auth\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(ch.credentials);\n\t\t\t\tfor (let $$index = 0, $$length = each_array_1.length; $$index < $$length; $$index++) {\n\t\t\t\t\tlet cred = each_array_1[$$index];\n\t\t\t\t\tconst inputType = cred.secret === false ? \"text\" : \"password\";\n\t\t\t\t\t$$renderer.push(`<div class=\"auth-row\"><label class=\"channel-cred-label\"${attr(\"for\", `cred-${stringify(ch.id)}-${stringify(cred.key)}`)}>${escape_html(cred.label)} `);\n\t\t\t\t\tif (cred.required) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"channel-cred-required\">*</span>`);\n\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t$$renderer.push(`<!--]--></label> <input${attr(\"id\", `cred-${stringify(ch.id)}-${stringify(cred.key)}`)}${attr(\"type\", inputType)}${attr(\"placeholder\", cred.placeholder ?? \"\")}${attr(\"value\", getCredValue$2(ch.id, cred.key))}/></div>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></div> <div class=\"options-section\"><h3 class=\"options-section-title\">Add-ons</h3> <p class=\"options-section-desc\">Optional features to extend your assistant.</p> <div class=\"toggle-grid\" id=\"addons-grid\"><div${attr_class(`toggle-card ${enableVoice ? \"on\" : \"\"} ${enableVoice && voiceProfiles.length > 0 ? \"wide\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🎙️</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Voice</div> <div class=\"toggle-card-desc\">Bundled text-to-speech and speech-to-text. Requires a one-time local model download.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${enableVoice ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div> `);\n\t\tif (enableVoice && voiceProfiles.length > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\tprofiles: voiceProfiles,\n\t\t\t\tselectedProfile: selectedVoiceProfile,\n\t\t\t\tonchange: onvoiceprofilechange,\n\t\t\t\tshowDescription: false\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div${attr_class(`toggle-card ${ollamaEnabled ? \"on\" : \"\"} ${ollamaEnabled && ollamaProfiles.length > 0 ? \"wide\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🦙</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Ollama</div> <div class=\"toggle-card-desc\">Run local AI models inside the stack. Downloads and serves models via Docker.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${ollamaEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div> `);\n\t\tif (ollamaEnabled && ollamaProfiles.length > 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"pcard-auth\">`);\n\t\t\tVoiceProfileSelector($$renderer, {\n\t\t\t\tprofiles: ollamaProfiles,\n\t\t\t\tselectedProfile: selectedOllamaProfile,\n\t\t\t\tonchange: onollamaprofilechange,\n\t\t\t\tshowDescription: false\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div></div> <details id=\"options-advanced-details\" class=\"svelte-1q1mmx4\"><summary class=\"options-advanced-summary svelte-1q1mmx4\" id=\"options-advanced-toggle\">Advanced settings</summary> <div class=\"options-section\"><h3 class=\"options-section-title\">Container Image</h3> <p class=\"options-section-desc\">Tag or version of the OpenPalm images to deploy.</p> <div class=\"field-group\"><label for=\"image-tag\">Image tag</label> <div class=\"field-hint svelte-1q1mmx4\">Advanced — leave blank to use the default.</div> <input id=\"image-tag\" type=\"text\" placeholder=\"dev\"${attr(\"value\", imageTag)}/></div></div> `);\n\t\tif (hostAkmAvailable) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"options-section\"><h3 class=\"options-section-title\">Share knowledge with my host AKM</h3> <p class=\"options-section-desc\">Adds a source entry to your personal <code>~/.config/akm/config.json</code> and mounts <code>~/akm</code> into the assistant as a secondary source. Your files' ownership is not changed and your primary stash is unchanged — your <code>~/akm</code> data and cache stay yours.</p> <div class=\"toggle-grid\"><div${attr_class(`toggle-card ${hostAkmEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-card-header\" role=\"button\" tabindex=\"0\"><div class=\"toggle-card-icon\">🧠</div> <div class=\"toggle-card-info\"><div class=\"toggle-card-name\">Share knowledge with my host AKM (read + contribute)</div> <div class=\"toggle-card-desc\">The assistant reads your personal knowledge and can contribute back. Each side keeps its own primary stash, database, and cache — only the knowledge files are shared.</div></div> <div class=\"toggle-card-switch\"><div${attr_class(`toggle-track ${hostAkmEnabled ? \"on\" : \"\"}`)}><div class=\"toggle-thumb\"></div></div></div></div></div></div></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></details> `);\n\t\tif (errorMessage) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"field-error\" role=\"alert\">${escape_html(errorMessage)}</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\"><button class=\"btn btn-secondary\" id=\"btn-step4-back\">Back</button> <button class=\"btn btn-primary\" id=\"btn-step4-next\">Review</button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/ReviewStep.svelte\nfunction ReviewStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { uiLoginPassword, verifiedProviders, modelSelection, activeTts, activeStt, voiceProfileLabel = \"\", ollamaProfileLabel = \"\", channelSelection, ollamaEnabled, payload, installError, installing, isRerun = false, onback, oninstall, ongostepedit } = $$props;\n\t\tfunction maskSecret(value) {\n\t\t\tif (!value || value.length < 8) return \"(not set)\";\n\t\t\treturn value.slice(0, 4) + \"...\" + value.slice(-4);\n\t\t}\n\t\tfunction isChannelEnabled$1(chId, locked) {\n\t\t\treturn isChannelEnabled(channelSelection, chId, locked);\n\t\t}\n\t\tfunction getCredValue$1(chId, key) {\n\t\t\treturn getCredValue(channelSelection, chId, key);\n\t\t}\n\t\tconst ttsOpt = derived(() => TTS_OPTIONS.find((o) => o.id === activeTts));\n\t\tconst sttOpt = derived(() => STT_OPTIONS.find((o) => o.id === activeStt));\n\t\tconst activeChannels = derived(() => CHANNELS.filter((ch) => isChannelEnabled$1(ch.id, ch.locked)));\n\t\tfunction findProvider(connId) {\n\t\t\treturn PROVIDERS.find((p) => p.id === connId);\n\t\t}\n\t\t$$renderer.push(`<h2>Review &amp; Install</h2> <p class=\"step-description\">Confirm your settings, then install.</p> `);\n\t\tif (verifiedProviders.length === 0) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-warning svelte-1q74f52\" role=\"alert\">⚠ No AI provider connected — your assistant won't be able to chat until you add one from the dashboard.</div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div id=\"review-summary\"><div class=\"review-card\"><div class=\"review-card-title\"><span>Account</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (!isRerun) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row review-row--alert svelte-1q74f52\"><span class=\"review-row-label\">UI Login Password</span> <span class=\"review-row-value\">`);\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<span class=\"token-save-box svelte-1q74f52\">${escape_html(uiLoginPassword.substring(0, 2))}*********</span>`);\n\t\t\t$$renderer.push(`<!--]--></span></div> <div class=\"review-row review-row--alert svelte-1q74f52\"><span class=\"review-row-label\"><span class=\"token-save-hint svelte-1q74f52\">You'll need this to sign in. Also saved in <code class=\"svelte-1q74f52\">stack.env</code>.</span></span> <span class=\"review-row-value\"><button type=\"button\" class=\"btn btn-secondary btn-sm\">${escape_html(\"Copy password\")}</button></span></div>`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">UI Login Password</span> <span class=\"review-row-value\">${escape_html(maskSecret(uiLoginPassword))}</span></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Models</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (modelSelection.llm) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst llmProv = findProvider(modelSelection.llm.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Chat Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.llm.model)}${escape_html(llmProv ? \" (\" + llmProv.name + \")\" : \"\")}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (modelSelection.small?.model) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst smallProv = findProvider(modelSelection.small.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Small Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.small.model)}${escape_html(smallProv ? \" (\" + smallProv.name + \")\" : \"\")}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (modelSelection.embedding) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tconst embProv = findProvider(modelSelection.embedding.connId);\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Memory Model</span> <span class=\"review-row-value\">${escape_html(modelSelection.embedding.model)}${escape_html(embProv ? \" (\" + embProv.name + \")\" : \"\")}</span></div> <div class=\"review-row\" style=\"padding:4px 0\"><span class=\"review-row-label\">Embedding Dims</span> <span class=\"review-row-value\">${escape_html(modelSelection.embedding.dims ?? 1536)}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Channels</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <!--[-->`);\n\t\tconst each_array = ensure_array_like(activeChannels());\n\t\tfor (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {\n\t\t\tlet ch = each_array[$$index_1];\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">${escape_html(ch.icon)} ${escape_html(ch.name)}</span> <span class=\"review-row-value review-row-value-ok\">Enabled ✓</span></div> `);\n\t\t\tif (ch.credentials) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (typeof sel === \"object\" && sel !== null && sel.enabled) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<!--[-->`);\n\t\t\t\t\tconst each_array_1 = ensure_array_like(ch.credentials);\n\t\t\t\t\tfor (let $$index = 0, $$length = each_array_1.length; $$index < $$length; $$index++) {\n\t\t\t\t\t\tlet cred = each_array_1[$$index];\n\t\t\t\t\t\tconst val = getCredValue$1(ch.id, cred.key);\n\t\t\t\t\t\tif (val) {\n\t\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\" style=\"padding-left:24px\">${escape_html(cred.label)}</span> <span class=\"review-row-value\">${escape_html(maskSecret(val))}</span></div>`);\n\t\t\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]-->`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Voice</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <div class=\"review-row\"><span class=\"review-row-label\">Text-to-Speech</span> <span class=\"review-row-value\">${escape_html(ttsOpt() ? ttsOpt().name : \"Disabled\")}</span></div> <div class=\"review-row\"><span class=\"review-row-label\">Speech-to-Text</span> <span class=\"review-row-value\">${escape_html(sttOpt() ? sttOpt().name : \"Disabled\")}</span></div> `);\n\t\tif (voiceProfileLabel && (activeTts === \"openpalm-voice\" || activeStt === \"openpalm-voice\")) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Voice Container</span> <span class=\"review-row-value\">${escape_html(voiceProfileLabel)}</span></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Options</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> `);\n\t\tif (ollamaEnabled) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Ollama In-Stack</span> <span class=\"review-row-value\">Enabled</span></div> `);\n\t\t\tif (ollamaProfileLabel) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">Ollama Profile</span> <span class=\"review-row-value\">${escape_html(ollamaProfileLabel)}</span></div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]-->`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div> <div class=\"review-card\"><div class=\"review-card-title\"><span>Providers</span> <button class=\"review-edit-btn\" type=\"button\">Edit</button></div> <!--[-->`);\n\t\tconst each_array_2 = ensure_array_like(verifiedProviders);\n\t\tfor (let $$index_2 = 0, $$length = each_array_2.length; $$index_2 < $$length; $$index_2++) {\n\t\t\tlet p = each_array_2[$$index_2];\n\t\t\t$$renderer.push(`<div class=\"review-row\"><span class=\"review-row-label\">${escape_html(p.icon)} ${escape_html(p.name)}</span> <span class=\"review-row-value review-row-value-ok\">Connected ✓</span></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div></div> `);\n\t\tif (installError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tFriendlyError($$renderer, { error: friendlyError(installError, \"setup-complete\") });\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"step-actions\" id=\"review-actions\"><button type=\"button\" class=\"btn btn-info\">Save configuration</button> <button class=\"btn btn-secondary\">Back</button> <button class=\"btn btn-primary\" id=\"btn-install\"${attr(\"disabled\", installing, true)}>`);\n\t\tif (installing) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<span class=\"spinner\"></span> Installing...`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`Install`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></button></div>`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/steps/DeployStep.svelte\nfunction DeployStep($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet { deployData, deployDone, deployError, onback, onretry } = $$props;\n\t\tconst isElectron = typeof window !== \"undefined\" && !!window.openpalm;\n\t\tconst windowPort = typeof window !== \"undefined\" ? Number(window.location.port) || 3880 : 3880;\n\t\tconst adminPort = derived(() => deployData.ports?.admin ?? windowPort);\n\t\tconst assistantPort = derived(() => deployData.ports?.assistant ?? 3800);\n\t\tconst serviceLinks = derived(() => ({\n\t\t\tassistant: {\n\t\t\t\tport: assistantPort(),\n\t\t\t\tlabel: \"Assistant (OpenCode)\",\n\t\t\t\tpath: \"\"\n\t\t\t},\n\t\t\tadmin: {\n\t\t\t\tport: adminPort(),\n\t\t\t\tlabel: \"Admin Dashboard\",\n\t\t\t\tpath: \"\"\n\t\t\t}\n\t\t}));\n\t\tconst services = derived(() => deployData.deployStatus ?? []);\n\t\tconst total = derived(() => services().length);\n\t\tconst running = derived(() => services().filter((s) => s.status === \"running\").length);\n\t\tconst pct = derived(() => total() > 0 ? Math.round(running() / total() * 100) : 0);\n\t\tconst phase = derived(() => deployData.phase ?? \"writing-config\");\n\t\tconst voiceEnabled = derived(() => services().some((s) => /^voice(-cuda|-rocm)?$/.test(s.service ?? \"\")));\n\t\tconst deployTitle = derived(() => {\n\t\t\tif (deployDone) return \"Setup Complete\";\n\t\t\tif (deployError) return \"Deployment Issue\";\n\t\t\tswitch (phase()) {\n\t\t\t\tcase \"writing-config\": return \"Preparing Configuration…\";\n\t\t\t\tcase \"pulling-images\": return voiceEnabled() ? \"Downloading Images (incl. Voice ~2.4 GB)…\" : \"Downloading Images…\";\n\t\t\t\tcase \"starting\": return \"Starting Services…\";\n\t\t\t\tcase \"starting-voice\": return \"Starting Voice Addon…\";\n\t\t\t\tcase \"ready\": return \"Setup Complete\";\n\t\t\t}\n\t\t\treturn \"Deploying…\";\n\t\t});\n\t\tconst deploySubtitle = derived(() => {\n\t\t\tif (deployDone) return \"Your OpenPalm stack is up and running.\";\n\t\t\tif (deployError) return \"Setup could not finish starting the stack.\";\n\t\t\tswitch (phase()) {\n\t\t\t\tcase \"writing-config\": return \"Writing config files and validating settings.\";\n\t\t\t\tcase \"pulling-images\": return voiceEnabled() ? \"Downloading container images. The voice model (~2.4 GB) is the largest — on a typical home connection this step can take 10–30 minutes. The wizard will wait — keep this tab open.\" : \"Downloading container images — first install can take 3–8 minutes depending on connection.\";\n\t\t\t\tcase \"starting\": return `${running()} of ${total()} services running.`;\n\t\t\t\tcase \"starting-voice\": return \"Pulling the voice image (~2.4 GB) and warming up Kokoro + Whisper models. First launch can take 5–30 minutes on slow connections — the wizard will wait.\";\n\t\t\t\tcase \"ready\": return \"All services are up.\";\n\t\t\t}\n\t\t\treturn \"Writing configuration and starting services.\";\n\t\t});\n\t\tconst noStartMode = derived(() => deployDone && services().length === 0);\n\t\t$$renderer.push(`<div class=\"deploy-header\"><h2 id=\"deploy-title\">${escape_html(deployTitle())}</h2> <p class=\"step-description\" id=\"deploy-subtitle\">${escape_html(deploySubtitle())}</p></div> <div class=\"deploy-progress-summary\"><div class=\"deploy-progress-meta\"><span class=\"deploy-progress-label\">Progress</span> <span${attr_class(`deploy-progress-value ${deployError ? \"deploy-progress-value--error\" : \"\"}`)} id=\"deploy-progress-value\">`);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`Error`);\n\t\t} else if (deployDone) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`${escape_html(services().length > 0 ? \"100%\" : \"\")}`);\n\t\t} else {\n\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`${escape_html(pct())}%`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></span></div> <div class=\"deploy-progress-bar\"><div class=\"deploy-progress-fill\" id=\"deploy-progress-fill\"${attr_style(`width:${stringify(deployDone && services().length > 0 ? 100 : deployDone ? 0 : pct())}%`)}></div></div></div> <div class=\"deploy-services\" id=\"deploy-services\"><!--[-->`);\n\t\tconst each_array = ensure_array_like(services());\n\t\tfor (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {\n\t\t\tlet svc = each_array[$$index];\n\t\t\t$$renderer.push(`<div class=\"deploy-service-row\"><div class=\"deploy-service-indicator\">`);\n\t\t\tif (svc.status === \"running\") {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-check\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--color-success)\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg></span>`);\n\t\t\t} else if (svc.status === \"error\") {\n\t\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-warning\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#d97706\" stroke-width=\"2.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"></path><path d=\"M12 17h.01\"></path><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path></svg></span>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<span class=\"deploy-spinner\"><span class=\"spinner\"></span></span>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div> <div class=\"deploy-service-info\"><span class=\"deploy-service-name\">${escape_html(svc.service || svc.label || \"\")}</span> <span class=\"deploy-service-status\">${escape_html(svc.label || svc.status)}</span></div> <div class=\"deploy-service-bar\"><div${attr_class(`deploy-bar-fill ${svc.status === \"running\" ? \"complete\" : svc.status === \"ready\" ? \"ready\" : svc.status === \"error\" ? \"stopped\" : \"indeterminate\"}`)}></div></div></div>`);\n\t\t}\n\t\t$$renderer.push(`<!--]--></div> `);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div id=\"deploy-failure\">`);\n\t\t\tFriendlyError($$renderer, { error: friendlyError(deployError, \"deploy\") });\n\t\t\t$$renderer.push(`<!----></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (!deployDone && !deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<aside class=\"deploy-tips\" id=\"deploy-tips\"><div class=\"deploy-tips-header\"><span class=\"deploy-tips-kicker\">Tips</span> <h3>${escape_html(voiceEnabled() ? \"First install may take 10–30 minutes\" : \"First startup takes a few minutes\")}</h3></div> <ul>`);\n\t\t\tif (voiceEnabled()) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<li>The OpenPalm Voice image is ~2.4 GB — the largest piece by far. Download speed depends on your internet connection.</li> <li>The wizard waits as long as the download takes. Progress bars below show each service's state.</li>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<li>Container images are being downloaded for the first time.</li>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--> <li>The admin console will be available once all services are healthy.</li> `);\n\t\t\tif (isElectron) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<li>You can leave this window — we'll let you know when it's ready.</li>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<li><strong>Keep this tab open while installation runs.</strong></li>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></ul></aside>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (deployDone) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"done-state\" id=\"deploy-done\"><div class=\"done-icon\"><svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--color-success)\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"></path><polyline points=\"22 4 12 14.01 9 11.01\"></polyline></svg></div> <h2>Setup Complete</h2> `);\n\t\t\tif (noStartMode()) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<p class=\"done-subtitle\">Configuration saved. Run 'openpalm start' to start services.</p>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<p class=\"done-subtitle\">Your OpenPalm stack is up and running.</p> `);\n\t\t\t\tif (!isElectron) {\n\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t$$renderer.push(`<p class=\"done-close-hint svelte-1orw49v\">Setup is complete. You can safely close this tab now.</p>`);\n\t\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t\t$$renderer.push(`<!--]--> <ul class=\"service-list\" id=\"deploy-service-list\"><!--[-->`);\n\t\t\t\tconst each_array_1 = ensure_array_like(services());\n\t\t\t\tfor (let $$index_1 = 0, $$length = each_array_1.length; $$index_1 < $$length; $$index_1++) {\n\t\t\t\t\tlet svc = each_array_1[$$index_1];\n\t\t\t\t\tconst name = svc.service || svc.label || \"\";\n\t\t\t\t\tconst linkInfo = serviceLinks()[name];\n\t\t\t\t\t$$renderer.push(`<li>`);\n\t\t\t\t\tif (linkInfo) {\n\t\t\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t\t\tconst url = \"http://127.0.0.1:\" + linkInfo.port + linkInfo.path;\n\t\t\t\t\t\t$$renderer.push(`<span class=\"deploy-svc-name\">${escape_html(linkInfo.label)}</span> <a${attr(\"href\", url)} target=\"_blank\" rel=\"noopener\" class=\"deploy-svc-link\">${escape_html(url)}</a> <span class=\"deploy-svc-status\">✓ Running</span>`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\t\t\t$$renderer.push(`<span class=\"deploy-svc-name\">${escape_html(name)}</span> <span class=\"deploy-svc-status\">✓ Running</span>`);\n\t\t\t\t\t}\n\t\t\t\t\t$$renderer.push(`<!--]--></li>`);\n\t\t\t\t}\n\t\t\t\t$$renderer.push(`<!--]--></ul> <div class=\"done-links\"><a href=\"/chat\" class=\"btn btn-primary\">Open Chat</a> <a${attr(\"href\", `http://127.0.0.1:${stringify(assistantPort())}`)} target=\"_blank\" rel=\"noopener\" class=\"btn btn-secondary\">OpenCode UI</a> <a href=\"/\" class=\"btn btn-secondary\">Admin Dashboard</a></div>`);\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (deployError) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t$$renderer.push(`<div class=\"step-actions\" id=\"deploy-error-actions\"><button class=\"btn btn-secondary\" id=\"btn-deploy-back\">Back to Review</button> <button class=\"btn btn-primary\" id=\"btn-deploy-retry\">Retry</button></div>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]-->`);\n\t});\n}\n//#endregion\n//#region src/routes/setup/+page.svelte\nfunction _page($$renderer, $$props) {\n\t$$renderer.component(($$renderer) => {\n\t\tlet currentStep = 0;\n\t\tlet maxVisitedStep = 0;\n\t\tlet showDeploy = false;\n\t\tlet systemCheckPassed = false;\n\t\tlet uiLoginPassword = \"\";\n\t\tlet step0Error = \"\";\n\t\tlet detectionReady = false;\n\t\tlet autoModeImporting = false;\n\t\tlet enableVoice = false;\n\t\tlet gpuDetected = false;\n\t\tlet providerState = {};\n\t\tlet expandedProvider = null;\n\t\tlet detectedProviders = [];\n\t\tlet detecting = false;\n\t\tlet opencodeAvailable = false;\n\t\tlet opencodeProviders = [];\n\t\tlet opencodeAuth = {};\n\t\tlet ocFilterQuery = \"\";\n\t\tlet hostProviderCount = 0;\n\t\tlet hostStatusWarning = null;\n\t\tlet allowEmptyInstall = false;\n\t\tlet voiceEngineUnknownTts = false;\n\t\tlet voiceEngineUnknownStt = false;\n\t\t/** Generation counter per provider — discard stale verify results */\n\t\tconst verifyGeneration = {};\n\t\t/** AbortControllers for in-flight OAuth long-poll requests */\n\t\tconst oauthAbortControllers = {};\n\t\tlet modelSelection = {};\n\t\tlet step2Error = \"\";\n\t\tlet step2EmbDimWarning = \"\";\n\t\tlet voiceTts = { engine: \"\" };\n\t\tlet voiceStt = { engine: \"\" };\n\t\tlet voiceProfiles = [];\n\t\tlet selectedVoiceProfile = \"\";\n\t\tlet channelSelection = {\n\t\t\tdiscord: {\n\t\t\t\tenabled: false,\n\t\t\t\tbotToken: \"\",\n\t\t\t\tapplicationId: \"\"\n\t\t\t},\n\t\t\tslack: {\n\t\t\t\tenabled: false,\n\t\t\t\tslackBotToken: \"\",\n\t\t\t\tslackAppToken: \"\"\n\t\t\t}\n\t\t};\n\t\tlet ollamaEnabled = false;\n\t\tlet ollamaProfiles = [];\n\t\tlet selectedOllamaProfile = \"\";\n\t\tlet imageTag = \"\";\n\t\tlet hostAkmEnabled = false;\n\t\tlet hostAkmAvailable = false;\n\t\tlet step4Error = \"\";\n\t\tlet installError = \"\";\n\t\tlet installing = false;\n\t\tlet deployData = {};\n\t\tlet deployDone = false;\n\t\tlet deployError = null;\n\t\tlet deployTimer = null;\n\t\tlet deployPollErrors = 0;\n\t\tconst verifiedCount = derived(() => {\n\t\t\treturn PROVIDERS.map((p) => p.id).filter((id) => providerState[id]?.verified).length;\n\t\t});\n\t\tconst verifiedProviders = derived(() => {\n\t\t\treturn PROVIDERS.filter((p) => providerState[p.id]?.verified);\n\t\t});\n\t\tconst hasOllamaVerified = derived(() => PROVIDERS.some((p) => p.id === \"ollama\" && providerState[p.id]?.verified));\n\t\tconst hasOpenAI = derived(() => PROVIDERS.some((p) => p.id === \"openai\" && providerState[p.id]?.verified));\n\t\tconst voiceDefaults = derived(() => hasOpenAI() ? {\n\t\t\ttts: \"openai-tts\",\n\t\t\tstt: \"openai-stt\"\n\t\t} : {\n\t\t\ttts: \"browser-tts\",\n\t\t\tstt: \"browser-stt\"\n\t\t});\n\t\tconst displayedVoiceTts = derived(() => {\n\t\t\tif (voiceTts.engine) return voiceTts;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: voiceDefaults().tts };\n\t\t});\n\t\tconst displayedVoiceStt = derived(() => {\n\t\t\tif (voiceStt.engine) return voiceStt;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: voiceDefaults().stt };\n\t\t});\n\t\tconst persistedVoiceTts = derived(() => {\n\t\t\tif (voiceTts.engine) return voiceTts;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: \"\" };\n\t\t});\n\t\tconst persistedVoiceStt = derived(() => {\n\t\t\tif (voiceStt.engine) return voiceStt;\n\t\t\tif (enableVoice) return { engine: \"openpalm-voice\" };\n\t\t\treturn { engine: \"\" };\n\t\t});\n\t\tconst selectedVoiceProfileLabel = derived(() => {\n\t\t\tif (!selectedVoiceProfile) return \"\";\n\t\t\tconst profile = voiceProfiles.find((p) => p.id === selectedVoiceProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedVoiceProfile;\n\t\t});\n\t\tconst selectedOllamaProfileLabel = derived(() => {\n\t\t\tif (!selectedOllamaProfile) return \"\";\n\t\t\tconst profile = ollamaProfiles.find((p) => p.id === selectedOllamaProfile);\n\t\t\treturn profile?.label ?? profile?.id ?? selectedOllamaProfile;\n\t\t});\n\t\tfunction addonProfileId(addon, variant) {\n\t\t\treturn `addon.${addon}.${variant}`;\n\t\t}\n\t\tconst payload = derived(() => {\n\t\t\tconst llm = modelSelection.llm;\n\t\t\tconst emb = modelSelection.embedding;\n\t\t\tconst small = modelSelection.small;\n\t\t\tconst capabilityProviderIds = {};\n\t\t\tif (llm) capabilityProviderIds[llm.connId] = true;\n\t\t\tif (emb) capabilityProviderIds[emb.connId] = true;\n\t\t\tif (small?.model) capabilityProviderIds[small.connId] = true;\n\t\t\tconst capabilities = verifiedProviders().filter((p) => capabilityProviderIds[p.id]).map((p) => {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\treturn {\n\t\t\t\t\tid: p.id,\n\t\t\t\t\tname: p.name,\n\t\t\t\t\tprovider: p.id,\n\t\t\t\t\tbaseUrl: st?.baseUrl ?? p.baseUrl,\n\t\t\t\t\tapiKey: st?.apiKey ?? \"\"\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst llmConnId = llm?.connId ?? \"\";\n\t\t\tconst embConnId = emb?.connId ?? \"\";\n\t\t\tconst llmCap = capabilities.find((c) => c.id === llmConnId);\n\t\t\tconst embCap = capabilities.find((c) => c.id === embConnId);\n\t\t\tconst llmProvider = llmCap?.provider ?? \"\";\n\t\t\tconst embProvider = embCap?.provider ?? \"\";\n\t\t\tconst addons = {};\n\t\t\tif (ollamaEnabled) addons.ollama = true;\n\t\t\tif (persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") addons.voice = true;\n\t\t\tconst channelCredentials = {};\n\t\t\tconst channelsConfig = buildChannelsConfig();\n\t\t\tfor (const chId of Object.keys(channelsConfig)) {\n\t\t\t\tconst chVal = channelsConfig[chId];\n\t\t\t\tif (chVal === true) addons[chId] = true;\n\t\t\t\telse if (typeof chVal === \"object\" && chVal !== null) {\n\t\t\t\t\taddons[chId] = true;\n\t\t\t\t\tconst creds = {};\n\t\t\t\t\tfor (const key of Object.keys(chVal)) if (key !== \"enabled\" && chVal[key]) creds[key] = String(chVal[key]);\n\t\t\t\t\tif (Object.keys(creds).length > 0) channelCredentials[chId] = creds;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst result = {\n\t\t\t\tversion: 2,\n\t\t\t\taddons,\n\t\t\t\tsecurity: { uiLoginPassword },\n\t\t\t\tconnections: capabilities\n\t\t\t};\n\t\t\tif (llmProvider && llm?.model) result.llm = {\n\t\t\t\tprovider: llmProvider,\n\t\t\t\tmodel: llm.model,\n\t\t\t\tbaseUrl: llmCap?.baseUrl ?? \"\"\n\t\t\t};\n\t\t\tif (embProvider && emb?.model) result.embedding = {\n\t\t\t\tprovider: embProvider,\n\t\t\t\tmodel: emb.model,\n\t\t\t\tdims: emb.dims ?? 1536,\n\t\t\t\tbaseUrl: embCap?.baseUrl ?? \"\"\n\t\t\t};\n\t\t\tconst voicePayload = (v) => {\n\t\t\t\tif (!v.engine || v.engine.startsWith(\"skip-\")) return void 0;\n\t\t\t\tconst out = {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tengine: v.engine\n\t\t\t\t};\n\t\t\t\tif (v.provider) out.provider = v.provider;\n\t\t\t\tif (v.baseURL) out.baseURL = v.baseURL;\n\t\t\t\tif (v.model) out.model = v.model;\n\t\t\t\tif (v.voice) out.voice = v.voice;\n\t\t\t\tif (v.language) out.language = v.language;\n\t\t\t\treturn out;\n\t\t\t};\n\t\t\tconst ttsCap = voicePayload(persistedVoiceTts());\n\t\t\tif (ttsCap) result.tts = ttsCap;\n\t\t\tconst sttCap = voicePayload(persistedVoiceStt());\n\t\t\tif (sttCap) result.stt = sttCap;\n\t\t\tif ((persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") && selectedVoiceProfile) result.voiceProfile = selectedVoiceProfile;\n\t\t\tif (ollamaEnabled && selectedOllamaProfile) result.ollamaProfile = selectedOllamaProfile;\n\t\t\tif (Object.keys(channelCredentials).length > 0) result.channelCredentials = channelCredentials;\n\t\t\tif (imageTag.trim()) result.imageTag = imageTag.trim();\n\t\t\tif (hostAkmEnabled) result.hostAkm = true;\n\t\t\treturn result;\n\t\t});\n\t\tfunction buildChannelsConfig() {\n\t\t\tconst result = {};\n\t\t\tfor (const ch of CHANNELS) {\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (ch.locked) result[ch.id] = true;\n\t\t\t\telse if (typeof sel === \"object\" && sel !== null) {\n\t\t\t\t\tif (sel.enabled) {\n\t\t\t\t\t\tconst entry = { enabled: true };\n\t\t\t\t\t\tif (ch.credentials) for (const cred of ch.credentials) {\n\t\t\t\t\t\t\tconst v = sel[cred.key];\n\t\t\t\t\t\t\tif (v) entry[cred.key] = v;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult[ch.id] = entry;\n\t\t\t\t\t}\n\t\t\t\t} else if (sel) result[ch.id] = true;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tfunction validateStep0() {\n\t\t\tif (uiLoginPassword.trim().length < 8) {\n\t\t\t\tstep0Error = \"UI login password must be at least 8 characters.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep0Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction enableRecommendedOllama() {\n\t\t\tollamaEnabled = true;\n\t\t\tconst st = providerState[\"ollama\"];\n\t\t\tif (st) {\n\t\t\t\tst.selected = true;\n\t\t\t\tst.verified = true;\n\t\t\t\tst.ollamaMode = \"instack\";\n\t\t\t\tst.baseUrl = \"http://ollama:11434\";\n\t\t\t\tif (st.models.length === 0) st.models = [\"nomic-embed-text\", \"qwen3:4b\"];\n\t\t\t}\n\t\t\tconst preferred = addonProfileId(\"ollama\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\tselectedOllamaProfile = (ollamaProfiles.find((p) => p.id === preferred && p.available !== false) ?? ollamaProfiles.find((p) => p.available !== false))?.id ?? preferred;\n\t\t}\n\t\tasync function handleUseDefaults() {\n\t\t\tif (verifiedProviders().length >= 1) {\n\t\t\t\tenableRecommendedOllama();\n\t\t\t\tautoSelectModels();\n\t\t\t\tgoToStep(5);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tenableRecommendedOllama();\n\t\t\tautoSelectModels();\n\t\t\tallowEmptyInstall = true;\n\t\t\tgoToStep(5);\n\t\t}\n\t\tfunction handleEnableVoiceChange(v) {\n\t\t\tenableVoice = v;\n\t\t\tif (v && !selectedVoiceProfile) {\n\t\t\t\tconst preferred = addonProfileId(\"voice\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\t\tconst match = voiceProfiles.find((p) => p.id === preferred && p.available !== false) ?? voiceProfiles.find((p) => p.available !== false);\n\t\t\t\tif (match) selectedVoiceProfile = match.id;\n\t\t\t}\n\t\t}\n\t\tfunction handleOptionsOllamaChange(v) {\n\t\t\tif (v) enableRecommendedOllama();\n\t\t\telse {\n\t\t\t\tollamaEnabled = false;\n\t\t\t\tconst st = providerState[\"ollama\"];\n\t\t\t\tif (st && st.ollamaMode !== \"running\") {\n\t\t\t\t\tst.selected = false;\n\t\t\t\t\tst.verified = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction validateStep2() {\n\t\t\tif (verifiedProviders().length === 0) {\n\t\t\t\tif (allowEmptyInstall) {\n\t\t\t\t\tstep2Error = \"\";\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tstep2Error = \"Connect at least one provider, or check \\\"Install without an AI provider\\\" on the previous step.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!modelSelection.llm?.model) {\n\t\t\t\tstep2Error = \"Select a chat model.\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep2Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction validateStep4() {\n\t\t\tconst errors = [];\n\t\t\tfor (const ch of CHANNELS) {\n\t\t\t\tif (!ch.credentials) continue;\n\t\t\t\tconst sel = channelSelection[ch.id];\n\t\t\t\tif (typeof sel !== \"object\" || sel === null) continue;\n\t\t\t\tif (!sel.enabled) continue;\n\t\t\t\tfor (const cred of ch.credentials) if (cred.required && !String(sel[cred.key] ?? \"\").trim()) errors.push(ch.name + \": \" + cred.label + \" is required.\");\n\t\t\t}\n\t\t\tif (errors.length > 0) {\n\t\t\t\tstep4Error = errors.join(\" \");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstep4Error = \"\";\n\t\t\treturn true;\n\t\t}\n\t\tfunction canNavigateTo(step) {\n\t\t\tif (step > maxVisitedStep) return false;\n\t\t\treturn true;\n\t\t}\n\t\tfunction goToStep(n) {\n\t\t\tif (n < 0 || n > 6) return;\n\t\t\tif (n > 0 && !systemCheckPassed) return;\n\t\t\tcurrentStep = n;\n\t\t\tif (n > maxVisitedStep) maxVisitedStep = n;\n\t\t\tshowDeploy = false;\n\t\t\tif (n === 3) autoSelectModels();\n\t\t\tif (n === 5 && hasOllamaVerified()) ollamaEnabled = providerState.ollama?.ollamaMode === \"instack\";\n\t\t}\n\t\tfunction autoSelectModels() {\n\t\t\tfor (const roleId of [\n\t\t\t\t\"llm\",\n\t\t\t\t\"embedding\",\n\t\t\t\t\"small\"\n\t\t\t]) {\n\t\t\t\tif (modelSelection[roleId]) continue;\n\t\t\t\tconst options = getModelOptionsForRole(roleId);\n\t\t\t\tif (options.length === 0) continue;\n\t\t\t\tconst defaultOpt = roleId === \"embedding\" && ollamaEnabled ? options.find((o) => o.connId === \"ollama\") ?? options.find((o) => o.isDefault) ?? options[0] : options.find((o) => o.isDefault) ?? options[0];\n\t\t\t\tmodelSelection[roleId] = {\n\t\t\t\t\tconnId: defaultOpt.connId,\n\t\t\t\t\tmodel: defaultOpt.id,\n\t\t\t\t\tdims: defaultOpt.dims\n\t\t\t\t};\n\t\t\t\tif (roleId === \"embedding\" && defaultOpt.dims <= 0) step2EmbDimWarning = \"Unknown embedding model dimensions — set manually in akm config after install.\";\n\t\t\t}\n\t\t}\n\t\tfunction getModelOptionsForRole(roleId) {\n\t\t\tconst options = [];\n\t\t\tfor (const p of verifiedProviders()) {\n\t\t\t\tconst st = providerState[p.id];\n\t\t\t\tconst defaultModel = roleId === \"embedding\" ? p.embModel : p.llmModel;\n\t\t\t\tconst models = st.models.length > 0 ? st.models : [];\n\t\t\t\tif (defaultModel && models.includes(defaultModel)) options.push({\n\t\t\t\t\tid: defaultModel,\n\t\t\t\t\tconnId: p.id,\n\t\t\t\t\tisDefault: true,\n\t\t\t\t\tdims: roleId === \"embedding\" ? KNOWN_EMB_DIMS[defaultModel] ?? KNOWN_EMB_DIMS[defaultModel.replace(/:.*$/, \"\")] ?? p.embDims ?? 0 : 0\n\t\t\t\t});\n\t\t\t\tfor (const m of models) {\n\t\t\t\t\tif (m === defaultModel) continue;\n\t\t\t\t\tconst dims = roleId === \"embedding\" ? KNOWN_EMB_DIMS[m] ?? KNOWN_EMB_DIMS[m.replace(/:.*$/, \"\")] ?? 0 : 0;\n\t\t\t\t\toptions.push({\n\t\t\t\t\t\tid: m,\n\t\t\t\t\t\tconnId: p.id,\n\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\tdims\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (roleId === \"embedding\" && ollamaEnabled) {\n\t\t\t\tconst ollamaSt = providerState[\"ollama\"];\n\t\t\t\tif (ollamaSt?.verified && !options.some((o) => o.connId === \"ollama\")) {\n\t\t\t\t\tconst embModel = \"nomic-embed-text\";\n\t\t\t\t\tif (ollamaSt.models.includes(embModel) || ollamaSt.models.length > 0) {\n\t\t\t\t\t\tconst dims = KNOWN_EMB_DIMS[embModel] ?? 768;\n\t\t\t\t\t\toptions.unshift({\n\t\t\t\t\t\t\tid: embModel,\n\t\t\t\t\t\t\tconnId: \"ollama\",\n\t\t\t\t\t\t\tisDefault: false,\n\t\t\t\t\t\t\tdims\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (roleId === \"embedding\") {\n\t\t\t\tconst filtered = options.filter((o) => o.isDefault || o.dims > 0);\n\t\t\t\tif (filtered.length > 0) return filtered;\n\t\t\t}\n\t\t\treturn options;\n\t\t}\n\t\tasync function apiFetchModels(provider, baseUrl, apiKey) {\n\t\t\tconst url = \"/api/setup/models/\" + encodeURIComponent(provider);\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tapiKey: apiKey ?? \"\",\n\t\t\t\t\tbaseUrl: baseUrl ?? \"\"\n\t\t\t\t})\n\t\t\t});\n\t\t\tconst data = await res.json();\n\t\t\tif (!res.ok || data.status === \"recoverable_error\") throw new Error(data.error ?? \"Failed to fetch models (HTTP \" + res.status + \")\");\n\t\t\treturn data;\n\t\t}\n\t\tasync function verifyProvider(id) {\n\t\t\tconst p = PROVIDERS.find((x) => x.id === id);\n\t\t\tif (!p) return;\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tif (id === \"ollama\" && st.ollamaMode === \"instack\") {\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst gen = (verifyGeneration[id] ?? 0) + 1;\n\t\t\tverifyGeneration[id] = gen;\n\t\t\tst.verifying = true;\n\t\t\tst.error = false;\n\t\t\tconst baseUrl = (st.baseUrl || p.baseUrl).trim();\n\t\t\tconst apiKey = (st.apiKey ?? \"\").trim();\n\t\t\ttry {\n\t\t\t\tconst result = await apiFetchModels(id, baseUrl, apiKey);\n\t\t\t\tif (verifyGeneration[id] !== gen) return;\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t\tst.models = result.models ?? [];\n\t\t\t} catch (e) {\n\t\t\t\tif (verifyGeneration[id] !== gen) return;\n\t\t\t\tst.verified = false;\n\t\t\t\tst.error = true;\n\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"\";\n\t\t\t\tst.models = [];\n\t\t\t}\n\t\t\tst.verifying = false;\n\t\t}\n\t\tasync function startOpenCodeOAuth(providerId, methodIndex) {\n\t\t\tconst st = providerState[providerId];\n\t\t\tif (!st) return;\n\t\t\tst.verifying = true;\n\t\t\tst.error = false;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/opencode/provider/\" + encodeURIComponent(providerId) + \"/oauth/authorize\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ method: methodIndex })\n\t\t\t\t});\n\t\t\t\tconst oauthRes = await res.json();\n\t\t\t\tif (!res.ok) throw new Error(oauthRes.message ?? \"OAuth failed\");\n\t\t\t\tst.oauthPolling = true;\n\t\t\t\tst.oauthUrl = oauthRes.url ?? \"\";\n\t\t\t\tst.oauthInstructions = oauthRes.instructions ?? \"\";\n\t\t\t\tif (oauthRes.url && oauthRes.method === \"auto\") window.open(oauthRes.url, \"_blank\");\n\t\t\t\tawait pollOpenCodeOAuth(providerId, methodIndex);\n\t\t\t} catch (e) {\n\t\t\t\tst.verifying = false;\n\t\t\t\tst.error = true;\n\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"OAuth failed\";\n\t\t\t\tst.oauthPolling = false;\n\t\t\t}\n\t\t}\n\t\tasync function pollOpenCodeOAuth(providerId, methodIndex) {\n\t\t\tconst st = providerState[providerId];\n\t\t\tconst ac = new AbortController();\n\t\t\toauthAbortControllers[providerId] = ac;\n\t\t\tconst timeoutSignal = AbortSignal.timeout(10 * 6e4);\n\t\t\tconst combinedSignal = AbortSignal.any ? AbortSignal.any([ac.signal, timeoutSignal]) : ac.signal;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/opencode/provider/\" + encodeURIComponent(providerId) + \"/oauth/callback\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ method: methodIndex }),\n\t\t\t\t\tsignal: combinedSignal\n\t\t\t\t});\n\t\t\t\tconst data = await res.json().catch(() => null);\n\t\t\t\tif (res.ok && data?.ok) {\n\t\t\t\t\tst.verified = true;\n\t\t\t\t\tst.error = false;\n\t\t\t\t} else {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = data?.message ?? \"Authorization failed\";\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof Error && e.name === \"AbortError\" && ac.signal.aborted) return;\n\t\t\t\tif (e instanceof Error && e.name === \"AbortError\") {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = \"Authorization timed out. Try again.\";\n\t\t\t\t} else {\n\t\t\t\t\tst.error = true;\n\t\t\t\t\tst.errorMessage = e instanceof Error ? e.message : \"Authorization failed\";\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tdelete oauthAbortControllers[providerId];\n\t\t\t\tst.oauthPolling = false;\n\t\t\t\tst.verifying = false;\n\t\t\t}\n\t\t}\n\t\tasync function handleInstall() {\n\t\t\tif (installing) return;\n\t\t\tinstallError = \"\";\n\t\t\tinstalling = true;\n\t\t\tif ((persistedVoiceTts().engine === \"openpalm-voice\" || persistedVoiceStt().engine === \"openpalm-voice\") && !selectedVoiceProfile) {\n\t\t\t\tconst preferred = addonProfileId(\"voice\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\t\tselectedVoiceProfile = (voiceProfiles.find((p) => p.id === preferred && p.available !== false) ?? voiceProfiles.find((p) => p.id === addonProfileId(\"voice\", \"cpu\") && p.available !== false) ?? voiceProfiles.find((p) => p.available !== false))?.id ?? addonProfileId(\"voice\", \"cpu\");\n\t\t\t}\n\t\t\tif (ollamaEnabled && !selectedOllamaProfile) selectedOllamaProfile = addonProfileId(\"ollama\", gpuDetected ? \"cuda\" : \"cpu\");\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/complete\", {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify(payload())\n\t\t\t\t});\n\t\t\t\tconst data = await res.json();\n\t\t\t\tif (!res.ok || !data.ok) {\n\t\t\t\t\tinstallError = data.error ?? data.message ?? \"Install failed.\";\n\t\t\t\t\tinstalling = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshowDeploy = true;\n\t\t\t\tstartDeployPolling();\n\t\t\t} catch (e) {\n\t\t\t\tinstallError = \"Network error: \" + (e instanceof Error ? e.message : \"unable to reach server.\");\n\t\t\t\tinstalling = false;\n\t\t\t}\n\t\t}\n\t\tfunction startDeployPolling() {\n\t\t\tstopDeployPolling();\n\t\t\tpollDeployStatus();\n\t\t\tdeployTimer = setInterval(() => {\n\t\t\t\tpollDeployStatus();\n\t\t\t}, 2500);\n\t\t}\n\t\tfunction stopDeployPolling() {\n\t\t\tif (deployTimer) {\n\t\t\t\tclearInterval(deployTimer);\n\t\t\t\tdeployTimer = null;\n\t\t\t}\n\t\t}\n\t\tasync function pollDeployStatus() {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/deploy-status\");\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tdeployPollErrors++;\n\t\t\t\t\tif (deployPollErrors >= 5) {\n\t\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\t\tdeployError = \"Lost contact with the installer. Services may still be starting in the background.\";\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst data = await res.json();\n\t\t\t\tdeployPollErrors = 0;\n\t\t\t\tif (data.deployStatus && data.deployStatus.length > 0) data.deployStatus.map((s) => ({\n\t\t\t\t\tservice: s.service,\n\t\t\t\t\tstatus: s.status,\n\t\t\t\t\tlabel: s.label\n\t\t\t\t}));\n\t\t\t\tdeployData = data;\n\t\t\t\tif (data.deployError) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployError = data.deployError;\n\t\t\t\t} else if (data.setupComplete && data.deployStatus && data.deployStatus.length > 0) {\n\t\t\t\t\tif (data.deployStatus.every((s) => s.status === \"running\")) {\n\t\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\t\tdeployDone = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (data.setupComplete && !data.deploying && (!data.deployStatus || data.deployStatus.length === 0)) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployDone = true;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tdeployPollErrors++;\n\t\t\t\tif (deployPollErrors >= 5) {\n\t\t\t\t\tstopDeployPolling();\n\t\t\t\t\tdeployError = err instanceof Error ? `Lost contact with the installer: ${err.message}` : \"Lost contact with the installer.\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction handleToggleFallback(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tif (st.selected) expandedProvider = expandedProvider === id ? null : id;\n\t\t\telse {\n\t\t\t\tst.selected = true;\n\t\t\t\texpandedProvider = id;\n\t\t\t\tconst detected = detectedProviders.find((d) => d.provider === id && d.available);\n\t\t\t\tif (detected) st.baseUrl = detected.url;\n\t\t\t}\n\t\t}\n\t\tfunction handleToggleOpenCode(id) {\n\t\t\texpandedProvider = expandedProvider === id ? null : id;\n\t\t}\n\t\tfunction handleDeselect(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (!st) return;\n\t\t\tst.selected = false;\n\t\t\tst.verified = false;\n\t\t\tst.verifying = false;\n\t\t\tst.error = false;\n\t\t\tst.apiKey = \"\";\n\t\t\tst.models = [];\n\t\t\tif (id === \"ollama\") st.ollamaMode = null;\n\t\t\tif (expandedProvider === id) expandedProvider = null;\n\t\t}\n\t\tfunction handleMarkReady(id) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) {\n\t\t\t\tst.verified = true;\n\t\t\t\tst.error = false;\n\t\t\t}\n\t\t}\n\t\tfunction handleVerify(id) {\n\t\t\tverifyProvider(id);\n\t\t}\n\t\tfunction handleApiKey(id, key) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) st.apiKey = key;\n\t\t}\n\t\tfunction handleBaseUrl(id, url) {\n\t\t\tconst st = providerState[id];\n\t\t\tif (st) st.baseUrl = url;\n\t\t}\n\t\tfunction handleOllamaMode(mode) {\n\t\t\tconst st = providerState.ollama;\n\t\t\tif (st) st.ollamaMode = mode;\n\t\t}\n\t\tfunction handleChannelToggle(id) {\n\t\t\tconst sel = channelSelection[id];\n\t\t\tif (typeof sel === \"object\" && sel !== null) sel.enabled = !sel.enabled;\n\t\t\telse channelSelection[id] = !sel;\n\t\t}\n\t\tfunction handleCredentialChange(chId, credKey, value) {\n\t\t\tconst sel = channelSelection[chId];\n\t\t\tif (typeof sel === \"object\" && sel !== null) sel[credKey] = value;\n\t\t}\n\t\tfunction handleSelectModel(role, connId, modelId, dims) {\n\t\t\tmodelSelection[role] = {\n\t\t\t\tconnId,\n\t\t\t\tmodel: modelId,\n\t\t\t\tdims\n\t\t\t};\n\t\t\tif (role === \"embedding\" && (dims <= 0 || dims === void 0)) step2EmbDimWarning = \"Unknown embedding model dimensions — set manually in akm config after install.\";\n\t\t\telse if (role === \"embedding\") step2EmbDimWarning = \"\";\n\t\t}\n\t\tfunction handleSelectNone(role) {\n\t\t\tdelete modelSelection[role];\n\t\t}\n\t\tfunction handleDeployRetry() {\n\t\t\tinstalling = false;\n\t\t\tdeployError = null;\n\t\t\tdeployDone = false;\n\t\t\tdeployData = {};\n\t\t\tdeployPollErrors = 0;\n\t\t\thandleInstall();\n\t\t}\n\t\tfunction handleDeployBack() {\n\t\t\tinstalling = false;\n\t\t\tdeployError = null;\n\t\t\tdeployDone = false;\n\t\t\tdeployData = {};\n\t\t\tdeployPollErrors = 0;\n\t\t\tshowDeploy = false;\n\t\t\tcurrentStep = 6;\n\t\t}\n\t\tlet hostImporting = false;\n\t\tasync function handleHostImport() {\n\t\t\thostImporting = true;\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(\"/api/setup/import-host\", { method: \"POST\" });\n\t\t\t\tif (res.ok) {\n\t\t\t\t\tif ((await res.json()).ok) {\n\t\t\t\t\t\tfor (const id of Object.keys(providerState)) if (!providerState[id].verified && PROVIDERS.some((p) => p.id === id)) verifyProvider(id);\n\t\t\t\t\t\thostImporting = false;\n\t\t\t\t\t\tif (!isRerun) goToStep(3);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t\thostImporting = false;\n\t\t}\n\t\tlet isRerun = false;\n\t\thead(\"g40i6i\", $$renderer, ($$renderer) => {\n\t\t\t$$renderer.title(($$renderer) => {\n\t\t\t\t$$renderer.push(`<title>OpenPalm Setup</title>`);\n\t\t\t});\n\t\t\t$$renderer.push(`<link rel=\"stylesheet\" href=\"/setup/wizard.css\"/>`);\n\t\t});\n\t\t$$renderer.push(`<main class=\"setup-page\" aria-label=\"Setup wizard\"><div class=\"wizard-card\">`);\n\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> <div class=\"wizard-header\"><div class=\"hdr-logo\">OP</div> <h1>OpenPalm <span class=\"hdr-suffix\">${escape_html(\"Setup\")}</span></h1></div> <div class=\"wizard-body\">`);\n\t\tif (!showDeploy) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tProgressBar($$renderer, {\n\t\t\t\tcurrentStep,\n\t\t\t\tmaxVisitedStep,\n\t\t\t\tonnavigate: goToStep,\n\t\t\t\tcanNavigateTo\n\t\t\t});\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--> `);\n\t\tif (showDeploy) {\n\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\tDeployStep($$renderer, {\n\t\t\t\tdeployData,\n\t\t\t\tdeployDone,\n\t\t\t\tdeployError,\n\t\t\t\tonback: handleDeployBack,\n\t\t\t\tonretry: handleDeployRetry\n\t\t\t});\n\t\t} else if (currentStep === 0) {\n\t\t\t$$renderer.push(\"<!--[1-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-0\" data-testid=\"step-system-check\">`);\n\t\t\tSystemCheckStep($$renderer, {\n\t\t\t\tisRerun,\n\t\t\t\tonpass: () => {\n\t\t\t\t\tsystemCheckPassed = true;\n\t\t\t\t},\n\t\t\t\tonnext: () => {\n\t\t\t\t\tsystemCheckPassed = true;\n\t\t\t\t\tgoToStep(1);\n\t\t\t\t},\n\t\t\t\tongpudetected: (_gpu) => {\n\t\t\t\t\tgpuDetected = true;\n\t\t\t\t\tif (voiceProfiles.length > 0 && selectedVoiceProfile !== addonProfileId(\"voice\", \"cuda\")) {\n\t\t\t\t\t\tconst cuda = voiceProfiles.find((p) => p.id === addonProfileId(\"voice\", \"cuda\") && p.available !== false);\n\t\t\t\t\t\tif (cuda) selectedVoiceProfile = cuda.id;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 1) {\n\t\t\t$$renderer.push(\"<!--[2-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-1\" data-testid=\"step-welcome\">`);\n\t\t\tWelcomeStep($$renderer, {\n\t\t\t\terrorMessage: step0Error,\n\t\t\t\tdetectionReady,\n\t\t\t\tautoModeImporting,\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep0()) goToStep(2);\n\t\t\t\t},\n\t\t\t\tonusedefaults: () => {\n\t\t\t\t\tif (validateStep0()) handleUseDefaults();\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 2) {\n\t\t\t$$renderer.push(\"<!--[3-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-2\" data-testid=\"step-capabilities\">`);\n\t\t\tif (hostImporting) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div style=\"text-align:center;padding:48px 0\"><div class=\"loading-state\"><span class=\"spinner\"></span> Importing providers from host OpenCode…</div></div>`);\n\t\t\t} else {\n\t\t\t\t$$renderer.push(\"<!--[-1-->\");\n\t\t\t\tProvidersStep($$renderer, {\n\t\t\t\t\topencodeAvailable,\n\t\t\t\t\topencodeProviders,\n\t\t\t\t\topencodeAuth,\n\t\t\t\t\tproviderState,\n\t\t\t\t\texpandedProvider,\n\t\t\t\t\tdetectedProviders,\n\t\t\t\t\tdetecting,\n\t\t\t\t\tocFilterQuery,\n\t\t\t\t\tverifiedCount: verifiedCount(),\n\t\t\t\t\thostProviderCount,\n\t\t\t\t\thostStatusWarning,\n\t\t\t\t\tallowEmptyInstall,\n\t\t\t\t\tonback: () => goToStep(1),\n\t\t\t\t\tonnext: () => goToStep(3),\n\t\t\t\t\tontogglefallback: handleToggleFallback,\n\t\t\t\t\tontoggleopencode: handleToggleOpenCode,\n\t\t\t\t\tonverify: handleVerify,\n\t\t\t\t\tonapikey: handleApiKey,\n\t\t\t\t\tonbaseurl: handleBaseUrl,\n\t\t\t\t\tonollamamode: handleOllamaMode,\n\t\t\t\t\tonoauthstart: startOpenCodeOAuth,\n\t\t\t\t\tonoauthcancel: (id) => {\n\t\t\t\t\t\tconst ac = oauthAbortControllers[id];\n\t\t\t\t\t\tif (ac) {\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t\tdelete oauthAbortControllers[id];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst st = providerState[id];\n\t\t\t\t\t\tif (st) {\n\t\t\t\t\t\t\tst.oauthPolling = false;\n\t\t\t\t\t\t\tst.verifying = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tonmarkready: handleMarkReady,\n\t\t\t\t\tondeselect: handleDeselect,\n\t\t\t\t\tonfilterchange: (q) => ocFilterQuery = q,\n\t\t\t\t\tonhostimport: () => void handleHostImport(),\n\t\t\t\t\tonallowemptyinstallchange: (v) => allowEmptyInstall = v\n\t\t\t\t});\n\t\t\t}\n\t\t\t$$renderer.push(`<!--]--></section>`);\n\t\t} else if (currentStep === 3) {\n\t\t\t$$renderer.push(\"<!--[4-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-3\" data-testid=\"step-models\">`);\n\t\t\tif (step2EmbDimWarning) {\n\t\t\t\t$$renderer.push(\"<!--[0-->\");\n\t\t\t\t$$renderer.push(`<div class=\"field-warning\" role=\"alert\">${escape_html(step2EmbDimWarning)}</div>`);\n\t\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t\t$$renderer.push(`<!--]--> `);\n\t\t\tModelsStep($$renderer, {\n\t\t\t\tverifiedProviders: verifiedProviders(),\n\t\t\t\tproviderState,\n\t\t\t\tmodelSelection,\n\t\t\t\terrorMessage: step2Error,\n\t\t\t\tonback: () => goToStep(2),\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep2()) goToStep(4);\n\t\t\t\t},\n\t\t\t\tonselect: handleSelectModel,\n\t\t\t\tonselectnone: handleSelectNone\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 4) {\n\t\t\t$$renderer.push(\"<!--[5-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-4\" data-testid=\"step-voice\">`);\n\t\t\tVoiceStep($$renderer, {\n\t\t\t\ttts: displayedVoiceTts(),\n\t\t\t\tstt: displayedVoiceStt(),\n\t\t\t\thasOpenAI: hasOpenAI(),\n\t\t\t\tunknownTts: voiceEngineUnknownTts,\n\t\t\t\tunknownStt: voiceEngineUnknownStt,\n\t\t\t\tprofiles: voiceProfiles,\n\t\t\t\tselectedVoiceProfile,\n\t\t\t\tonback: () => goToStep(3),\n\t\t\t\tonnext: () => goToStep(5),\n\t\t\t\tonchangetts: (v) => {\n\t\t\t\t\tvoiceTts = v;\n\t\t\t\t\tvoiceEngineUnknownTts = false;\n\t\t\t\t},\n\t\t\t\tonchangestt: (v) => {\n\t\t\t\t\tvoiceStt = v;\n\t\t\t\t\tvoiceEngineUnknownStt = false;\n\t\t\t\t},\n\t\t\t\tonprofilechange: (id) => {\n\t\t\t\t\tselectedVoiceProfile = id;\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 5) {\n\t\t\t$$renderer.push(\"<!--[6-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-5\" data-testid=\"step-options\">`);\n\t\t\tOptionsStep($$renderer, {\n\t\t\t\tchannelSelection,\n\t\t\t\timageTag,\n\t\t\t\thostAkmEnabled,\n\t\t\t\thostAkmAvailable,\n\t\t\t\tenableVoice,\n\t\t\t\tvoiceProfiles,\n\t\t\t\tselectedVoiceProfile,\n\t\t\t\tollamaEnabled,\n\t\t\t\tollamaProfiles,\n\t\t\t\tselectedOllamaProfile,\n\t\t\t\terrorMessage: step4Error,\n\t\t\t\tonback: () => goToStep(4),\n\t\t\t\tonnext: () => {\n\t\t\t\t\tif (validateStep4()) goToStep(6);\n\t\t\t\t},\n\t\t\t\tonchanneltoggle: handleChannelToggle,\n\t\t\t\toncredentialchange: handleCredentialChange,\n\t\t\t\tonimagtagchange: (v) => imageTag = v,\n\t\t\t\tonhostakmchange: (v) => hostAkmEnabled = v,\n\t\t\t\tonenablevoicechange: handleEnableVoiceChange,\n\t\t\t\tonvoiceprofilechange: (id) => {\n\t\t\t\t\tselectedVoiceProfile = id;\n\t\t\t\t},\n\t\t\t\tonollamachange: handleOptionsOllamaChange,\n\t\t\t\tonollamaprofilechange: (id) => {\n\t\t\t\t\tselectedOllamaProfile = id;\n\t\t\t\t}\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else if (currentStep === 6) {\n\t\t\t$$renderer.push(\"<!--[7-->\");\n\t\t\t$$renderer.push(`<section class=\"step-content\" id=\"step-6\" data-testid=\"step-review\">`);\n\t\t\tReviewStep($$renderer, {\n\t\t\t\tuiLoginPassword,\n\t\t\t\tverifiedProviders: verifiedProviders(),\n\t\t\t\tmodelSelection,\n\t\t\t\tactiveTts: persistedVoiceTts().engine,\n\t\t\t\tactiveStt: persistedVoiceStt().engine,\n\t\t\t\tvoiceProfileLabel: selectedVoiceProfileLabel(),\n\t\t\t\tollamaProfileLabel: selectedOllamaProfileLabel(),\n\t\t\t\tchannelSelection,\n\t\t\t\tollamaEnabled,\n\t\t\t\tpayload: payload(),\n\t\t\t\tinstallError,\n\t\t\t\tinstalling,\n\t\t\t\tisRerun,\n\t\t\t\tonback: () => goToStep(5),\n\t\t\t\toninstall: handleInstall,\n\t\t\t\tongostepedit: goToStep\n\t\t\t});\n\t\t\t$$renderer.push(`<!----></section>`);\n\t\t} else $$renderer.push(\"<!--[-1-->\");\n\t\t$$renderer.push(`<!--]--></div></div></main>`);\n\t});\n}\n//#endregion\nexport { _page as default };\n"],"names":[],"mappings":";;;AAkOA,IAAI,WAAW,GAAG;AAClB,CAAC,cAAc;AACf,CAAC,aAAa;AACd,CAAC,WAAW;AACZ,CAAC,QAAQ;AACT,CAAC,OAAO;AACR,CAAC,SAAS;AACV,CAAC;AACD,CAAC;;AChID;AACA;AACA,SAAS,WAAW,CAAC,UAAU,EAAE,OAAO,EAAE;AAC1C,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AACtC,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAc,aAAa,EAAE,GAAG,OAAO;AAC1E,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,mFAAmF,CAAC,CAAC;AACxG,EAAE,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACnD,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE;AACnE,GAAG,UAAU,CAAC,CAAC,CAAC;AAChB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC1F,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,gDAAgD,CAAC,CAAC;AACrE,EAAE,MAAM,YAAY,GAAG,iBAAiB,CAAC,WAAW,CAAC;AACrD,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE;AACrE,GAAG,IAAI,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC;AAC9B,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC,IAAI,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,WAAW,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,cAAc,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;AAChS,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AACH;AAwCA;AACA;AACA,SAAS,eAAe,CAAC,UAAU,EAAE,OAAO,EAAE;AAC9C,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AAItC,EAAE,IAAI,OAAO,GAAG,IAAI;AACpB,EAAE,IAAI,MAAM,GAAG,IAAI;AAKnB,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,kHAAkH,CAAC,CAAC;AACvI,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,0EAA0E,EAAE,UAAU,CAAC,6BAA6B,EAAE,MAAM,EAAE;AACjJ,GAAG,kBAAkB,EAAE,MAAM;AAC7B,GAAG,oBAAoB,EAAE;AACzB,GAAG,CAAC,CAAC,2CAA2C,CAAC,CAAC;AAClD,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,0IAA0I,CAAC,CAAC;AAC/J,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,yBAAyB,EAAE,UAAU,CAAC,6BAA6B,EAAE,MAAM,EAAE;AAChG,GAAG,kBAAkB,EAAE,MAAM;AAC7B,GAAG,oBAAoB,EAAE;AACzB,GAAG,CAAC,CAAC,2CAA2C,CAAC,CAAC;AAClD,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,8IAA8I,CAAC,CAAC;AACnK,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,CAAC;AAC1C,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;AAC9B,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,kGAAkG,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,gEAAgE,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,wBAAwB,CAAC,CAAC;AAC/S,CAAC,CAAC,CAAC;AACH;AA83BA;AACA;AACA,SAAS,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE;AACpC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,KAAK;AACtC,EAAE,IAAI,WAAW,GAAG,CAAC;AACrB,EAAE,IAAI,cAAc,GAAG,CAAC;AAiSxB,EAAE,SAAS,aAAa,CAAC,IAAI,EAAE;AAC/B,GAAG,IAAI,IAAI,GAAG,cAAc,EAAE,OAAO,KAAK;AAC1C,GAAG,OAAO,IAAI;AACd,EAAE;AAyWF,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,UAAU,KAAK;AAC7C,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,UAAU,KAAK;AACpC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,6BAA6B,CAAC,CAAC;AACpD,GAAG,CAAC,CAAC;AACL,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,iDAAiD,CAAC,CAAC;AACvE,EAAE,CAAC,CAAC;AACJ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,4EAA4E,CAAC,CAAC;AACjG,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC/B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,yGAAyG,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,4CAA4C,CAAC,CAAC;AACjM,EAAmB;AACnB,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/B,GAAG,WAAW,CAAC,UAAU,EAAE;AAC3B,IAAI,WAAW;AACf,IAAI,cAAc;AAClB,IACI;AACJ,IAAI,CAAC;AACL,EAAE;AACF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;AAC9B,EASgC;AAChC,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAC/B,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,0EAA0E,CAAC,CAAC;AAChG,GAAG,eAAe,CAAC,UAgBf,CAAC;AACL,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,CAAC;AACvC,EAAE;AAwKF,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,2BAA2B,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AACH;;;;"}