@openpalm/ui 0.11.2 → 0.11.3-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/build/.openpalm-ui-version +1 -1
  2. package/build/client/_app/immutable/chunks/BzMbI6G9.js +5 -0
  3. package/build/client/_app/immutable/chunks/BzMbI6G9.js.br +0 -0
  4. package/build/client/_app/immutable/chunks/BzMbI6G9.js.gz +0 -0
  5. package/build/client/_app/immutable/chunks/DLZB-lDO.js +1 -0
  6. package/build/client/_app/immutable/chunks/DLZB-lDO.js.br +2 -0
  7. package/build/client/_app/immutable/chunks/DLZB-lDO.js.gz +0 -0
  8. package/build/client/_app/immutable/chunks/DbYMkvQX.js +3 -0
  9. package/build/client/_app/immutable/chunks/DbYMkvQX.js.br +0 -0
  10. package/build/client/_app/immutable/chunks/DbYMkvQX.js.gz +0 -0
  11. package/build/client/_app/immutable/chunks/Q60SYwq0.js +1 -0
  12. package/build/client/_app/immutable/chunks/Q60SYwq0.js.br +0 -0
  13. package/build/client/_app/immutable/chunks/Q60SYwq0.js.gz +0 -0
  14. package/build/client/_app/immutable/entry/{app.jhM1F9Lz.js → app.6RzKsf7V.js} +2 -2
  15. package/build/client/_app/immutable/entry/app.6RzKsf7V.js.br +0 -0
  16. package/build/client/_app/immutable/entry/app.6RzKsf7V.js.gz +0 -0
  17. package/build/client/_app/immutable/entry/start.CqKzCNEy.js +1 -0
  18. package/build/client/_app/immutable/entry/start.CqKzCNEy.js.br +1 -0
  19. package/build/client/_app/immutable/entry/start.CqKzCNEy.js.gz +0 -0
  20. package/build/client/_app/immutable/nodes/{1.CAM0_CnR.js → 1.CU5j754b.js} +1 -1
  21. package/build/client/_app/immutable/nodes/1.CU5j754b.js.br +1 -0
  22. package/build/client/_app/immutable/nodes/1.CU5j754b.js.gz +0 -0
  23. package/build/client/_app/immutable/nodes/{4.BInZ_Tt5.js → 4.R4lRKhe8.js} +1 -1
  24. package/build/client/_app/immutable/nodes/4.R4lRKhe8.js.br +0 -0
  25. package/build/client/_app/immutable/nodes/{4.BInZ_Tt5.js.gz → 4.R4lRKhe8.js.gz} +0 -0
  26. package/build/client/_app/immutable/nodes/{5.e3eblL7D.js → 5.NUXXVDlQ.js} +1 -1
  27. package/build/client/_app/immutable/nodes/5.NUXXVDlQ.js.br +0 -0
  28. package/build/client/_app/immutable/nodes/5.NUXXVDlQ.js.gz +0 -0
  29. package/build/client/_app/immutable/nodes/{6.D6wSITV7.js → 6.DCGzb_pK.js} +1 -1
  30. package/build/client/_app/immutable/nodes/6.DCGzb_pK.js.br +0 -0
  31. package/build/client/_app/immutable/nodes/6.DCGzb_pK.js.gz +0 -0
  32. package/build/client/_app/immutable/nodes/{7.C1W_OsSf.js → 7.DuxnfDxB.js} +1 -1
  33. package/build/client/_app/immutable/nodes/7.DuxnfDxB.js.br +0 -0
  34. package/build/client/_app/immutable/nodes/7.DuxnfDxB.js.gz +0 -0
  35. package/build/client/_app/immutable/nodes/{8.9E6jSDDa.js → 8.DLc2iN5h.js} +1 -1
  36. package/build/client/_app/immutable/nodes/8.DLc2iN5h.js.br +0 -0
  37. package/build/client/_app/immutable/nodes/8.DLc2iN5h.js.gz +0 -0
  38. package/build/client/_app/immutable/nodes/{9.CutxJ3jN.js → 9.CFQabEMi.js} +3 -3
  39. package/build/client/_app/immutable/nodes/9.CFQabEMi.js.br +0 -0
  40. package/build/client/_app/immutable/nodes/9.CFQabEMi.js.gz +0 -0
  41. package/build/client/_app/version.json +1 -1
  42. package/build/client/_app/version.json.br +1 -1
  43. package/build/client/_app/version.json.gz +0 -0
  44. package/build/server/chunks/1-Bf3C8Sem.js +9 -0
  45. package/build/server/chunks/{1-DGZd-zFK.js.map → 1-Bf3C8Sem.js.map} +1 -1
  46. package/build/server/chunks/4-Cow1n2qH.js +9 -0
  47. package/build/server/chunks/{4-D9UtUsJp.js.map → 4-Cow1n2qH.js.map} +1 -1
  48. package/build/server/chunks/5-CacEvwL6.js +9 -0
  49. package/build/server/chunks/{5-B_4lRh2I.js.map → 5-CacEvwL6.js.map} +1 -1
  50. package/build/server/chunks/{6-BLnRcxu-.js → 6-kzDGNRbL.js} +3 -3
  51. package/build/server/chunks/{6-BLnRcxu-.js.map → 6-kzDGNRbL.js.map} +1 -1
  52. package/build/server/chunks/7-DCR9r57x.js +9 -0
  53. package/build/server/chunks/{7-Ce9mKDNS.js.map → 7-DCR9r57x.js.map} +1 -1
  54. package/build/server/chunks/{8-DZdi94I7.js → 8-CI7yb1Ce.js} +3 -3
  55. package/build/server/chunks/{8-DZdi94I7.js.map → 8-CI7yb1Ce.js.map} +1 -1
  56. package/build/server/chunks/{9-DbwaI7nh.js → 9-CGVsBC0_.js} +2 -2
  57. package/build/server/chunks/{9-DbwaI7nh.js.map → 9-CGVsBC0_.js.map} +1 -1
  58. package/build/server/chunks/{Navbar-BHPXjl1A.js → Navbar-D5G8jm15.js} +6 -3
  59. package/build/server/chunks/Navbar-D5G8jm15.js.map +1 -0
  60. package/build/server/chunks/{_page.svelte-Cp6aBilY.js → _page.svelte-B-lalOw2.js} +5 -5
  61. package/build/server/chunks/{_page.svelte-Cp6aBilY.js.map → _page.svelte-B-lalOw2.js.map} +1 -1
  62. package/build/server/chunks/_page.svelte-B0M8mXzs.js.map +1 -1
  63. package/build/server/chunks/{_page.svelte-BXZROSm4.js → _page.svelte-BCxCH8fC.js} +5 -5
  64. package/build/server/chunks/{_page.svelte-BXZROSm4.js.map → _page.svelte-BCxCH8fC.js.map} +1 -1
  65. package/build/server/chunks/{_page.svelte-Ra8DEIk0.js → _page.svelte-BZNq9li9.js} +3 -3
  66. package/build/server/chunks/{_page.svelte-Ra8DEIk0.js.map → _page.svelte-BZNq9li9.js.map} +1 -1
  67. package/build/server/chunks/{_page.svelte-C4_2jNl6.js → _page.svelte-BuetGcnd.js} +6 -6
  68. package/build/server/chunks/{_page.svelte-C4_2jNl6.js.map → _page.svelte-BuetGcnd.js.map} +1 -1
  69. package/build/server/chunks/{_page.svelte-CXkNPL1p.js → _page.svelte-CDzTRckl.js} +5 -5
  70. package/build/server/chunks/{_page.svelte-CXkNPL1p.js.map → _page.svelte-CDzTRckl.js.map} +1 -1
  71. package/build/server/chunks/{_server.ts-OVKLVpsS.js → _server.ts-3bIOrNCW.js} +4 -4
  72. package/build/server/chunks/{_server.ts-OVKLVpsS.js.map → _server.ts-3bIOrNCW.js.map} +1 -1
  73. package/build/server/chunks/{_server.ts-IJ68pRcj.js → _server.ts-6j35W-bb.js} +5 -5
  74. package/build/server/chunks/{_server.ts-IJ68pRcj.js.map → _server.ts-6j35W-bb.js.map} +1 -1
  75. package/build/server/chunks/{_server.ts-Cix_DzOZ.js → _server.ts-7Wf3G6xc.js} +4 -4
  76. package/build/server/chunks/{_server.ts-Cix_DzOZ.js.map → _server.ts-7Wf3G6xc.js.map} +1 -1
  77. package/build/server/chunks/{_server.ts-5pMviGH3.js → _server.ts-B3DUJf6P.js} +16 -4
  78. package/build/server/chunks/_server.ts-B3DUJf6P.js.map +1 -0
  79. package/build/server/chunks/{_server.ts-DuJ8w3d8.js → _server.ts-B8V8xLOX.js} +4 -4
  80. package/build/server/chunks/{_server.ts-DuJ8w3d8.js.map → _server.ts-B8V8xLOX.js.map} +1 -1
  81. package/build/server/chunks/{_server.ts-C901uAGV.js → _server.ts-BGZDhLXh.js} +8 -7
  82. package/build/server/chunks/_server.ts-BGZDhLXh.js.map +1 -0
  83. package/build/server/chunks/{_server.ts-CyUtNvIJ.js → _server.ts-BOha2L_A.js} +4 -4
  84. package/build/server/chunks/{_server.ts-CyUtNvIJ.js.map → _server.ts-BOha2L_A.js.map} +1 -1
  85. package/build/server/chunks/{_server.ts-6KmCyX4_.js → _server.ts-BPBMdkDE.js} +6 -6
  86. package/build/server/chunks/{_server.ts-6KmCyX4_.js.map → _server.ts-BPBMdkDE.js.map} +1 -1
  87. package/build/server/chunks/{_server.ts-BJqeSuwW.js → _server.ts-BTFkcp50.js} +4 -4
  88. package/build/server/chunks/{_server.ts-BJqeSuwW.js.map → _server.ts-BTFkcp50.js.map} +1 -1
  89. package/build/server/chunks/{_server.ts-D5gUeFJE.js → _server.ts-BU9Dy6Ga.js} +5 -5
  90. package/build/server/chunks/{_server.ts-D5gUeFJE.js.map → _server.ts-BU9Dy6Ga.js.map} +1 -1
  91. package/build/server/chunks/{_server.ts-DiJOVzSl.js → _server.ts-B_PD1-BE.js} +4 -4
  92. package/build/server/chunks/{_server.ts-DiJOVzSl.js.map → _server.ts-B_PD1-BE.js.map} +1 -1
  93. package/build/server/chunks/{_server.ts-crIb-8QZ.js → _server.ts-BbzfnU5x.js} +5 -5
  94. package/build/server/chunks/{_server.ts-crIb-8QZ.js.map → _server.ts-BbzfnU5x.js.map} +1 -1
  95. package/build/server/chunks/{_server.ts-Bvp4YpaT.js → _server.ts-Bc4WPPlv.js} +6 -6
  96. package/build/server/chunks/{_server.ts-Bvp4YpaT.js.map → _server.ts-Bc4WPPlv.js.map} +1 -1
  97. package/build/server/chunks/{_server.ts-zCuG209p.js → _server.ts-BkpQZcF0.js} +4 -4
  98. package/build/server/chunks/{_server.ts-zCuG209p.js.map → _server.ts-BkpQZcF0.js.map} +1 -1
  99. package/build/server/chunks/{_server.ts-ByXfEYZ3.js → _server.ts-ByC7qKzo.js} +4 -4
  100. package/build/server/chunks/{_server.ts-ByXfEYZ3.js.map → _server.ts-ByC7qKzo.js.map} +1 -1
  101. package/build/server/chunks/{_server.ts-MVqFnsqa.js → _server.ts-C1m2Gw5U.js} +4 -4
  102. package/build/server/chunks/{_server.ts-MVqFnsqa.js.map → _server.ts-C1m2Gw5U.js.map} +1 -1
  103. package/build/server/chunks/{_server.ts-C_JYwlDL.js → _server.ts-C2-tZdFx.js} +4 -4
  104. package/build/server/chunks/{_server.ts-C_JYwlDL.js.map → _server.ts-C2-tZdFx.js.map} +1 -1
  105. package/build/server/chunks/{_server.ts-CK0Rxw5K.js → _server.ts-C2qehtMf.js} +4 -4
  106. package/build/server/chunks/{_server.ts-CK0Rxw5K.js.map → _server.ts-C2qehtMf.js.map} +1 -1
  107. package/build/server/chunks/{_server.ts-BH3-HO5r.js → _server.ts-CF-JUFSB.js} +6 -6
  108. package/build/server/chunks/{_server.ts-BH3-HO5r.js.map → _server.ts-CF-JUFSB.js.map} +1 -1
  109. package/build/server/chunks/{_server.ts-Dhzz7tHs.js → _server.ts-CGHhMNs3.js} +5 -5
  110. package/build/server/chunks/{_server.ts-Dhzz7tHs.js.map → _server.ts-CGHhMNs3.js.map} +1 -1
  111. package/build/server/chunks/{_server.ts-o9s65uGr.js → _server.ts-CP6bZaJJ.js} +4 -4
  112. package/build/server/chunks/{_server.ts-o9s65uGr.js.map → _server.ts-CP6bZaJJ.js.map} +1 -1
  113. package/build/server/chunks/{_server.ts-RHuSC2x-.js → _server.ts-CS7JXLT-.js} +4 -4
  114. package/build/server/chunks/{_server.ts-RHuSC2x-.js.map → _server.ts-CS7JXLT-.js.map} +1 -1
  115. package/build/server/chunks/{_server.ts-DFJDEcdK.js → _server.ts-CSZYdKIz.js} +2 -2
  116. package/build/server/chunks/{_server.ts-DFJDEcdK.js.map → _server.ts-CSZYdKIz.js.map} +1 -1
  117. package/build/server/chunks/{_server.ts-B8jv4dTo.js → _server.ts-CS_9GHcK.js} +4 -4
  118. package/build/server/chunks/{_server.ts-B8jv4dTo.js.map → _server.ts-CS_9GHcK.js.map} +1 -1
  119. package/build/server/chunks/{_server.ts-CjcbK3K2.js → _server.ts-CXZAOFJM.js} +4 -4
  120. package/build/server/chunks/{_server.ts-CjcbK3K2.js.map → _server.ts-CXZAOFJM.js.map} +1 -1
  121. package/build/server/chunks/{_server.ts-BRaaz800.js → _server.ts-ChEUjFy2.js} +4 -4
  122. package/build/server/chunks/{_server.ts-BRaaz800.js.map → _server.ts-ChEUjFy2.js.map} +1 -1
  123. package/build/server/chunks/{_server.ts-BmCX_RO-.js → _server.ts-CnU909WV.js} +5 -5
  124. package/build/server/chunks/{_server.ts-BmCX_RO-.js.map → _server.ts-CnU909WV.js.map} +1 -1
  125. package/build/server/chunks/{_server.ts-C6CQ4cXn.js → _server.ts-Cnjv0PV3.js} +4 -4
  126. package/build/server/chunks/{_server.ts-C6CQ4cXn.js.map → _server.ts-Cnjv0PV3.js.map} +1 -1
  127. package/build/server/chunks/{_server.ts-C6xE00MS.js → _server.ts-Ctm2JarS.js} +4 -4
  128. package/build/server/chunks/{_server.ts-C6xE00MS.js.map → _server.ts-Ctm2JarS.js.map} +1 -1
  129. package/build/server/chunks/{_server.ts-CkyeWLQD.js → _server.ts-CuWvzlxI.js} +5 -5
  130. package/build/server/chunks/{_server.ts-CkyeWLQD.js.map → _server.ts-CuWvzlxI.js.map} +1 -1
  131. package/build/server/chunks/{_server.ts-c5vxACJj.js → _server.ts-D-CG_91w.js} +4 -4
  132. package/build/server/chunks/{_server.ts-c5vxACJj.js.map → _server.ts-D-CG_91w.js.map} +1 -1
  133. package/build/server/chunks/{_server.ts-XII8m8Um.js → _server.ts-D-p2Hm9n.js} +2 -2
  134. package/build/server/chunks/{_server.ts-XII8m8Um.js.map → _server.ts-D-p2Hm9n.js.map} +1 -1
  135. package/build/server/chunks/{_server.ts-BqQPs0i_.js → _server.ts-D-s-9ge-.js} +3 -3
  136. package/build/server/chunks/{_server.ts-BqQPs0i_.js.map → _server.ts-D-s-9ge-.js.map} +1 -1
  137. package/build/server/chunks/{_server.ts-D4X4auyD.js → _server.ts-D2KqxMre.js} +4 -4
  138. package/build/server/chunks/{_server.ts-D4X4auyD.js.map → _server.ts-D2KqxMre.js.map} +1 -1
  139. package/build/server/chunks/{_server.ts-D8sMZCw-.js → _server.ts-D2iTW5_-.js} +4 -4
  140. package/build/server/chunks/{_server.ts-D8sMZCw-.js.map → _server.ts-D2iTW5_-.js.map} +1 -1
  141. package/build/server/chunks/{_server.ts-CqlfB-aA.js → _server.ts-D5p0zu-y.js} +4 -4
  142. package/build/server/chunks/{_server.ts-CqlfB-aA.js.map → _server.ts-D5p0zu-y.js.map} +1 -1
  143. package/build/server/chunks/{_server.ts-DhyOE-KP.js → _server.ts-D86uN0DZ.js} +2 -2
  144. package/build/server/chunks/{_server.ts-DhyOE-KP.js.map → _server.ts-D86uN0DZ.js.map} +1 -1
  145. package/build/server/chunks/{_server.ts-CIcZeBAF.js → _server.ts-D8p-Zc8Z.js} +4 -4
  146. package/build/server/chunks/{_server.ts-CIcZeBAF.js.map → _server.ts-D8p-Zc8Z.js.map} +1 -1
  147. package/build/server/chunks/{_server.ts-BRAfEDvT.js → _server.ts-D9bBTzrV.js} +4 -4
  148. package/build/server/chunks/{_server.ts-BRAfEDvT.js.map → _server.ts-D9bBTzrV.js.map} +1 -1
  149. package/build/server/chunks/{_server.ts-X6kwNmZX.js → _server.ts-DJLROGuC.js} +4 -4
  150. package/build/server/chunks/{_server.ts-X6kwNmZX.js.map → _server.ts-DJLROGuC.js.map} +1 -1
  151. package/build/server/chunks/{_server.ts-BHIP51pX.js → _server.ts-DKKKZx7q.js} +4 -4
  152. package/build/server/chunks/{_server.ts-BHIP51pX.js.map → _server.ts-DKKKZx7q.js.map} +1 -1
  153. package/build/server/chunks/{_server.ts-DxDXTfuq.js → _server.ts-DP-NPkMD.js} +4 -4
  154. package/build/server/chunks/{_server.ts-DxDXTfuq.js.map → _server.ts-DP-NPkMD.js.map} +1 -1
  155. package/build/server/chunks/{_server.ts-CK8sJWT2.js → _server.ts-D_da58Nk.js} +5 -5
  156. package/build/server/chunks/{_server.ts-CK8sJWT2.js.map → _server.ts-D_da58Nk.js.map} +1 -1
  157. package/build/server/chunks/{_server.ts-CKf5jMDy.js → _server.ts-DaLBPART.js} +4 -4
  158. package/build/server/chunks/{_server.ts-CKf5jMDy.js.map → _server.ts-DaLBPART.js.map} +1 -1
  159. package/build/server/chunks/{_server.ts-CrRcF8Ie.js → _server.ts-DgRjI1W8.js} +4 -4
  160. package/build/server/chunks/{_server.ts-CrRcF8Ie.js.map → _server.ts-DgRjI1W8.js.map} +1 -1
  161. package/build/server/chunks/{_server.ts-B4Atr7Pb.js → _server.ts-DjfCGqvA.js} +4 -4
  162. package/build/server/chunks/{_server.ts-B4Atr7Pb.js.map → _server.ts-DjfCGqvA.js.map} +1 -1
  163. package/build/server/chunks/{_server.ts-CaSXmkds.js → _server.ts-Dkk8XP3m.js} +4 -4
  164. package/build/server/chunks/{_server.ts-CaSXmkds.js.map → _server.ts-Dkk8XP3m.js.map} +1 -1
  165. package/build/server/chunks/{_server.ts-C5cUQhLR.js → _server.ts-Dl07R_n2.js} +5 -5
  166. package/build/server/chunks/{_server.ts-C5cUQhLR.js.map → _server.ts-Dl07R_n2.js.map} +1 -1
  167. package/build/server/chunks/{_server.ts-C90P5trG.js → _server.ts-Do2sgBif.js} +8 -7
  168. package/build/server/chunks/_server.ts-Do2sgBif.js.map +1 -0
  169. package/build/server/chunks/{_server.ts-BHxlYhmn.js → _server.ts-DrJ5_e35.js} +2 -2
  170. package/build/server/chunks/{_server.ts-BHxlYhmn.js.map → _server.ts-DrJ5_e35.js.map} +1 -1
  171. package/build/server/chunks/{_server.ts-CXkRiweb.js → _server.ts-Ds9OIz3V.js} +4 -4
  172. package/build/server/chunks/{_server.ts-CXkRiweb.js.map → _server.ts-Ds9OIz3V.js.map} +1 -1
  173. package/build/server/chunks/{_server.ts-CPo93T4Q.js → _server.ts-DuMzNLkr.js} +6 -6
  174. package/build/server/chunks/{_server.ts-CPo93T4Q.js.map → _server.ts-DuMzNLkr.js.map} +1 -1
  175. package/build/server/chunks/{_server.ts-CWhPqSHs.js → _server.ts-Dv1tbIPB.js} +4 -4
  176. package/build/server/chunks/{_server.ts-CWhPqSHs.js.map → _server.ts-Dv1tbIPB.js.map} +1 -1
  177. package/build/server/chunks/{_server.ts-DseLSghB.js → _server.ts-DvES1wiN.js} +4 -4
  178. package/build/server/chunks/{_server.ts-DseLSghB.js.map → _server.ts-DvES1wiN.js.map} +1 -1
  179. package/build/server/chunks/{_server.ts-Bwx3Gjwd.js → _server.ts-DwufWrL8.js} +4 -4
  180. package/build/server/chunks/{_server.ts-Bwx3Gjwd.js.map → _server.ts-DwufWrL8.js.map} +1 -1
  181. package/build/server/chunks/{_server.ts-DE0m1Q4L.js → _server.ts-DypIhw8E.js} +4 -4
  182. package/build/server/chunks/{_server.ts-DE0m1Q4L.js.map → _server.ts-DypIhw8E.js.map} +1 -1
  183. package/build/server/chunks/{_server.ts-BRefcV0Z.js → _server.ts-I_df3rNy.js} +2 -2
  184. package/build/server/chunks/{_server.ts-BRefcV0Z.js.map → _server.ts-I_df3rNy.js.map} +1 -1
  185. package/build/server/chunks/{_server.ts-BHZefY3G.js → _server.ts-JqtP_8OZ.js} +4 -4
  186. package/build/server/chunks/{_server.ts-BHZefY3G.js.map → _server.ts-JqtP_8OZ.js.map} +1 -1
  187. package/build/server/chunks/{_server.ts-fDATxtr3.js → _server.ts-KbEJb9iF.js} +4 -4
  188. package/build/server/chunks/{_server.ts-fDATxtr3.js.map → _server.ts-KbEJb9iF.js.map} +1 -1
  189. package/build/server/chunks/{_server.ts-DPhVV-jJ.js → _server.ts-KdUnJtGx.js} +4 -4
  190. package/build/server/chunks/{_server.ts-DPhVV-jJ.js.map → _server.ts-KdUnJtGx.js.map} +1 -1
  191. package/build/server/chunks/{_server.ts-BGUpdnPV.js → _server.ts-LnGYpCfy.js} +4 -4
  192. package/build/server/chunks/{_server.ts-BGUpdnPV.js.map → _server.ts-LnGYpCfy.js.map} +1 -1
  193. package/build/server/chunks/{_server.ts-HwlPZi53.js → _server.ts-MPuOqnb6.js} +5 -5
  194. package/build/server/chunks/{_server.ts-HwlPZi53.js.map → _server.ts-MPuOqnb6.js.map} +1 -1
  195. package/build/server/chunks/{_server.ts-CFtUB8Hj.js → _server.ts-Q2jLnu8r.js} +4 -4
  196. package/build/server/chunks/{_server.ts-CFtUB8Hj.js.map → _server.ts-Q2jLnu8r.js.map} +1 -1
  197. package/build/server/chunks/{_server.ts-B3N5nJb3.js → _server.ts-URmO6EQw.js} +4 -4
  198. package/build/server/chunks/{_server.ts-B3N5nJb3.js.map → _server.ts-URmO6EQw.js.map} +1 -1
  199. package/build/server/chunks/{_server.ts-Dq4ZhGok.js → _server.ts-XOD7SUR4.js} +4 -4
  200. package/build/server/chunks/{_server.ts-Dq4ZhGok.js.map → _server.ts-XOD7SUR4.js.map} +1 -1
  201. package/build/server/chunks/{_server.ts-CN5s8RLB.js → _server.ts-XQi6MDkU.js} +6 -6
  202. package/build/server/chunks/{_server.ts-CN5s8RLB.js.map → _server.ts-XQi6MDkU.js.map} +1 -1
  203. package/build/server/chunks/{_server.ts-CnCzNcH9.js → _server.ts-lwKsNmQt.js} +4 -4
  204. package/build/server/chunks/{_server.ts-CnCzNcH9.js.map → _server.ts-lwKsNmQt.js.map} +1 -1
  205. package/build/server/chunks/{_server.ts-DDFiq1Ud.js → _server.ts-m1ayiB8O.js} +4 -4
  206. package/build/server/chunks/{_server.ts-DDFiq1Ud.js.map → _server.ts-m1ayiB8O.js.map} +1 -1
  207. package/build/server/chunks/{_server.ts-CdM6LezY.js → _server.ts-qmijt9h5.js} +4 -4
  208. package/build/server/chunks/{_server.ts-CdM6LezY.js.map → _server.ts-qmijt9h5.js.map} +1 -1
  209. package/build/server/chunks/{_server.ts-DxDpkTu4.js → _server.ts-t7MfsyTJ.js} +4 -4
  210. package/build/server/chunks/{_server.ts-DxDpkTu4.js.map → _server.ts-t7MfsyTJ.js.map} +1 -1
  211. package/build/server/chunks/{_server.ts-CKlHRDZS.js → _server.ts-z2KYSfCP.js} +4 -4
  212. package/build/server/chunks/{_server.ts-CKlHRDZS.js.map → _server.ts-z2KYSfCP.js.map} +1 -1
  213. package/build/server/chunks/{addon-helpers-BY7Y68Or.js → addon-helpers-xb9eIaVn.js} +2 -2
  214. package/build/server/chunks/{addon-helpers-BY7Y68Or.js.map → addon-helpers-xb9eIaVn.js.map} +1 -1
  215. package/build/server/chunks/{client-ArAeRoxk.js → client-CXNrwMy2.js} +28 -3
  216. package/build/server/chunks/{client-ArAeRoxk.js.map → client-CXNrwMy2.js.map} +1 -1
  217. package/build/server/chunks/{config-CjX55Ht6.js → config-0V4UPT81.js} +2 -2
  218. package/build/server/chunks/{config-CjX55Ht6.js.map → config-0V4UPT81.js.map} +1 -1
  219. package/build/server/chunks/{docker-NqrL9zHp.js → docker-CKOdzi6A.js} +2 -2
  220. package/build/server/chunks/{docker-NqrL9zHp.js.map → docker-CKOdzi6A.js.map} +1 -1
  221. package/build/server/chunks/{endpoints-Ci6CJJnc.js → endpoints-uSe3ORbp.js} +2 -2
  222. package/build/server/chunks/{endpoints-Ci6CJJnc.js.map → endpoints-uSe3ORbp.js.map} +1 -1
  223. package/build/server/chunks/{environment-Bpg55mjq.js → environment-DdkeH_HT.js} +2 -2
  224. package/build/server/chunks/{environment-Bpg55mjq.js.map → environment-DdkeH_HT.js.map} +1 -1
  225. package/build/server/chunks/{error.svelte-CpFwRtRX.js → error.svelte-DZ8Z0DRg.js} +4 -4
  226. package/build/server/chunks/{error.svelte-CpFwRtRX.js.map → error.svelte-DZ8Z0DRg.js.map} +1 -1
  227. package/build/server/chunks/{helpers-BqYJlSJg.js → helpers-D4ot6bJ_.js} +3 -3
  228. package/build/server/chunks/{helpers-BqYJlSJg.js.map → helpers-D4ot6bJ_.js.map} +1 -1
  229. package/build/server/chunks/{hooks.server-CRMfHyDz.js → hooks.server-CksTzt9Y.js} +5 -5
  230. package/build/server/chunks/{hooks.server-CRMfHyDz.js.map → hooks.server-CksTzt9Y.js.map} +1 -1
  231. package/build/server/chunks/{http-CghRhEH6.js → http-DWdG8RlO.js} +2 -2
  232. package/build/server/chunks/{http-CghRhEH6.js.map → http-DWdG8RlO.js.map} +1 -1
  233. package/build/server/chunks/{internal-W1HfYnMF.js → internal-BbfLl3-2.js} +3 -3
  234. package/build/server/chunks/{internal-W1HfYnMF.js.map → internal-BbfLl3-2.js.map} +1 -1
  235. package/build/server/chunks/{session-cookie-BGqzaS8B.js → session-cookie-CY2ZiP5t.js} +2 -2
  236. package/build/server/chunks/{session-cookie-BGqzaS8B.js.map → session-cookie-CY2ZiP5t.js.map} +1 -1
  237. package/build/server/chunks/{setup-deploy-Cg9faOlI.js → setup-deploy-CN1g3_cR.js} +2 -7
  238. package/build/server/chunks/setup-deploy-CN1g3_cR.js.map +1 -0
  239. package/build/server/chunks/{src-b3nBkyhY.js → src-DkGZ5D6n.js} +855 -855
  240. package/build/server/chunks/{src-b3nBkyhY.js.map → src-DkGZ5D6n.js.map} +1 -1
  241. package/build/server/chunks/{state-BIeW4-XD.js → state-CyX6jYFl.js} +2 -2
  242. package/build/server/chunks/{state-BIeW4-XD.js.map → state-CyX6jYFl.js.map} +1 -1
  243. package/build/server/index.js +2 -2
  244. package/build/server/manifest.js +79 -79
  245. package/build/server/manifest.js.map +1 -1
  246. package/package.json +2 -2
  247. package/build/client/_app/immutable/chunks/5ZqlzR7j.js +0 -3
  248. package/build/client/_app/immutable/chunks/5ZqlzR7j.js.br +0 -0
  249. package/build/client/_app/immutable/chunks/5ZqlzR7j.js.gz +0 -0
  250. package/build/client/_app/immutable/chunks/Bu0cBnLr.js +0 -1
  251. package/build/client/_app/immutable/chunks/Bu0cBnLr.js.br +0 -2
  252. package/build/client/_app/immutable/chunks/Bu0cBnLr.js.gz +0 -0
  253. package/build/client/_app/immutable/chunks/CEPSqAnS.js +0 -1
  254. package/build/client/_app/immutable/chunks/CEPSqAnS.js.br +0 -0
  255. package/build/client/_app/immutable/chunks/CEPSqAnS.js.gz +0 -0
  256. package/build/client/_app/immutable/chunks/ltAtEuyp.js +0 -5
  257. package/build/client/_app/immutable/chunks/ltAtEuyp.js.br +0 -0
  258. package/build/client/_app/immutable/chunks/ltAtEuyp.js.gz +0 -0
  259. package/build/client/_app/immutable/entry/app.jhM1F9Lz.js.br +0 -0
  260. package/build/client/_app/immutable/entry/app.jhM1F9Lz.js.gz +0 -0
  261. package/build/client/_app/immutable/entry/start.Dc1B22-x.js +0 -1
  262. package/build/client/_app/immutable/entry/start.Dc1B22-x.js.br +0 -1
  263. package/build/client/_app/immutable/entry/start.Dc1B22-x.js.gz +0 -0
  264. package/build/client/_app/immutable/nodes/1.CAM0_CnR.js.br +0 -1
  265. package/build/client/_app/immutable/nodes/1.CAM0_CnR.js.gz +0 -0
  266. package/build/client/_app/immutable/nodes/4.BInZ_Tt5.js.br +0 -0
  267. package/build/client/_app/immutable/nodes/5.e3eblL7D.js.br +0 -0
  268. package/build/client/_app/immutable/nodes/5.e3eblL7D.js.gz +0 -0
  269. package/build/client/_app/immutable/nodes/6.D6wSITV7.js.br +0 -0
  270. package/build/client/_app/immutable/nodes/6.D6wSITV7.js.gz +0 -0
  271. package/build/client/_app/immutable/nodes/7.C1W_OsSf.js.br +0 -0
  272. package/build/client/_app/immutable/nodes/7.C1W_OsSf.js.gz +0 -0
  273. package/build/client/_app/immutable/nodes/8.9E6jSDDa.js.br +0 -0
  274. package/build/client/_app/immutable/nodes/8.9E6jSDDa.js.gz +0 -0
  275. package/build/client/_app/immutable/nodes/9.CutxJ3jN.js.br +0 -0
  276. package/build/client/_app/immutable/nodes/9.CutxJ3jN.js.gz +0 -0
  277. package/build/server/chunks/1-DGZd-zFK.js +0 -9
  278. package/build/server/chunks/4-D9UtUsJp.js +0 -9
  279. package/build/server/chunks/5-B_4lRh2I.js +0 -9
  280. package/build/server/chunks/7-Ce9mKDNS.js +0 -9
  281. package/build/server/chunks/Navbar-BHPXjl1A.js.map +0 -1
  282. package/build/server/chunks/_server.ts-5pMviGH3.js.map +0 -1
  283. package/build/server/chunks/_server.ts-C901uAGV.js.map +0 -1
  284. package/build/server/chunks/_server.ts-C90P5trG.js.map +0 -1
  285. package/build/server/chunks/setup-deploy-Cg9faOlI.js.map +0 -1
@@ -12263,975 +12263,975 @@ function removeTaskFile(stashDir, name) {
12263
12263
  function isSetupComplete(stackDir) {
12264
12264
  return parseEnvFile(stackEnvPathFromStackDir(stackDir)).OP_SETUP_COMPLETE === "true";
12265
12265
  }
12266
- //#endregion
12267
- //#region ../lib/src/control-plane/channels.ts
12266
+ /** Execute docker with an argument array — no shell interpolation. */
12267
+ function run$1(args, cwd, timeoutMs = 12e4, envOverrides) {
12268
+ return new Promise((resolve) => {
12269
+ execFile("docker", args, {
12270
+ cwd,
12271
+ timeout: timeoutMs,
12272
+ env: {
12273
+ ...process.env,
12274
+ ...envOverrides
12275
+ }
12276
+ }, (error, stdout, stderr) => {
12277
+ resolve({
12278
+ ok: !error,
12279
+ stdout: stdout?.toString() ?? "",
12280
+ stderr: stderr?.toString() ?? "",
12281
+ code: error?.code ? Number(error.code) : 0
12282
+ });
12283
+ });
12284
+ });
12285
+ }
12268
12286
  /**
12269
- * Channel validation, discovery, and allowlist checks for the OpenPalm control plane.
12287
+ * Resolve the Docker Compose project name.
12288
+ * Honors OP_PROJECT_NAME first for OpenPalm stacks, then COMPOSE_PROJECT_NAME.
12270
12289
  */
12271
- function addonComposePaths(homeDir) {
12272
- const paths = [];
12273
- for (const name of [
12274
- "channels.compose.yml",
12275
- "services.compose.yml",
12276
- "custom.compose.yml"
12277
- ]) {
12278
- const composePath = `${homeDir}/config/stack/${name}`;
12279
- if (existsSync(composePath)) paths.push(composePath);
12280
- }
12281
- return paths;
12290
+ function resolveComposeProjectName(envOverrides = {}) {
12291
+ return envOverrides.OP_PROJECT_NAME?.trim() || envOverrides.COMPOSE_PROJECT_NAME?.trim() || process.env.OP_PROJECT_NAME?.trim() || process.env.COMPOSE_PROJECT_NAME?.trim() || "openpalm";
12282
12292
  }
12283
12293
  /**
12284
- * Check if a service name is allowed. Core services are always allowed.
12285
- * Addon services are allowed if they appear as a compose service defined in
12286
- * any active addon compose file. This is compose-derived: the actual compose
12287
- * content is checked, not directory naming conventions.
12294
+ * Decide whether a running compose project (identified by its
12295
+ * `com.docker.compose.project.working_dir` label) is OURS i.e. was launched
12296
+ * from this install's working dir. An empty/unknown label can't prove foreign,
12297
+ * so it counts as ours (reconcile rather than wrongly refuse a redeploy).
12298
+ *
12299
+ * Pure decision split out from detectExistingProject so the ours-vs-foreign
12300
+ * rule is unit-testable without a Docker daemon.
12288
12301
  */
12289
- function isAllowedService(value, configDir) {
12290
- if (!value || !value.trim() || value !== value.toLowerCase()) return false;
12291
- if (CORE_SERVICES.includes(value)) return true;
12292
- if (configDir) {
12293
- const homeDir = dirname(configDir);
12294
- for (const composePath of addonComposePaths(homeDir)) try {
12295
- const doc = (0, import_dist.parse)(readFileSync(composePath, "utf-8"));
12296
- if (typeof doc === "object" && doc !== null) {
12297
- const services = doc.services;
12298
- if (typeof services === "object" && services !== null && value in services) return true;
12299
- }
12300
- } catch {
12301
- continue;
12302
- }
12303
- }
12304
- return false;
12302
+ function isProjectOurs(workingDirLabel, expectedWorkingDir) {
12303
+ const label = workingDirLabel.trim();
12304
+ return label === "" || label === expectedWorkingDir;
12305
12305
  }
12306
- //#endregion
12307
- //#region ../lib/src/control-plane/provider-models.ts
12308
12306
  /**
12309
- * Provider model discovery and API key resolution.
12307
+ * Probe the Docker daemon for a running compose project that shares
12308
+ * `projectName`. Decides ours-vs-foreign by comparing the project's
12309
+ * `com.docker.compose.project.working_dir` label against `expectedWorkingDir`
12310
+ * (the install's OP_HOME / compose context).
12310
12311
  *
12311
- * Used by the admin capabilities test endpoint and the CLI setup wizard
12312
- * to enumerate the models a configured provider exposes.
12312
+ * Returns `{ exists:false }` on any docker error (daemon down, no permission) —
12313
+ * detection is best-effort and never blocks the caller; a real failure surfaces
12314
+ * later through composeUp.
12313
12315
  */
12314
- /** Static model list for Anthropic (no listing API available). */
12315
- var ANTHROPIC_MODELS = [
12316
- "claude-opus-4-6",
12317
- "claude-sonnet-4-6",
12318
- "claude-opus-4-20250514",
12319
- "claude-sonnet-4-20250514",
12320
- "claude-haiku-4-5-20251001",
12321
- "claude-3-5-sonnet-20241022",
12322
- "claude-3-5-haiku-20241022"
12323
- ];
12316
+ function detectExistingProject(opts) {
12317
+ const none = {
12318
+ exists: false,
12319
+ isOurs: false,
12320
+ workingDir: ""
12321
+ };
12322
+ return new Promise((resolve) => {
12323
+ execFile("docker", [
12324
+ "ps",
12325
+ "-q",
12326
+ "--filter",
12327
+ `label=com.docker.compose.project=${opts.projectName}`
12328
+ ], { timeout: 1e4 }, (err, stdout) => {
12329
+ if (err) return resolve(none);
12330
+ const ids = stdout.toString().trim().split(/\s+/).filter(Boolean);
12331
+ if (ids.length === 0) return resolve(none);
12332
+ execFile("docker", [
12333
+ "inspect",
12334
+ "--format",
12335
+ "{{ index .Config.Labels \"com.docker.compose.project.working_dir\" }}",
12336
+ ids[0]
12337
+ ], { timeout: 1e4 }, (err2, stdout2) => {
12338
+ if (err2) return resolve({
12339
+ exists: true,
12340
+ isOurs: false,
12341
+ workingDir: ""
12342
+ });
12343
+ const workingDir = stdout2.toString().trim();
12344
+ resolve({
12345
+ exists: true,
12346
+ isOurs: isProjectOurs(workingDir, opts.expectedWorkingDir),
12347
+ workingDir
12348
+ });
12349
+ });
12350
+ });
12351
+ });
12352
+ }
12353
+ /** Check if Docker is available */
12354
+ async function checkDocker() {
12355
+ return new Promise((resolve) => {
12356
+ execFile("docker", [
12357
+ "info",
12358
+ "--format",
12359
+ "{{.ServerVersion}}"
12360
+ ], (error, stdout, stderr) => {
12361
+ const stdoutStr = stdout?.toString().trim() ?? "";
12362
+ const stderrStr = stderr?.toString() ?? "";
12363
+ resolve({
12364
+ ok: stdoutStr.length > 0 || !error,
12365
+ stdout: stdoutStr,
12366
+ stderr: stderrStr,
12367
+ code: error?.code ? Number(error.code) : 0
12368
+ });
12369
+ });
12370
+ });
12371
+ }
12372
+ /** Check if docker compose is available */
12373
+ async function checkDockerCompose() {
12374
+ return new Promise((resolve) => {
12375
+ execFile("docker", ["compose", "version"], (error, stdout, stderr) => {
12376
+ resolve({
12377
+ ok: !error,
12378
+ stdout: stdout?.toString() ?? "",
12379
+ stderr: stderr?.toString() ?? "",
12380
+ code: error?.code ? Number(error.code) : 0
12381
+ });
12382
+ });
12383
+ });
12384
+ }
12385
+ /** Build common prefix: compose -f ... --project-name ... --env-file ... --profile ... */
12386
+ function buildComposeArgs(options) {
12387
+ const envOverrides = collectEnvOverrides(options.envFiles);
12388
+ const args = [
12389
+ "compose",
12390
+ ...options.files.flatMap((f) => ["-f", f]),
12391
+ "--project-name",
12392
+ resolveComposeProjectName(envOverrides)
12393
+ ];
12394
+ for (const ef of options.envFiles ?? []) if (existsSync(ef)) args.push("--env-file", ef);
12395
+ for (const p of options.profiles ?? []) args.push("--profile", p);
12396
+ return args;
12397
+ }
12398
+ /** Merge all env files into a single overrides object for process env. */
12399
+ function collectEnvOverrides(envFiles) {
12400
+ const overrides = {};
12401
+ for (const ef of envFiles ?? []) Object.assign(overrides, parseEnvFile(ef));
12402
+ return overrides;
12403
+ }
12324
12404
  /**
12325
- * Resolve an API key reference.
12326
- *
12327
- * - Empty input → empty string.
12328
- * - `env:NAME` form → looks up `NAME` in `process.env` first, then falls back
12329
- * to `knowledge/secrets/<NAME>` resolved against `stackDir`.
12330
- * - Anything else → returned verbatim (treated as a literal key value).
12405
+ * Run `docker compose config` to validate compose file merge and variable substitution.
12406
+ * Must be called before any lifecycle mutation (install/apply/update).
12331
12407
  */
12332
- function resolveApiKey(apiKeyRef, stackDir) {
12333
- if (!apiKeyRef) return "";
12334
- if (!apiKeyRef.startsWith("env:")) return apiKeyRef;
12335
- const varName = apiKeyRef.slice(4);
12336
- if (process.env[varName]) return process.env[varName];
12337
- return readStackRuntimeEnv(stackDir)[varName] ?? "";
12408
+ async function composePreflight(options) {
12409
+ const args = buildComposeArgs(options);
12410
+ args.push("config", "--quiet");
12411
+ return run$1(args, void 0, 3e4, collectEnvOverrides(options.envFiles));
12338
12412
  }
12339
- var HTTP_STATUS_LABELS = {
12340
- 401: "Invalid or missing API key",
12341
- 403: "Access denied — check API key permissions",
12342
- 404: "Endpoint not found — verify the base URL",
12343
- 429: "Rate limited — try again shortly",
12344
- 500: "Provider internal error",
12345
- 502: "Provider returned a bad gateway error",
12346
- 503: "Provider is temporarily unavailable"
12347
- };
12348
12413
  /**
12349
- * Enumerate available models for a provider. Returns an `ok` result with a
12350
- * sorted model list when the provider responds successfully, or a
12351
- * `recoverable_error` with a structured reason otherwise. Network and timeout
12352
- * failures are caught and mapped to a result rather than thrown.
12414
+ * Run compose config preflight validation before any mutation.
12415
+ * Skipped when OP_SKIP_COMPOSE_PREFLIGHT is set (tests, CI).
12353
12416
  */
12354
- async function fetchProviderModels(provider, apiKeyRef, baseUrl, stackDir) {
12355
- try {
12356
- if (provider === "anthropic") return {
12357
- models: [...ANTHROPIC_MODELS],
12358
- status: "ok",
12359
- reason: "provider_static"
12360
- };
12361
- const resolvedKey = resolveApiKey(apiKeyRef, stackDir);
12362
- if (provider === "ollama") {
12363
- const url = `${(baseUrl?.trim() || PROVIDER_DEFAULT_URLS.ollama).replace(/\/+$/, "")}/api/tags`;
12364
- const res = await fetch(url, { signal: AbortSignal.timeout(5e3) });
12365
- if (!res.ok) return {
12366
- models: [],
12367
- status: "recoverable_error",
12368
- reason: "provider_http",
12369
- error: `Ollama API returned ${res.status}: ${HTTP_STATUS_LABELS[res.status] ?? `HTTP ${res.status}`}`
12370
- };
12371
- return {
12372
- models: ((await res.json()).models ?? []).map((m) => m.name).sort(),
12373
- status: "ok",
12374
- reason: "none"
12375
- };
12376
- }
12377
- const base = baseUrl?.trim() || PROVIDER_DEFAULT_URLS[provider] || "";
12378
- if (!base) return {
12379
- models: [],
12380
- status: "recoverable_error",
12381
- reason: "missing_base_url",
12382
- error: `No base URL configured for provider "${provider}"`
12383
- };
12384
- const url = `${base.replace(/\/+$/, "")}/v1/models`;
12385
- const headers = {};
12386
- if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
12387
- const res = await fetch(url, {
12388
- headers,
12389
- signal: AbortSignal.timeout(5e3)
12390
- });
12391
- if (!res.ok) {
12392
- let detail = "";
12393
- try {
12394
- const json = JSON.parse(await res.text());
12395
- const errObj = json.error;
12396
- detail = typeof errObj === "object" && errObj !== null && typeof errObj.message === "string" ? errObj.message : typeof errObj === "string" ? errObj : typeof json.message === "string" ? json.message : typeof json.detail === "string" ? json.detail : "";
12397
- } catch {}
12398
- return {
12399
- models: [],
12400
- status: "recoverable_error",
12401
- reason: "provider_http",
12402
- error: detail ? `Provider API returned ${res.status}: ${detail}` : `Provider API returned ${res.status}: ${HTTP_STATUS_LABELS[res.status] ?? `HTTP ${res.status}`}`
12403
- };
12404
- }
12405
- return {
12406
- models: ((await res.json()).data ?? []).map((m) => m.id).sort(),
12407
- status: "ok",
12408
- reason: "none"
12409
- };
12410
- } catch (err) {
12411
- const message = err instanceof Error && err.name === "TimeoutError" ? "Request timed out after 5s" : String(err);
12412
- return {
12413
- models: [],
12414
- status: "recoverable_error",
12415
- reason: err instanceof Error && err.name === "TimeoutError" ? "timeout" : "network",
12416
- error: message
12417
- };
12417
+ async function runPreflight(options) {
12418
+ if (options.files.length === 0 || process.env.OP_SKIP_COMPOSE_PREFLIGHT) return;
12419
+ const result = await composePreflight(options);
12420
+ if (!result.ok) {
12421
+ const project = resolveComposeProjectName(collectEnvOverrides(options.envFiles));
12422
+ const fileArgs = options.files.map((f) => `-f ${f}`).join(" ");
12423
+ const envArgs = (options.envFiles ?? []).map((f) => `--env-file ${f}`).join(" ");
12424
+ const profileArgs = (options.profiles ?? []).map((p) => `--profile ${p}`).join(" ");
12425
+ throw new Error(`Compose preflight failed: ${result.stderr}\nResolved command: docker compose ${fileArgs} --project-name ${project} ${envArgs} ${profileArgs} config --quiet`);
12418
12426
  }
12419
12427
  }
12420
- //#endregion
12421
- //#region ../lib/src/control-plane/fs-atomic.ts
12428
+ async function composeConfigServices(options) {
12429
+ const args = buildComposeArgs(options);
12430
+ args.push("config", "--services");
12431
+ const result = await run$1(args, void 0, 3e4, collectEnvOverrides(options.envFiles));
12432
+ if (!result.ok) return {
12433
+ ok: false,
12434
+ services: []
12435
+ };
12436
+ return {
12437
+ ok: true,
12438
+ services: result.stdout.split("\n").map((s) => s.trim()).filter(Boolean)
12439
+ };
12440
+ }
12422
12441
  /**
12423
- * Write a file atomically: write to `${path}.tmp` then rename over the target.
12424
- * The rename is atomic on the same filesystem, so readers never observe a
12425
- * partially written file. `mode` (e.g. 0o600) is applied on creation.
12426
- *
12427
- * Shared by all control-plane writers (setup, akm-sources, …) so config and
12428
- * secret files are written through one audited path — never hand-rolled.
12442
+ * Run `docker compose up -d` with the generated compose file(s).
12443
+ * Pass `files` to merge multiple compose overlays (e.g. core + addon files).
12429
12444
  */
12430
- function writeFileAtomic(path, content, mode) {
12431
- const tmp = `${path}.tmp`;
12432
- writeFileSync(tmp, content, { mode } );
12433
- renameSync(tmp, path);
12445
+ async function composeUp(options) {
12446
+ await runPreflight(options);
12447
+ if (!existsSync(options.files[0])) return {
12448
+ ok: false,
12449
+ stdout: "",
12450
+ stderr: "Compose file not found",
12451
+ code: 1
12452
+ };
12453
+ const args = buildComposeArgs(options);
12454
+ args.push("up", "-d");
12455
+ if (options.forceRecreate) args.push("--force-recreate");
12456
+ if (options.removeOrphans) args.push("--remove-orphans");
12457
+ if (options.services?.length) args.push(...options.services);
12458
+ return run$1(args, void 0, composeUpTimeoutMs(), collectEnvOverrides(options.envFiles));
12434
12459
  }
12435
- //#endregion
12436
- //#region ../lib/src/control-plane/akm-sources.ts
12437
12460
  /**
12438
- * Host Assistant AKM source wiring (control-plane logic lives in lib).
12439
- *
12440
- * Implements the "symmetric writable secondary" design
12441
- * (docs/technical/akm-host-assistant-integration-proposal.md §8).
12442
- *
12443
- * Each akm instance keeps its OWN primary stash, data dir, and cache. Sharing
12444
- * is done purely by adding the other instance's stash as a *secondary* source
12445
- * in `config.sources[]`:
12446
- * - The OpenPalm/container config gains a `host-akm` source → /host-stash
12447
- * (the user's personal ~/akm, bind-mounted by the host-akm.compose.yml overlay).
12448
- * - The personal config gains an `openpalm` source → OP_HOME/knowledge.
12449
- *
12450
- * VERIFIED against akm 0.8.0 (rc.13 → stable; schema unchanged):
12451
- * - `SourceConfigEntrySchema` (config-schema.ts:259) accepts
12452
- * { type, path?, url?, name?, enabled?, writable?, primary?, options?, wikiName? }.
12453
- * - The indexer's `resolveSourceEntries` (search-source.ts:56) ALWAYS injects the
12454
- * env-resolved primary stash (AKM_STASH_DIR) as sources[0], then appends
12455
- * config.sources[] deduped by path. So a secondary entry can never strand or
12456
- * displace the primary — provided we NEVER set `primary:true` and NEVER set
12457
- * `config.stashDir`.
12458
- * - Writes resolve to the primary unless an explicit `--target` is given
12459
- * (write-source.ts) and `defaultWriteTarget` is left unset, so a writable
12460
- * secondary is safe by construction.
12461
- *
12462
- * Invariants (enforced + unit-tested):
12463
- * - Only ever appends/updates a NAMED source (idempotent upsert by name).
12464
- * - NEVER sets `primary`, NEVER sets `defaultWriteTarget`, NEVER sets `stashDir`.
12465
- * - Atomic 0600 writes.
12466
- * - The OpenPalm config is parse-tolerant (we own it: corrupt → start from {}).
12467
- * - The PERSONAL config FAILS CLOSED (corrupt/unreadable → throw, never overwrite
12468
- * the user's file). This asymmetry is the host-data-loss guard.
12461
+ * Timeout budget for `compose up`. A first install extracts multi-GB images
12462
+ * (voice CUDA ~7.6 GB) onto slow disks; the previous hard 5-minute cap
12463
+ * SIGTERM-killed the start mid-extraction and surfaced as an empty/opaque
12464
+ * error. Default 30 min, override with OP_COMPOSE_UP_TIMEOUT_MS. Kept bounded
12465
+ * (never removed) so a genuinely hung start still eventually fails.
12469
12466
  */
12470
- /** Source entry name added to the OpenPalm/container config (points at /host-stash). */
12471
- var HOST_SOURCE_NAME = "host-akm";
12472
- function readConfigTolerant(configPath) {
12473
- if (!existsSync(configPath)) return {};
12474
- try {
12475
- const parsed = JSON.parse(readFileSync(configPath, "utf-8"));
12476
- return parsed && typeof parsed === "object" ? parsed : {};
12477
- } catch {
12478
- return {};
12479
- }
12480
- }
12481
- function readConfigFailClosed(configPath) {
12482
- if (!existsSync(configPath)) throw new Error(`Personal akm config not found at ${configPath}; refusing to create it. Run \`akm init\`/\`akm setup\` first, then enable host AKM sharing.`);
12483
- let text;
12484
- try {
12485
- text = readFileSync(configPath, "utf-8");
12486
- } catch (err) {
12487
- throw new Error(`Unable to read personal akm config at ${configPath}: ${err.message}`);
12488
- }
12489
- let parsed;
12490
- try {
12491
- parsed = JSON.parse(text);
12492
- } catch {
12493
- throw new Error(`Personal akm config at ${configPath} is not valid JSON; refusing to overwrite it. Fix the file by hand, then retry.`);
12494
- }
12495
- if (!parsed || typeof parsed !== "object") throw new Error(`Personal akm config at ${configPath} is not a JSON object; refusing to overwrite it.`);
12496
- return parsed;
12467
+ function composeUpTimeoutMs() {
12468
+ const raw = process.env.OP_COMPOSE_UP_TIMEOUT_MS?.trim();
12469
+ const parsed = raw ? Number(raw) : NaN;
12470
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
12471
+ return 30 * 6e4;
12497
12472
  }
12498
12473
  /**
12499
- * Upsert a named filesystem source into `config.sources[]` by name. Idempotent.
12500
- * NEVER touches `primary`, `defaultWriteTarget`, or `stashDir`.
12474
+ * Run `docker compose down` to stop and remove containers.
12501
12475
  */
12502
- function upsertSource(config, entry) {
12503
- const sources = Array.isArray(config.sources) ? [...config.sources] : [];
12504
- const idx = sources.findIndex((s) => s && typeof s === "object" && s.name === entry.name);
12505
- if (idx >= 0) sources[idx] = {
12506
- ...sources[idx],
12507
- ...entry
12508
- };
12509
- else sources.push(entry);
12510
- return {
12511
- ...config,
12512
- sources
12476
+ async function composeDown(options) {
12477
+ await runPreflight(options);
12478
+ if (!existsSync(options.files[0])) return {
12479
+ ok: false,
12480
+ stdout: "",
12481
+ stderr: "Compose file not found",
12482
+ code: 1
12513
12483
  };
12484
+ const args = buildComposeArgs(options);
12485
+ args.push("down");
12486
+ if (options.removeVolumes) args.push("-v");
12487
+ if (options.removeOrphans) args.push("--remove-orphans");
12488
+ return run$1(args, void 0);
12514
12489
  }
12515
- function removeSource(config, name) {
12516
- if (!Array.isArray(config.sources)) return config;
12517
- const sources = config.sources.filter((s) => !(s && typeof s === "object" && s.name === name));
12518
- return {
12519
- ...config,
12520
- sources
12490
+ /**
12491
+ * Restart specific services.
12492
+ */
12493
+ async function composeRestart(services, options) {
12494
+ await runPreflight(options);
12495
+ const primaryFile = options.files[0];
12496
+ if (!existsSync(primaryFile)) return {
12497
+ ok: false,
12498
+ stdout: "",
12499
+ stderr: "Compose file not found",
12500
+ code: 1
12521
12501
  };
12502
+ const args = buildComposeArgs(options);
12503
+ args.push("restart", ...services);
12504
+ return run$1(args, void 0);
12522
12505
  }
12523
- function assertNoPrimaryEscalation(entry) {
12524
- if (entry.primary !== void 0) throw new Error("akm-sources: refusing to write a source entry carrying `primary`.");
12525
- }
12526
- function openpalmConfigPath(state) {
12527
- return join(state.configDir, "akm", "config.json");
12506
+ /**
12507
+ * Stop specific services.
12508
+ */
12509
+ async function composeStop(services, options) {
12510
+ await runPreflight(options);
12511
+ const args = buildComposeArgs(options);
12512
+ args.push("stop", ...services);
12513
+ return run$1(args, void 0);
12528
12514
  }
12529
12515
  /**
12530
- * Container/OpenPalm side: add the personal stash (mounted at /host-stash) as a
12531
- * secondary source. Parse-tolerant (we own this config). Writable by default so
12532
- * the assistant can contribute back via an explicit `--target host-akm`.
12516
+ * Start specific services (must already be created).
12533
12517
  */
12534
- function addHostStashToOpenpalmConfig(state, writable = true) {
12535
- const configPath = openpalmConfigPath(state);
12536
- const entry = {
12537
- type: "filesystem",
12538
- path: "/host-stash",
12539
- name: HOST_SOURCE_NAME,
12540
- writable,
12541
- enabled: true
12542
- };
12543
- assertNoPrimaryEscalation(entry);
12544
- const updated = upsertSource(readConfigTolerant(configPath), entry);
12545
- writeFileAtomic(configPath, JSON.stringify(updated, null, 2), 384);
12518
+ async function composeStart(services, options) {
12519
+ await runPreflight(options);
12520
+ const args = buildComposeArgs(options);
12521
+ args.push("up", "-d", ...services);
12522
+ return run$1(args, void 0);
12546
12523
  }
12547
12524
  /**
12548
- * Remove the `host-akm` secondary source from the assistant config (disable
12549
- * sharing). Parse-tolerant; never touches the user's personal config (D1 —
12550
- * host sharing is assistant-reads-host only). Idempotent.
12525
+ * Get the status of all containers in the project.
12551
12526
  */
12552
- function removeHostAkmSource(state) {
12553
- const opPath = openpalmConfigPath(state);
12554
- const opConfig = readConfigTolerant(opPath);
12555
- writeFileAtomic(opPath, JSON.stringify(removeSource(opConfig, HOST_SOURCE_NAME), null, 2), 384);
12527
+ async function composePs(options) {
12528
+ const primaryFile = options.files[0];
12529
+ if (!existsSync(primaryFile)) return run$1([
12530
+ "ps",
12531
+ "--filter",
12532
+ `label=com.docker.compose.project=${resolveComposeProjectName()}`,
12533
+ "--format",
12534
+ "json"
12535
+ ], void 0);
12536
+ const args = buildComposeArgs(options);
12537
+ args.push("ps", "--format", "json");
12538
+ return run$1(args, void 0);
12556
12539
  }
12557
12540
  /**
12558
- * Read-only snapshot import of the host's reusable akm config into the OpenPalm
12559
- * config. Reads the personal config READ-ONLY; never writes back to the host.
12560
- *
12561
- * ADDITIVE MERGE: existing OpenPalm values ALWAYS win — the host only fills gaps.
12562
- * A profile name, default selection, or embedding field that OpenPalm already has
12563
- * is never overwritten; host-only profiles/fields are added. Covers the
12564
- * LLM/agent/improve PROFILES (+ their `defaults.*`) and the top-level `embedding`
12565
- * connection. Returns which sections actually gained values.
12566
- *
12567
- * Writes the canonical akm 0.8.0 shape (profiles.* + defaults.* + embedding) —
12568
- * never the legacy top-level `llm` (see I-3). NEVER touches `sources`, `stashDir`,
12569
- * `registries`, or `installed`.
12541
+ * Get logs for specific services or all services.
12570
12542
  */
12571
- function importHostProfiles(state, hostConfigPath) {
12572
- const host = readConfigFailClosed(hostConfigPath);
12573
- const hostProfiles = host.profiles ?? {};
12574
- const hostDefaults = host.defaults ?? {};
12575
- const opPath = openpalmConfigPath(state);
12576
- const op = readConfigTolerant(opPath);
12577
- const opProfiles = op.profiles ?? {};
12578
- const opDefaults = op.defaults ?? {};
12579
- const imported = [];
12580
- const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
12581
- for (const ns of [
12582
- "llm",
12583
- "agent",
12584
- "improve"
12585
- ]) {
12586
- if (isObj(hostProfiles[ns])) {
12587
- const existing = isObj(opProfiles[ns]) ? opProfiles[ns] : {};
12588
- const merged = {
12589
- ...hostProfiles[ns],
12590
- ...existing
12591
- };
12592
- const added = Object.keys(merged).length - Object.keys(existing).length;
12593
- opProfiles[ns] = merged;
12594
- if (added > 0) imported.push(`profiles.${ns}`);
12595
- }
12596
- if (typeof hostDefaults[ns] === "string" && typeof opDefaults[ns] !== "string") {
12597
- opDefaults[ns] = hostDefaults[ns];
12598
- imported.push(`defaults.${ns}`);
12599
- }
12600
- }
12601
- let embedding;
12602
- if (isObj(host.embedding)) {
12603
- const existing = isObj(op.embedding) ? op.embedding : {};
12604
- const merged = {
12605
- ...host.embedding,
12606
- ...existing
12607
- };
12608
- if (Object.keys(merged).length > Object.keys(existing).length) {
12609
- embedding = merged;
12610
- imported.push("embedding");
12611
- }
12612
- }
12613
- if (imported.length === 0) return { imported };
12614
- const updated = {
12615
- ...op,
12616
- profiles: opProfiles,
12617
- defaults: opDefaults
12618
- };
12619
- if (embedding !== void 0) updated.embedding = embedding;
12620
- delete updated.llm;
12621
- writeFileAtomic(opPath, JSON.stringify(updated, null, 2), 384);
12622
- return { imported };
12543
+ async function composeLogs(services, tail, options) {
12544
+ const args = buildComposeArgs(options);
12545
+ args.push("logs", "--tail", String(tail));
12546
+ if (options.since) args.push("--since", options.since);
12547
+ if (services && services.length > 0) args.push(...services);
12548
+ return run$1(args, void 0);
12549
+ }
12550
+ var PULL_TIMEOUT_MS = 60 * 6e4;
12551
+ async function composePull(options) {
12552
+ await runPreflight(options);
12553
+ const args = buildComposeArgs(options);
12554
+ args.push("pull");
12555
+ return run$1(args, void 0, PULL_TIMEOUT_MS, collectEnvOverrides(options.envFiles));
12623
12556
  }
12624
- //#endregion
12625
- //#region ../lib/src/control-plane/host-akm-sharing.ts
12626
12557
  /**
12627
- * Host AKM sharing (control-plane logic lives in lib).
12628
- *
12629
- * Simplified model (no compose overlay, no file-presence gating):
12630
- *
12631
- * - The assistant ALWAYS mounts `/host-stash` (core.compose.yml). When the host
12632
- * has AKM, OP_HOST_AKM_STASH points at the user's personal stash (~/akm);
12633
- * otherwise it is unset and compose falls back to an always-present empty dir.
12634
- * - "Sharing" is purely a writable SECONDARY source entry named `host-akm` →
12635
- * /host-stash in the assistant's config/akm/config.json. Adding it = enabled;
12636
- * removing it = disabled. akm resolves writes to the primary unless an explicit
12637
- * --target is given, and silently skips a source whose dir is empty/missing —
12638
- * so a mounted-but-unconfigured /host-stash is harmless.
12639
- * - Host availability is detected from the presence of the user's personal akm
12640
- * CONFIG (~/.config/akm/config.json) — the real signal that akm is initialized.
12641
- *
12642
- * Decision D1 (2026-06-03): host sharing is assistant-reads-host ONLY by default.
12643
- * We never write into the user's personal ~/.config/akm here. (Letting the host
12644
- * akm see OpenPalm's knowledge is a future, explicit opt-in.)
12558
+ * Get resource usage stats for all containers in the project.
12645
12559
  */
12646
- var logger$5 = createLogger("host-akm-sharing");
12647
- var ENV_KEY = "OP_HOST_AKM_STASH";
12648
- function userHome() {
12649
- return process.env.HOME ?? process.env.USERPROFILE ?? homedir();
12650
- }
12651
- /** The user's personal akm stash dir (mounted into the assistant at /host-stash). */
12652
- function hostAkmStashPath() {
12653
- return `${userHome()}/akm`;
12654
- }
12655
- /** The user's personal akm config file — its existence is our availability signal. */
12656
- function hostAkmConfigPath() {
12657
- return `${userHome()}/.config/akm/config.json`;
12658
- }
12659
- /** True when AKM is initialized on the host (personal config exists). */
12660
- function isHostAkmAvailable() {
12661
- return existsSync(hostAkmConfigPath());
12662
- }
12663
- function stackEnvPath(state) {
12664
- return `${state.stashDir}/env/stack.env`;
12560
+ async function composeStats(options) {
12561
+ const args = buildComposeArgs(options);
12562
+ args.push("stats", "--no-stream", "--format", "json");
12563
+ return run$1(args, void 0);
12665
12564
  }
12666
12565
  /**
12667
- * Point OP_HOST_AKM_STASH at the host stash when AKM is available, else unset it
12668
- * (compose then uses the empty-dir fallback). Pure infrastructure — does NOT
12669
- * change the source list. Idempotent; safe to call on setup and on deploy.
12566
+ * Get recent Docker events for the compose project.
12670
12567
  */
12671
- function ensureHostStashEnv(state) {
12672
- const path = stackEnvPath(state);
12673
- const existing = existsSync(path) ? readFileSync(path, "utf-8") : "";
12674
- const updated = isHostAkmAvailable() ? mergeEnvContent(existing, { [ENV_KEY]: hostAkmStashPath() }) : removeEnvKey(existing, ENV_KEY);
12675
- if (updated !== existing) writeFileAtomic(path, updated, 384);
12568
+ async function getDockerEvents(projectName, since = "1h") {
12569
+ return run$1([
12570
+ "events",
12571
+ "--filter",
12572
+ `label=com.docker.compose.project=${projectName}`,
12573
+ "--since",
12574
+ since,
12575
+ "--until",
12576
+ "now",
12577
+ "--format",
12578
+ "json"
12579
+ ], void 0, 15e3);
12676
12580
  }
12581
+ //#endregion
12582
+ //#region ../lib/src/control-plane/channels.ts
12677
12583
  /**
12678
- * Enable host AKM sharing: ensure OP_HOST_AKM_STASH points at ~/akm and add the
12679
- * writable `host-akm` secondary source to the assistant config. Optionally import
12680
- * host LLM/agent profiles (read-only). Throws if host AKM is not available.
12584
+ * Channel validation, discovery, and allowlist checks for the OpenPalm control plane.
12681
12585
  */
12682
- function enableHostAkmSharing(state, opts = {}) {
12683
- if (!isHostAkmAvailable()) throw new Error(`Host AKM is not available (no ${hostAkmConfigPath()}). Run \`akm init\` on the host first.`);
12684
- ensureHostStashEnv(state);
12685
- addHostStashToOpenpalmConfig(state, opts.writable ?? true);
12686
- let profilesImported = [];
12687
- if (opts.importProfiles) profilesImported = importHostProfiles(state, hostAkmConfigPath()).imported;
12688
- logger$5.info("host akm sharing enabled", {
12689
- hostStashPath: hostAkmStashPath(),
12690
- profilesImported
12691
- });
12692
- return { profilesImported };
12586
+ function addonComposePaths(homeDir) {
12587
+ const paths = [];
12588
+ for (const name of [
12589
+ "channels.compose.yml",
12590
+ "services.compose.yml",
12591
+ "custom.compose.yml"
12592
+ ]) {
12593
+ const composePath = `${homeDir}/config/stack/${name}`;
12594
+ if (existsSync(composePath)) paths.push(composePath);
12595
+ }
12596
+ return paths;
12693
12597
  }
12694
12598
  /**
12695
- * Disable host AKM sharing: remove the `host-akm` secondary source from the
12696
- * assistant config. Leaves the (harmless) mount and env in place; never deletes
12697
- * any stash content.
12599
+ * Check if a service name is allowed. Core services are always allowed.
12600
+ * Addon services are allowed if they appear as a compose service defined in
12601
+ * any active addon compose file. This is compose-derived: the actual compose
12602
+ * content is checked, not directory naming conventions.
12698
12603
  */
12699
- function disableHostAkmSharing(state) {
12700
- removeHostAkmSource(state);
12701
- logger$5.info("host akm sharing disabled");
12702
- }
12703
- /** Report availability + whether the host-akm source is currently configured. */
12704
- function getHostAkmSharingStatus(state) {
12705
- const available = isHostAkmAvailable();
12706
- return {
12707
- available,
12708
- enabled: openpalmHasHostSource(state),
12709
- hostStashPath: available ? hostAkmStashPath() : null
12710
- };
12711
- }
12712
- function openpalmHasHostSource(state) {
12713
- const path = `${state.configDir}/akm/config.json`;
12714
- if (!existsSync(path)) return false;
12715
- try {
12716
- const cfg = JSON.parse(readFileSync(path, "utf-8"));
12717
- return Array.isArray(cfg.sources) && cfg.sources.some((s) => s?.name === "host-akm");
12718
- } catch {
12719
- return false;
12604
+ function isAllowedService(value, configDir) {
12605
+ if (!value || !value.trim() || value !== value.toLowerCase()) return false;
12606
+ if (CORE_SERVICES.includes(value)) return true;
12607
+ if (configDir) {
12608
+ const homeDir = dirname(configDir);
12609
+ for (const composePath of addonComposePaths(homeDir)) try {
12610
+ const doc = (0, import_dist.parse)(readFileSync(composePath, "utf-8"));
12611
+ if (typeof doc === "object" && doc !== null) {
12612
+ const services = doc.services;
12613
+ if (typeof services === "object" && services !== null && value in services) return true;
12614
+ }
12615
+ } catch {
12616
+ continue;
12617
+ }
12720
12618
  }
12619
+ return false;
12721
12620
  }
12722
12621
  //#endregion
12723
- //#region ../lib/src/control-plane/rollback.ts
12622
+ //#region ../lib/src/control-plane/provider-models.ts
12724
12623
  /**
12725
- * Snapshot-based rollback for the OpenPalm control plane.
12624
+ * Provider model discovery and API key resolution.
12726
12625
  *
12727
- * Before writing validated changes to live paths, the current state
12728
- * is snapshotted to OP_HOME/data/rollback/. On deploy failure
12729
- * (or manual `openpalm rollback`), the snapshot is restored.
12626
+ * Used by the admin capabilities test endpoint and the CLI setup wizard
12627
+ * to enumerate the models a configured provider exposes.
12730
12628
  */
12731
- /** Files that are tracked for rollback (relative to homeDir).
12732
- * Only config/ system files are included — user-editable config files
12733
- * are never overwritten by lifecycle operations. */
12734
- var SNAPSHOT_FILES = [
12735
- "knowledge/env/stack.env",
12736
- "config/stack/services.compose.yml",
12737
- "config/stack/channels.compose.yml",
12738
- "config/stack/custom.compose.yml",
12739
- "knowledge/secrets/auth.json"
12629
+ /** Static model list for Anthropic (no listing API available). */
12630
+ var ANTHROPIC_MODELS = [
12631
+ "claude-opus-4-6",
12632
+ "claude-sonnet-4-6",
12633
+ "claude-opus-4-20250514",
12634
+ "claude-sonnet-4-20250514",
12635
+ "claude-haiku-4-5-20251001",
12636
+ "claude-3-5-sonnet-20241022",
12637
+ "claude-3-5-haiku-20241022"
12740
12638
  ];
12741
12639
  /**
12742
- * Copy a file if it exists, creating parent directories as needed.
12640
+ * Resolve an API key reference.
12641
+ *
12642
+ * - Empty input → empty string.
12643
+ * - `env:NAME` form → looks up `NAME` in `process.env` first, then falls back
12644
+ * to `knowledge/secrets/<NAME>` resolved against `stackDir`.
12645
+ * - Anything else → returned verbatim (treated as a literal key value).
12743
12646
  */
12744
- function safeCopy(src, dest) {
12745
- if (!existsSync(src)) return;
12746
- mkdirSync(dirname(dest), { recursive: true });
12747
- copyFileSync(src, dest);
12647
+ function resolveApiKey(apiKeyRef, stackDir) {
12648
+ if (!apiKeyRef) return "";
12649
+ if (!apiKeyRef.startsWith("env:")) return apiKeyRef;
12650
+ const varName = apiKeyRef.slice(4);
12651
+ if (process.env[varName]) return process.env[varName];
12652
+ return readStackRuntimeEnv(stackDir)[varName] ?? "";
12748
12653
  }
12654
+ var HTTP_STATUS_LABELS = {
12655
+ 401: "Invalid or missing API key",
12656
+ 403: "Access denied — check API key permissions",
12657
+ 404: "Endpoint not found — verify the base URL",
12658
+ 429: "Rate limited — try again shortly",
12659
+ 500: "Provider internal error",
12660
+ 502: "Provider returned a bad gateway error",
12661
+ 503: "Provider is temporarily unavailable"
12662
+ };
12749
12663
  /**
12750
- * Save the current live configuration files to the rollback directory.
12751
- * Also snapshots stack/core.compose.yml.
12664
+ * Enumerate available models for a provider. Returns an `ok` result with a
12665
+ * sorted model list when the provider responds successfully, or a
12666
+ * `recoverable_error` with a structured reason otherwise. Network and timeout
12667
+ * failures are caught and mapped to a result rather than thrown.
12752
12668
  */
12753
- function snapshotCurrentState(state) {
12754
- const rollbackDir = resolveRollbackDir();
12755
- mkdirSync(rollbackDir, { recursive: true });
12756
- for (const rel of SNAPSHOT_FILES) safeCopy(join(state.homeDir, rel), join(rollbackDir, rel));
12757
- safeCopy(join(state.homeDir, "config/stack/core.compose.yml"), join(rollbackDir, "config/stack/core.compose.yml"));
12758
- writeFileSync(join(rollbackDir, ".snapshot-ts"), (/* @__PURE__ */ new Date()).toISOString() + "\n");
12759
- }
12760
- //#endregion
12761
- //#region ../lib/src/control-plane/secret-mappings.ts
12762
- var STATIC_CORE_MAPPINGS = [
12763
- {
12764
- secretKey: "openpalm/ui-login-password",
12765
- envKey: "OP_UI_LOGIN_PASSWORD",
12766
- scope: "system"
12767
- },
12768
- {
12769
- secretKey: "openpalm/opencode/server-password",
12770
- envKey: "OP_OPENCODE_PASSWORD",
12771
- scope: "system"
12772
- },
12773
- {
12774
- secretKey: "openpalm/openai/api-key",
12775
- envKey: "OPENAI_API_KEY",
12776
- scope: "user"
12777
- },
12778
- {
12779
- secretKey: "openpalm/anthropic/api-key",
12780
- envKey: "ANTHROPIC_API_KEY",
12781
- scope: "user"
12782
- },
12783
- {
12784
- secretKey: "openpalm/groq/api-key",
12785
- envKey: "GROQ_API_KEY",
12786
- scope: "user"
12787
- },
12788
- {
12789
- secretKey: "openpalm/mistral/api-key",
12790
- envKey: "MISTRAL_API_KEY",
12791
- scope: "user"
12792
- },
12793
- {
12794
- secretKey: "openpalm/google/api-key",
12795
- envKey: "GOOGLE_API_KEY",
12796
- scope: "user"
12797
- },
12798
- {
12799
- secretKey: "openpalm/together/api-key",
12800
- envKey: "TOGETHER_API_KEY",
12801
- scope: "user"
12802
- },
12803
- {
12804
- secretKey: "openpalm/deepseek/api-key",
12805
- envKey: "DEEPSEEK_API_KEY",
12806
- scope: "user"
12807
- },
12808
- {
12809
- secretKey: "openpalm/xai/api-key",
12810
- envKey: "XAI_API_KEY",
12811
- scope: "user"
12812
- },
12813
- {
12814
- secretKey: "openpalm/huggingface/token",
12815
- envKey: "HF_TOKEN",
12816
- scope: "user"
12817
- },
12818
- {
12819
- secretKey: "openpalm/mcp/api-key",
12820
- envKey: "MCP_API_KEY",
12821
- scope: "user"
12822
- },
12823
- {
12824
- secretKey: "openpalm/embedding/api-key",
12825
- envKey: "EMBEDDING_API_KEY",
12826
- scope: "user"
12827
- },
12828
- {
12829
- secretKey: "openpalm/lmstudio/api-key",
12830
- envKey: "LMSTUDIO_API_KEY",
12831
- scope: "user"
12832
- },
12833
- {
12834
- secretKey: "openpalm/discord/bot-token",
12835
- envKey: "DISCORD_BOT_TOKEN",
12836
- scope: "user"
12837
- },
12838
- {
12839
- secretKey: "openpalm/slack/bot-token",
12840
- envKey: "SLACK_BOT_TOKEN",
12841
- scope: "user"
12842
- },
12843
- {
12844
- secretKey: "openpalm/slack/app-token",
12845
- envKey: "SLACK_APP_TOKEN",
12846
- scope: "user"
12847
- },
12848
- {
12849
- secretKey: "openpalm/voice/stt-api-key",
12850
- envKey: "STT_API_KEY",
12851
- scope: "user"
12852
- },
12853
- {
12854
- secretKey: "openpalm/voice/tts-api-key",
12855
- envKey: "TTS_API_KEY",
12856
- scope: "user"
12857
- }
12858
- ];
12859
- function getCoreSecretMappings(systemEnv) {
12860
- const dynamicMappings = [];
12861
- for (const envKey of Object.keys(systemEnv)) {
12862
- const match = envKey.match(/^CHANNEL_([A-Z0-9_]+)_SECRET$/);
12863
- if (!match?.[1]) continue;
12864
- dynamicMappings.push({
12865
- secretKey: `openpalm/channel/${match[1].toLowerCase()}/secret`,
12866
- envKey,
12867
- scope: "system"
12669
+ async function fetchProviderModels(provider, apiKeyRef, baseUrl, stackDir) {
12670
+ try {
12671
+ if (provider === "anthropic") return {
12672
+ models: [...ANTHROPIC_MODELS],
12673
+ status: "ok",
12674
+ reason: "provider_static"
12675
+ };
12676
+ const resolvedKey = resolveApiKey(apiKeyRef, stackDir);
12677
+ if (provider === "ollama") {
12678
+ const url = `${(baseUrl?.trim() || PROVIDER_DEFAULT_URLS.ollama).replace(/\/+$/, "")}/api/tags`;
12679
+ const res = await fetch(url, { signal: AbortSignal.timeout(5e3) });
12680
+ if (!res.ok) return {
12681
+ models: [],
12682
+ status: "recoverable_error",
12683
+ reason: "provider_http",
12684
+ error: `Ollama API returned ${res.status}: ${HTTP_STATUS_LABELS[res.status] ?? `HTTP ${res.status}`}`
12685
+ };
12686
+ return {
12687
+ models: ((await res.json()).models ?? []).map((m) => m.name).sort(),
12688
+ status: "ok",
12689
+ reason: "none"
12690
+ };
12691
+ }
12692
+ const base = baseUrl?.trim() || PROVIDER_DEFAULT_URLS[provider] || "";
12693
+ if (!base) return {
12694
+ models: [],
12695
+ status: "recoverable_error",
12696
+ reason: "missing_base_url",
12697
+ error: `No base URL configured for provider "${provider}"`
12698
+ };
12699
+ const url = `${base.replace(/\/+$/, "")}/v1/models`;
12700
+ const headers = {};
12701
+ if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
12702
+ const res = await fetch(url, {
12703
+ headers,
12704
+ signal: AbortSignal.timeout(5e3)
12868
12705
  });
12706
+ if (!res.ok) {
12707
+ let detail = "";
12708
+ try {
12709
+ const json = JSON.parse(await res.text());
12710
+ const errObj = json.error;
12711
+ detail = typeof errObj === "object" && errObj !== null && typeof errObj.message === "string" ? errObj.message : typeof errObj === "string" ? errObj : typeof json.message === "string" ? json.message : typeof json.detail === "string" ? json.detail : "";
12712
+ } catch {}
12713
+ return {
12714
+ models: [],
12715
+ status: "recoverable_error",
12716
+ reason: "provider_http",
12717
+ error: detail ? `Provider API returned ${res.status}: ${detail}` : `Provider API returned ${res.status}: ${HTTP_STATUS_LABELS[res.status] ?? `HTTP ${res.status}`}`
12718
+ };
12719
+ }
12720
+ return {
12721
+ models: ((await res.json()).data ?? []).map((m) => m.id).sort(),
12722
+ status: "ok",
12723
+ reason: "none"
12724
+ };
12725
+ } catch (err) {
12726
+ const message = err instanceof Error && err.name === "TimeoutError" ? "Request timed out after 5s" : String(err);
12727
+ return {
12728
+ models: [],
12729
+ status: "recoverable_error",
12730
+ reason: err instanceof Error && err.name === "TimeoutError" ? "timeout" : "network",
12731
+ error: message
12732
+ };
12869
12733
  }
12870
- return [...STATIC_CORE_MAPPINGS, ...dynamicMappings];
12871
12734
  }
12872
12735
  //#endregion
12873
- //#region ../lib/src/control-plane/validate.ts
12736
+ //#region ../lib/src/control-plane/fs-atomic.ts
12874
12737
  /**
12875
- * Runtime configuration validation for the OpenPalm control plane.
12738
+ * Write a file atomically: write to `${path}.tmp` then rename over the target.
12739
+ * The rename is atomic on the same filesystem, so readers never observe a
12740
+ * partially written file. `mode` (e.g. 0o600) is applied on creation.
12876
12741
  *
12877
- * Validation is a presence check on the canonical env keys we expect in
12878
- * the live config/stack files. The
12879
- * historical schema files and external validation binary were retired in
12880
- * #391; everything advisory is surfaced as a non-blocking warning. The
12881
- * function never shells out and never reads schemas.
12742
+ * Shared by all control-plane writers (setup, akm-sources, …) so config and
12743
+ * secret files are written through one audited path — never hand-rolled.
12882
12744
  */
12883
- var REQUIRED_SECRET_KEYS = ["OP_UI_LOGIN_PASSWORD"];
12745
+ function writeFileAtomic(path, content, mode) {
12746
+ const tmp = `${path}.tmp`;
12747
+ writeFileSync(tmp, content, { mode } );
12748
+ renameSync(tmp, path);
12749
+ }
12750
+ //#endregion
12751
+ //#region ../lib/src/control-plane/akm-sources.ts
12884
12752
  /**
12885
- * Validate the live configuration files.
12753
+ * Host Assistant AKM source wiring (control-plane logic — lives in lib).
12886
12754
  *
12887
- * Checks:
12888
- * 1. knowledge/env/stack.env exists and carries every required key with a
12889
- * non-empty value.
12890
- * 2. Every secret env key in getCoreSecretMappings() is present (key only
12891
- * — blank values are warned about, never erred on, because operators
12892
- * may opt out of providers they don't use).
12755
+ * Implements the "symmetric writable secondary" design
12756
+ * (docs/technical/akm-host-assistant-integration-proposal.md §8).
12893
12757
  *
12894
- * Errors fail the result. Warnings do not. The function never reads
12895
- * schema files and never spawns subprocesses.
12758
+ * Each akm instance keeps its OWN primary stash, data dir, and cache. Sharing
12759
+ * is done purely by adding the other instance's stash as a *secondary* source
12760
+ * in `config.sources[]`:
12761
+ * - The OpenPalm/container config gains a `host-akm` source → /host-stash
12762
+ * (the user's personal ~/akm, bind-mounted by the host-akm.compose.yml overlay).
12763
+ * - The personal config gains an `openpalm` source → OP_HOME/knowledge.
12764
+ *
12765
+ * VERIFIED against akm 0.8.0 (rc.13 → stable; schema unchanged):
12766
+ * - `SourceConfigEntrySchema` (config-schema.ts:259) accepts
12767
+ * { type, path?, url?, name?, enabled?, writable?, primary?, options?, wikiName? }.
12768
+ * - The indexer's `resolveSourceEntries` (search-source.ts:56) ALWAYS injects the
12769
+ * env-resolved primary stash (AKM_STASH_DIR) as sources[0], then appends
12770
+ * config.sources[] deduped by path. So a secondary entry can never strand or
12771
+ * displace the primary — provided we NEVER set `primary:true` and NEVER set
12772
+ * `config.stashDir`.
12773
+ * - Writes resolve to the primary unless an explicit `--target` is given
12774
+ * (write-source.ts) and `defaultWriteTarget` is left unset, so a writable
12775
+ * secondary is safe by construction.
12776
+ *
12777
+ * Invariants (enforced + unit-tested):
12778
+ * - Only ever appends/updates a NAMED source (idempotent upsert by name).
12779
+ * - NEVER sets `primary`, NEVER sets `defaultWriteTarget`, NEVER sets `stashDir`.
12780
+ * - Atomic 0600 writes.
12781
+ * - The OpenPalm config is parse-tolerant (we own it: corrupt → start from {}).
12782
+ * - The PERSONAL config FAILS CLOSED (corrupt/unreadable → throw, never overwrite
12783
+ * the user's file). This asymmetry is the host-data-loss guard.
12896
12784
  */
12897
- async function validateProposedState(state) {
12898
- const errors = [];
12899
- const warnings = [];
12900
- const stackEnvPath = `${state.stashDir}/env/stack.env`;
12901
- if (!existsSync(stackEnvPath)) {
12902
- errors.push(`ERROR: stack env file missing at ${stackEnvPath}`);
12903
- return {
12904
- ok: false,
12905
- errors,
12906
- warnings
12907
- };
12908
- }
12909
- const runtimeEnv = readStackRuntimeEnv(state.stackDir);
12910
- for (const key of REQUIRED_SECRET_KEYS) {
12911
- const value = runtimeEnv[key];
12912
- if (!value || value.trim().length === 0) errors.push(`ERROR: required secret ${key} is missing or empty in knowledge/secrets/${key.toLowerCase()}`);
12785
+ /** Source entry name added to the OpenPalm/container config (points at /host-stash). */
12786
+ var HOST_SOURCE_NAME = "host-akm";
12787
+ function readConfigTolerant(configPath) {
12788
+ if (!existsSync(configPath)) return {};
12789
+ try {
12790
+ const parsed = JSON.parse(readFileSync(configPath, "utf-8"));
12791
+ return parsed && typeof parsed === "object" ? parsed : {};
12792
+ } catch {
12793
+ return {};
12913
12794
  }
12914
- for (const mapping of getCoreSecretMappings(runtimeEnv)) if (!Object.prototype.hasOwnProperty.call(runtimeEnv, mapping.envKey)) warnings.push(`WARN: ${mapping.envKey} (akm ${mapping.secretKey}) is not declared in knowledge/secrets/${mapping.envKey.toLowerCase()}`);
12915
- return {
12916
- ok: errors.length === 0,
12917
- errors,
12918
- warnings
12919
- };
12920
- }
12921
- /** Execute docker with an argument array — no shell interpolation. */
12922
- function run$1(args, cwd, timeoutMs = 12e4, envOverrides) {
12923
- return new Promise((resolve) => {
12924
- execFile("docker", args, {
12925
- cwd,
12926
- timeout: timeoutMs,
12927
- env: {
12928
- ...process.env,
12929
- ...envOverrides
12930
- }
12931
- }, (error, stdout, stderr) => {
12932
- resolve({
12933
- ok: !error,
12934
- stdout: stdout?.toString() ?? "",
12935
- stderr: stderr?.toString() ?? "",
12936
- code: error?.code ? Number(error.code) : 0
12937
- });
12938
- });
12939
- });
12940
- }
12941
- /**
12942
- * Resolve the Docker Compose project name.
12943
- * Honors OP_PROJECT_NAME first for OpenPalm stacks, then COMPOSE_PROJECT_NAME.
12944
- */
12945
- function resolveComposeProjectName(envOverrides = {}) {
12946
- return envOverrides.OP_PROJECT_NAME?.trim() || envOverrides.COMPOSE_PROJECT_NAME?.trim() || process.env.OP_PROJECT_NAME?.trim() || process.env.COMPOSE_PROJECT_NAME?.trim() || "openpalm";
12947
12795
  }
12948
- /**
12949
- * Decide whether a running compose project (identified by its
12950
- * `com.docker.compose.project.working_dir` label) is OURS — i.e. was launched
12951
- * from this install's working dir. An empty/unknown label can't prove foreign,
12952
- * so it counts as ours (reconcile rather than wrongly refuse a redeploy).
12953
- *
12954
- * Pure decision split out from detectExistingProject so the ours-vs-foreign
12955
- * rule is unit-testable without a Docker daemon.
12956
- */
12957
- function isProjectOurs(workingDirLabel, expectedWorkingDir) {
12958
- const label = workingDirLabel.trim();
12959
- return label === "" || label === expectedWorkingDir;
12796
+ function readConfigFailClosed(configPath) {
12797
+ if (!existsSync(configPath)) throw new Error(`Personal akm config not found at ${configPath}; refusing to create it. Run \`akm init\`/\`akm setup\` first, then enable host AKM sharing.`);
12798
+ let text;
12799
+ try {
12800
+ text = readFileSync(configPath, "utf-8");
12801
+ } catch (err) {
12802
+ throw new Error(`Unable to read personal akm config at ${configPath}: ${err.message}`);
12803
+ }
12804
+ let parsed;
12805
+ try {
12806
+ parsed = JSON.parse(text);
12807
+ } catch {
12808
+ throw new Error(`Personal akm config at ${configPath} is not valid JSON; refusing to overwrite it. Fix the file by hand, then retry.`);
12809
+ }
12810
+ if (!parsed || typeof parsed !== "object") throw new Error(`Personal akm config at ${configPath} is not a JSON object; refusing to overwrite it.`);
12811
+ return parsed;
12960
12812
  }
12961
12813
  /**
12962
- * Probe the Docker daemon for a running compose project that shares
12963
- * `projectName`. Decides ours-vs-foreign by comparing the project's
12964
- * `com.docker.compose.project.working_dir` label against `expectedWorkingDir`
12965
- * (the install's OP_HOME / compose context).
12966
- *
12967
- * Returns `{ exists:false }` on any docker error (daemon down, no permission) —
12968
- * detection is best-effort and never blocks the caller; a real failure surfaces
12969
- * later through composeUp.
12814
+ * Upsert a named filesystem source into `config.sources[]` by name. Idempotent.
12815
+ * NEVER touches `primary`, `defaultWriteTarget`, or `stashDir`.
12970
12816
  */
12971
- function detectExistingProject(opts) {
12972
- const none = {
12973
- exists: false,
12974
- isOurs: false,
12975
- workingDir: ""
12817
+ function upsertSource(config, entry) {
12818
+ const sources = Array.isArray(config.sources) ? [...config.sources] : [];
12819
+ const idx = sources.findIndex((s) => s && typeof s === "object" && s.name === entry.name);
12820
+ if (idx >= 0) sources[idx] = {
12821
+ ...sources[idx],
12822
+ ...entry
12823
+ };
12824
+ else sources.push(entry);
12825
+ return {
12826
+ ...config,
12827
+ sources
12976
12828
  };
12977
- return new Promise((resolve) => {
12978
- execFile("docker", [
12979
- "ps",
12980
- "-q",
12981
- "--filter",
12982
- `label=com.docker.compose.project=${opts.projectName}`
12983
- ], { timeout: 1e4 }, (err, stdout) => {
12984
- if (err) return resolve(none);
12985
- const ids = stdout.toString().trim().split(/\s+/).filter(Boolean);
12986
- if (ids.length === 0) return resolve(none);
12987
- execFile("docker", [
12988
- "inspect",
12989
- "--format",
12990
- "{{ index .Config.Labels \"com.docker.compose.project.working_dir\" }}",
12991
- ids[0]
12992
- ], { timeout: 1e4 }, (err2, stdout2) => {
12993
- if (err2) return resolve({
12994
- exists: true,
12995
- isOurs: false,
12996
- workingDir: ""
12997
- });
12998
- const workingDir = stdout2.toString().trim();
12999
- resolve({
13000
- exists: true,
13001
- isOurs: isProjectOurs(workingDir, opts.expectedWorkingDir),
13002
- workingDir
13003
- });
13004
- });
13005
- });
13006
- });
13007
- }
13008
- /** Check if Docker is available */
13009
- async function checkDocker() {
13010
- return new Promise((resolve) => {
13011
- execFile("docker", [
13012
- "info",
13013
- "--format",
13014
- "{{.ServerVersion}}"
13015
- ], (error, stdout, stderr) => {
13016
- const stdoutStr = stdout?.toString().trim() ?? "";
13017
- const stderrStr = stderr?.toString() ?? "";
13018
- resolve({
13019
- ok: stdoutStr.length > 0 || !error,
13020
- stdout: stdoutStr,
13021
- stderr: stderrStr,
13022
- code: error?.code ? Number(error.code) : 0
13023
- });
13024
- });
13025
- });
13026
- }
13027
- /** Check if docker compose is available */
13028
- async function checkDockerCompose() {
13029
- return new Promise((resolve) => {
13030
- execFile("docker", ["compose", "version"], (error, stdout, stderr) => {
13031
- resolve({
13032
- ok: !error,
13033
- stdout: stdout?.toString() ?? "",
13034
- stderr: stderr?.toString() ?? "",
13035
- code: error?.code ? Number(error.code) : 0
13036
- });
13037
- });
13038
- });
13039
12829
  }
13040
- /** Build common prefix: compose -f ... --project-name ... --env-file ... --profile ... */
13041
- function buildComposeArgs(options) {
13042
- const envOverrides = collectEnvOverrides(options.envFiles);
13043
- const args = [
13044
- "compose",
13045
- ...options.files.flatMap((f) => ["-f", f]),
13046
- "--project-name",
13047
- resolveComposeProjectName(envOverrides)
13048
- ];
13049
- for (const ef of options.envFiles ?? []) if (existsSync(ef)) args.push("--env-file", ef);
13050
- for (const p of options.profiles ?? []) args.push("--profile", p);
13051
- return args;
12830
+ function removeSource(config, name) {
12831
+ if (!Array.isArray(config.sources)) return config;
12832
+ const sources = config.sources.filter((s) => !(s && typeof s === "object" && s.name === name));
12833
+ return {
12834
+ ...config,
12835
+ sources
12836
+ };
13052
12837
  }
13053
- /** Merge all env files into a single overrides object for process env. */
13054
- function collectEnvOverrides(envFiles) {
13055
- const overrides = {};
13056
- for (const ef of envFiles ?? []) Object.assign(overrides, parseEnvFile(ef));
13057
- return overrides;
12838
+ function assertNoPrimaryEscalation(entry) {
12839
+ if (entry.primary !== void 0) throw new Error("akm-sources: refusing to write a source entry carrying `primary`.");
12840
+ }
12841
+ function openpalmConfigPath(state) {
12842
+ return join(state.configDir, "akm", "config.json");
13058
12843
  }
13059
12844
  /**
13060
- * Run `docker compose config` to validate compose file merge and variable substitution.
13061
- * Must be called before any lifecycle mutation (install/apply/update).
12845
+ * Container/OpenPalm side: add the personal stash (mounted at /host-stash) as a
12846
+ * secondary source. Parse-tolerant (we own this config). Writable by default so
12847
+ * the assistant can contribute back via an explicit `--target host-akm`.
13062
12848
  */
13063
- async function composePreflight(options) {
13064
- const args = buildComposeArgs(options);
13065
- args.push("config", "--quiet");
13066
- return run$1(args, void 0, 3e4, collectEnvOverrides(options.envFiles));
12849
+ function addHostStashToOpenpalmConfig(state, writable = true) {
12850
+ const configPath = openpalmConfigPath(state);
12851
+ const entry = {
12852
+ type: "filesystem",
12853
+ path: "/host-stash",
12854
+ name: HOST_SOURCE_NAME,
12855
+ writable,
12856
+ enabled: true
12857
+ };
12858
+ assertNoPrimaryEscalation(entry);
12859
+ const updated = upsertSource(readConfigTolerant(configPath), entry);
12860
+ writeFileAtomic(configPath, JSON.stringify(updated, null, 2), 384);
13067
12861
  }
13068
12862
  /**
13069
- * Run compose config preflight validation before any mutation.
13070
- * Skipped when OP_SKIP_COMPOSE_PREFLIGHT is set (tests, CI).
12863
+ * Remove the `host-akm` secondary source from the assistant config (disable
12864
+ * sharing). Parse-tolerant; never touches the user's personal config (D1
12865
+ * host sharing is assistant-reads-host only). Idempotent.
13071
12866
  */
13072
- async function runPreflight(options) {
13073
- if (options.files.length === 0 || process.env.OP_SKIP_COMPOSE_PREFLIGHT) return;
13074
- const result = await composePreflight(options);
13075
- if (!result.ok) {
13076
- const project = resolveComposeProjectName(collectEnvOverrides(options.envFiles));
13077
- const fileArgs = options.files.map((f) => `-f ${f}`).join(" ");
13078
- const envArgs = (options.envFiles ?? []).map((f) => `--env-file ${f}`).join(" ");
13079
- const profileArgs = (options.profiles ?? []).map((p) => `--profile ${p}`).join(" ");
13080
- throw new Error(`Compose preflight failed: ${result.stderr}\nResolved command: docker compose ${fileArgs} --project-name ${project} ${envArgs} ${profileArgs} config --quiet`);
13081
- }
12867
+ function removeHostAkmSource(state) {
12868
+ const opPath = openpalmConfigPath(state);
12869
+ const opConfig = readConfigTolerant(opPath);
12870
+ writeFileAtomic(opPath, JSON.stringify(removeSource(opConfig, HOST_SOURCE_NAME), null, 2), 384);
13082
12871
  }
13083
- async function composeConfigServices(options) {
13084
- const args = buildComposeArgs(options);
13085
- args.push("config", "--services");
13086
- const result = await run$1(args, void 0, 3e4, collectEnvOverrides(options.envFiles));
13087
- if (!result.ok) return {
13088
- ok: false,
13089
- services: []
13090
- };
13091
- return {
13092
- ok: true,
13093
- services: result.stdout.split("\n").map((s) => s.trim()).filter(Boolean)
12872
+ /**
12873
+ * Read-only snapshot import of the host's reusable akm config into the OpenPalm
12874
+ * config. Reads the personal config READ-ONLY; never writes back to the host.
12875
+ *
12876
+ * ADDITIVE MERGE: existing OpenPalm values ALWAYS win — the host only fills gaps.
12877
+ * A profile name, default selection, or embedding field that OpenPalm already has
12878
+ * is never overwritten; host-only profiles/fields are added. Covers the
12879
+ * LLM/agent/improve PROFILES (+ their `defaults.*`) and the top-level `embedding`
12880
+ * connection. Returns which sections actually gained values.
12881
+ *
12882
+ * Writes the canonical akm 0.8.0 shape (profiles.* + defaults.* + embedding)
12883
+ * never the legacy top-level `llm` (see I-3). NEVER touches `sources`, `stashDir`,
12884
+ * `registries`, or `installed`.
12885
+ */
12886
+ function importHostProfiles(state, hostConfigPath) {
12887
+ const host = readConfigFailClosed(hostConfigPath);
12888
+ const hostProfiles = host.profiles ?? {};
12889
+ const hostDefaults = host.defaults ?? {};
12890
+ const opPath = openpalmConfigPath(state);
12891
+ const op = readConfigTolerant(opPath);
12892
+ const opProfiles = op.profiles ?? {};
12893
+ const opDefaults = op.defaults ?? {};
12894
+ const imported = [];
12895
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
12896
+ for (const ns of [
12897
+ "llm",
12898
+ "agent",
12899
+ "improve"
12900
+ ]) {
12901
+ if (isObj(hostProfiles[ns])) {
12902
+ const existing = isObj(opProfiles[ns]) ? opProfiles[ns] : {};
12903
+ const merged = {
12904
+ ...hostProfiles[ns],
12905
+ ...existing
12906
+ };
12907
+ const added = Object.keys(merged).length - Object.keys(existing).length;
12908
+ opProfiles[ns] = merged;
12909
+ if (added > 0) imported.push(`profiles.${ns}`);
12910
+ }
12911
+ if (typeof hostDefaults[ns] === "string" && typeof opDefaults[ns] !== "string") {
12912
+ opDefaults[ns] = hostDefaults[ns];
12913
+ imported.push(`defaults.${ns}`);
12914
+ }
12915
+ }
12916
+ let embedding;
12917
+ if (isObj(host.embedding)) {
12918
+ const existing = isObj(op.embedding) ? op.embedding : {};
12919
+ const merged = {
12920
+ ...host.embedding,
12921
+ ...existing
12922
+ };
12923
+ if (Object.keys(merged).length > Object.keys(existing).length) {
12924
+ embedding = merged;
12925
+ imported.push("embedding");
12926
+ }
12927
+ }
12928
+ if (imported.length === 0) return { imported };
12929
+ const updated = {
12930
+ ...op,
12931
+ profiles: opProfiles,
12932
+ defaults: opDefaults
13094
12933
  };
12934
+ if (embedding !== void 0) updated.embedding = embedding;
12935
+ delete updated.llm;
12936
+ writeFileAtomic(opPath, JSON.stringify(updated, null, 2), 384);
12937
+ return { imported };
13095
12938
  }
12939
+ //#endregion
12940
+ //#region ../lib/src/control-plane/host-akm-sharing.ts
13096
12941
  /**
13097
- * Run `docker compose up -d` with the generated compose file(s).
13098
- * Pass `files` to merge multiple compose overlays (e.g. core + addon files).
12942
+ * Host AKM sharing (control-plane logic lives in lib).
12943
+ *
12944
+ * Simplified model (no compose overlay, no file-presence gating):
12945
+ *
12946
+ * - The assistant ALWAYS mounts `/host-stash` (core.compose.yml). When the host
12947
+ * has AKM, OP_HOST_AKM_STASH points at the user's personal stash (~/akm);
12948
+ * otherwise it is unset and compose falls back to an always-present empty dir.
12949
+ * - "Sharing" is purely a writable SECONDARY source entry named `host-akm` →
12950
+ * /host-stash in the assistant's config/akm/config.json. Adding it = enabled;
12951
+ * removing it = disabled. akm resolves writes to the primary unless an explicit
12952
+ * --target is given, and silently skips a source whose dir is empty/missing —
12953
+ * so a mounted-but-unconfigured /host-stash is harmless.
12954
+ * - Host availability is detected from the presence of the user's personal akm
12955
+ * CONFIG (~/.config/akm/config.json) — the real signal that akm is initialized.
12956
+ *
12957
+ * Decision D1 (2026-06-03): host sharing is assistant-reads-host ONLY by default.
12958
+ * We never write into the user's personal ~/.config/akm here. (Letting the host
12959
+ * akm see OpenPalm's knowledge is a future, explicit opt-in.)
13099
12960
  */
13100
- async function composeUp(options) {
13101
- await runPreflight(options);
13102
- if (!existsSync(options.files[0])) return {
13103
- ok: false,
13104
- stdout: "",
13105
- stderr: "Compose file not found",
13106
- code: 1
13107
- };
13108
- const args = buildComposeArgs(options);
13109
- args.push("up", "-d");
13110
- if (options.forceRecreate) args.push("--force-recreate");
13111
- if (options.removeOrphans) args.push("--remove-orphans");
13112
- if (options.services?.length) args.push(...options.services);
13113
- return run$1(args, void 0, composeUpTimeoutMs(), collectEnvOverrides(options.envFiles));
12961
+ var logger$5 = createLogger("host-akm-sharing");
12962
+ var ENV_KEY = "OP_HOST_AKM_STASH";
12963
+ function userHome() {
12964
+ return process.env.HOME ?? process.env.USERPROFILE ?? homedir();
12965
+ }
12966
+ /** The user's personal akm stash dir (mounted into the assistant at /host-stash). */
12967
+ function hostAkmStashPath() {
12968
+ return `${userHome()}/akm`;
12969
+ }
12970
+ /** The user's personal akm config file — its existence is our availability signal. */
12971
+ function hostAkmConfigPath() {
12972
+ return `${userHome()}/.config/akm/config.json`;
12973
+ }
12974
+ /** True when AKM is initialized on the host (personal config exists). */
12975
+ function isHostAkmAvailable() {
12976
+ return existsSync(hostAkmConfigPath());
12977
+ }
12978
+ function stackEnvPath(state) {
12979
+ return `${state.stashDir}/env/stack.env`;
13114
12980
  }
13115
12981
  /**
13116
- * Timeout budget for `compose up`. A first install extracts multi-GB images
13117
- * (voice CUDA ~7.6 GB) onto slow disks; the previous hard 5-minute cap
13118
- * SIGTERM-killed the start mid-extraction and surfaced as an empty/opaque
13119
- * error. Default 30 min, override with OP_COMPOSE_UP_TIMEOUT_MS. Kept bounded
13120
- * (never removed) so a genuinely hung start still eventually fails.
12982
+ * Point OP_HOST_AKM_STASH at the host stash when AKM is available, else unset it
12983
+ * (compose then uses the empty-dir fallback). Pure infrastructure does NOT
12984
+ * change the source list. Idempotent; safe to call on setup and on deploy.
13121
12985
  */
13122
- function composeUpTimeoutMs() {
13123
- const raw = process.env.OP_COMPOSE_UP_TIMEOUT_MS?.trim();
13124
- const parsed = raw ? Number(raw) : NaN;
13125
- if (Number.isFinite(parsed) && parsed > 0) return parsed;
13126
- return 30 * 6e4;
12986
+ function ensureHostStashEnv(state) {
12987
+ const path = stackEnvPath(state);
12988
+ const existing = existsSync(path) ? readFileSync(path, "utf-8") : "";
12989
+ const updated = isHostAkmAvailable() ? mergeEnvContent(existing, { [ENV_KEY]: hostAkmStashPath() }) : removeEnvKey(existing, ENV_KEY);
12990
+ if (updated !== existing) writeFileAtomic(path, updated, 384);
13127
12991
  }
13128
12992
  /**
13129
- * Run `docker compose down` to stop and remove containers.
12993
+ * Enable host AKM sharing: ensure OP_HOST_AKM_STASH points at ~/akm and add the
12994
+ * writable `host-akm` secondary source to the assistant config. Optionally import
12995
+ * host LLM/agent profiles (read-only). Throws if host AKM is not available.
13130
12996
  */
13131
- async function composeDown(options) {
13132
- await runPreflight(options);
13133
- if (!existsSync(options.files[0])) return {
13134
- ok: false,
13135
- stdout: "",
13136
- stderr: "Compose file not found",
13137
- code: 1
13138
- };
13139
- const args = buildComposeArgs(options);
13140
- args.push("down");
13141
- if (options.removeVolumes) args.push("-v");
13142
- if (options.removeOrphans) args.push("--remove-orphans");
13143
- return run$1(args, void 0);
12997
+ function enableHostAkmSharing(state, opts = {}) {
12998
+ if (!isHostAkmAvailable()) throw new Error(`Host AKM is not available (no ${hostAkmConfigPath()}). Run \`akm init\` on the host first.`);
12999
+ ensureHostStashEnv(state);
13000
+ addHostStashToOpenpalmConfig(state, opts.writable ?? true);
13001
+ let profilesImported = [];
13002
+ if (opts.importProfiles) profilesImported = importHostProfiles(state, hostAkmConfigPath()).imported;
13003
+ logger$5.info("host akm sharing enabled", {
13004
+ hostStashPath: hostAkmStashPath(),
13005
+ profilesImported
13006
+ });
13007
+ return { profilesImported };
13144
13008
  }
13145
13009
  /**
13146
- * Restart specific services.
13010
+ * Disable host AKM sharing: remove the `host-akm` secondary source from the
13011
+ * assistant config. Leaves the (harmless) mount and env in place; never deletes
13012
+ * any stash content.
13147
13013
  */
13148
- async function composeRestart(services, options) {
13149
- await runPreflight(options);
13150
- const primaryFile = options.files[0];
13151
- if (!existsSync(primaryFile)) return {
13152
- ok: false,
13153
- stdout: "",
13154
- stderr: "Compose file not found",
13155
- code: 1
13156
- };
13157
- const args = buildComposeArgs(options);
13158
- args.push("restart", ...services);
13159
- return run$1(args, void 0);
13014
+ function disableHostAkmSharing(state) {
13015
+ removeHostAkmSource(state);
13016
+ logger$5.info("host akm sharing disabled");
13017
+ }
13018
+ /** Report availability + whether the host-akm source is currently configured. */
13019
+ function getHostAkmSharingStatus(state) {
13020
+ const available = isHostAkmAvailable();
13021
+ return {
13022
+ available,
13023
+ enabled: openpalmHasHostSource(state),
13024
+ hostStashPath: available ? hostAkmStashPath() : null
13025
+ };
13160
13026
  }
13161
- /**
13162
- * Stop specific services.
13163
- */
13164
- async function composeStop(services, options) {
13165
- await runPreflight(options);
13166
- const args = buildComposeArgs(options);
13167
- args.push("stop", ...services);
13168
- return run$1(args, void 0);
13027
+ function openpalmHasHostSource(state) {
13028
+ const path = `${state.configDir}/akm/config.json`;
13029
+ if (!existsSync(path)) return false;
13030
+ try {
13031
+ const cfg = JSON.parse(readFileSync(path, "utf-8"));
13032
+ return Array.isArray(cfg.sources) && cfg.sources.some((s) => s?.name === "host-akm");
13033
+ } catch {
13034
+ return false;
13035
+ }
13169
13036
  }
13037
+ //#endregion
13038
+ //#region ../lib/src/control-plane/rollback.ts
13170
13039
  /**
13171
- * Start specific services (must already be created).
13040
+ * Snapshot-based rollback for the OpenPalm control plane.
13041
+ *
13042
+ * Before writing validated changes to live paths, the current state
13043
+ * is snapshotted to OP_HOME/data/rollback/. On deploy failure
13044
+ * (or manual `openpalm rollback`), the snapshot is restored.
13172
13045
  */
13173
- async function composeStart(services, options) {
13174
- await runPreflight(options);
13175
- const args = buildComposeArgs(options);
13176
- args.push("up", "-d", ...services);
13177
- return run$1(args, void 0);
13178
- }
13046
+ /** Files that are tracked for rollback (relative to homeDir).
13047
+ * Only config/ system files are included — user-editable config files
13048
+ * are never overwritten by lifecycle operations. */
13049
+ var SNAPSHOT_FILES = [
13050
+ "knowledge/env/stack.env",
13051
+ "config/stack/services.compose.yml",
13052
+ "config/stack/channels.compose.yml",
13053
+ "config/stack/custom.compose.yml",
13054
+ "knowledge/secrets/auth.json"
13055
+ ];
13179
13056
  /**
13180
- * Get the status of all containers in the project.
13057
+ * Copy a file if it exists, creating parent directories as needed.
13181
13058
  */
13182
- async function composePs(options) {
13183
- const primaryFile = options.files[0];
13184
- if (!existsSync(primaryFile)) return run$1([
13185
- "ps",
13186
- "--filter",
13187
- `label=com.docker.compose.project=${resolveComposeProjectName()}`,
13188
- "--format",
13189
- "json"
13190
- ], void 0);
13191
- const args = buildComposeArgs(options);
13192
- args.push("ps", "--format", "json");
13193
- return run$1(args, void 0);
13059
+ function safeCopy(src, dest) {
13060
+ if (!existsSync(src)) return;
13061
+ mkdirSync(dirname(dest), { recursive: true });
13062
+ copyFileSync(src, dest);
13194
13063
  }
13195
13064
  /**
13196
- * Get logs for specific services or all services.
13065
+ * Save the current live configuration files to the rollback directory.
13066
+ * Also snapshots stack/core.compose.yml.
13197
13067
  */
13198
- async function composeLogs(services, tail, options) {
13199
- const args = buildComposeArgs(options);
13200
- args.push("logs", "--tail", String(tail));
13201
- if (options.since) args.push("--since", options.since);
13202
- if (services && services.length > 0) args.push(...services);
13203
- return run$1(args, void 0);
13068
+ function snapshotCurrentState(state) {
13069
+ const rollbackDir = resolveRollbackDir();
13070
+ mkdirSync(rollbackDir, { recursive: true });
13071
+ for (const rel of SNAPSHOT_FILES) safeCopy(join(state.homeDir, rel), join(rollbackDir, rel));
13072
+ safeCopy(join(state.homeDir, "config/stack/core.compose.yml"), join(rollbackDir, "config/stack/core.compose.yml"));
13073
+ writeFileSync(join(rollbackDir, ".snapshot-ts"), (/* @__PURE__ */ new Date()).toISOString() + "\n");
13204
13074
  }
13205
- var PULL_TIMEOUT_MS = 60 * 6e4;
13206
- async function composePull(options) {
13207
- await runPreflight(options);
13208
- const args = buildComposeArgs(options);
13209
- args.push("pull");
13210
- return run$1(args, void 0, PULL_TIMEOUT_MS, collectEnvOverrides(options.envFiles));
13075
+ //#endregion
13076
+ //#region ../lib/src/control-plane/secret-mappings.ts
13077
+ var STATIC_CORE_MAPPINGS = [
13078
+ {
13079
+ secretKey: "openpalm/ui-login-password",
13080
+ envKey: "OP_UI_LOGIN_PASSWORD",
13081
+ scope: "system"
13082
+ },
13083
+ {
13084
+ secretKey: "openpalm/opencode/server-password",
13085
+ envKey: "OP_OPENCODE_PASSWORD",
13086
+ scope: "system"
13087
+ },
13088
+ {
13089
+ secretKey: "openpalm/openai/api-key",
13090
+ envKey: "OPENAI_API_KEY",
13091
+ scope: "user"
13092
+ },
13093
+ {
13094
+ secretKey: "openpalm/anthropic/api-key",
13095
+ envKey: "ANTHROPIC_API_KEY",
13096
+ scope: "user"
13097
+ },
13098
+ {
13099
+ secretKey: "openpalm/groq/api-key",
13100
+ envKey: "GROQ_API_KEY",
13101
+ scope: "user"
13102
+ },
13103
+ {
13104
+ secretKey: "openpalm/mistral/api-key",
13105
+ envKey: "MISTRAL_API_KEY",
13106
+ scope: "user"
13107
+ },
13108
+ {
13109
+ secretKey: "openpalm/google/api-key",
13110
+ envKey: "GOOGLE_API_KEY",
13111
+ scope: "user"
13112
+ },
13113
+ {
13114
+ secretKey: "openpalm/together/api-key",
13115
+ envKey: "TOGETHER_API_KEY",
13116
+ scope: "user"
13117
+ },
13118
+ {
13119
+ secretKey: "openpalm/deepseek/api-key",
13120
+ envKey: "DEEPSEEK_API_KEY",
13121
+ scope: "user"
13122
+ },
13123
+ {
13124
+ secretKey: "openpalm/xai/api-key",
13125
+ envKey: "XAI_API_KEY",
13126
+ scope: "user"
13127
+ },
13128
+ {
13129
+ secretKey: "openpalm/huggingface/token",
13130
+ envKey: "HF_TOKEN",
13131
+ scope: "user"
13132
+ },
13133
+ {
13134
+ secretKey: "openpalm/mcp/api-key",
13135
+ envKey: "MCP_API_KEY",
13136
+ scope: "user"
13137
+ },
13138
+ {
13139
+ secretKey: "openpalm/embedding/api-key",
13140
+ envKey: "EMBEDDING_API_KEY",
13141
+ scope: "user"
13142
+ },
13143
+ {
13144
+ secretKey: "openpalm/lmstudio/api-key",
13145
+ envKey: "LMSTUDIO_API_KEY",
13146
+ scope: "user"
13147
+ },
13148
+ {
13149
+ secretKey: "openpalm/discord/bot-token",
13150
+ envKey: "DISCORD_BOT_TOKEN",
13151
+ scope: "user"
13152
+ },
13153
+ {
13154
+ secretKey: "openpalm/slack/bot-token",
13155
+ envKey: "SLACK_BOT_TOKEN",
13156
+ scope: "user"
13157
+ },
13158
+ {
13159
+ secretKey: "openpalm/slack/app-token",
13160
+ envKey: "SLACK_APP_TOKEN",
13161
+ scope: "user"
13162
+ },
13163
+ {
13164
+ secretKey: "openpalm/voice/stt-api-key",
13165
+ envKey: "STT_API_KEY",
13166
+ scope: "user"
13167
+ },
13168
+ {
13169
+ secretKey: "openpalm/voice/tts-api-key",
13170
+ envKey: "TTS_API_KEY",
13171
+ scope: "user"
13172
+ }
13173
+ ];
13174
+ function getCoreSecretMappings(systemEnv) {
13175
+ const dynamicMappings = [];
13176
+ for (const envKey of Object.keys(systemEnv)) {
13177
+ const match = envKey.match(/^CHANNEL_([A-Z0-9_]+)_SECRET$/);
13178
+ if (!match?.[1]) continue;
13179
+ dynamicMappings.push({
13180
+ secretKey: `openpalm/channel/${match[1].toLowerCase()}/secret`,
13181
+ envKey,
13182
+ scope: "system"
13183
+ });
13184
+ }
13185
+ return [...STATIC_CORE_MAPPINGS, ...dynamicMappings];
13211
13186
  }
13187
+ //#endregion
13188
+ //#region ../lib/src/control-plane/validate.ts
13212
13189
  /**
13213
- * Get resource usage stats for all containers in the project.
13190
+ * Runtime configuration validation for the OpenPalm control plane.
13191
+ *
13192
+ * Validation is a presence check on the canonical env keys we expect in
13193
+ * the live config/stack files. The
13194
+ * historical schema files and external validation binary were retired in
13195
+ * #391; everything advisory is surfaced as a non-blocking warning. The
13196
+ * function never shells out and never reads schemas.
13214
13197
  */
13215
- async function composeStats(options) {
13216
- const args = buildComposeArgs(options);
13217
- args.push("stats", "--no-stream", "--format", "json");
13218
- return run$1(args, void 0);
13219
- }
13198
+ var REQUIRED_SECRET_KEYS = ["OP_UI_LOGIN_PASSWORD"];
13220
13199
  /**
13221
- * Get recent Docker events for the compose project.
13200
+ * Validate the live configuration files.
13201
+ *
13202
+ * Checks:
13203
+ * 1. knowledge/env/stack.env exists and carries every required key with a
13204
+ * non-empty value.
13205
+ * 2. Every secret env key in getCoreSecretMappings() is present (key only
13206
+ * — blank values are warned about, never erred on, because operators
13207
+ * may opt out of providers they don't use).
13208
+ *
13209
+ * Errors fail the result. Warnings do not. The function never reads
13210
+ * schema files and never spawns subprocesses.
13222
13211
  */
13223
- async function getDockerEvents(projectName, since = "1h") {
13224
- return run$1([
13225
- "events",
13226
- "--filter",
13227
- `label=com.docker.compose.project=${projectName}`,
13228
- "--since",
13229
- since,
13230
- "--until",
13231
- "now",
13232
- "--format",
13233
- "json"
13234
- ], void 0, 15e3);
13212
+ async function validateProposedState(state) {
13213
+ const errors = [];
13214
+ const warnings = [];
13215
+ const stackEnvPath = `${state.stashDir}/env/stack.env`;
13216
+ if (!existsSync(stackEnvPath)) {
13217
+ errors.push(`ERROR: stack env file missing at ${stackEnvPath}`);
13218
+ return {
13219
+ ok: false,
13220
+ errors,
13221
+ warnings
13222
+ };
13223
+ }
13224
+ const runtimeEnv = readStackRuntimeEnv(state.stackDir);
13225
+ for (const key of REQUIRED_SECRET_KEYS) {
13226
+ const value = runtimeEnv[key];
13227
+ if (!value || value.trim().length === 0) errors.push(`ERROR: required secret ${key} is missing or empty in knowledge/secrets/${key.toLowerCase()}`);
13228
+ }
13229
+ for (const mapping of getCoreSecretMappings(runtimeEnv)) if (!Object.prototype.hasOwnProperty.call(runtimeEnv, mapping.envKey)) warnings.push(`WARN: ${mapping.envKey} (akm ${mapping.secretKey}) is not declared in knowledge/secrets/${mapping.envKey.toLowerCase()}`);
13230
+ return {
13231
+ ok: errors.length === 0,
13232
+ errors,
13233
+ warnings
13234
+ };
13235
13235
  }
13236
13236
  //#endregion
13237
13237
  //#region ../lib/src/control-plane/compose-args.ts
@@ -14878,4 +14878,4 @@ function importHostOpenCode(state, options = {}) {
14878
14878
  }
14879
14879
 
14880
14880
  export { hostAkmStashPath as $, AKM_USER_ENV_REF as A, createState as B, CORE_SERVICES as C, deleteUserEnvKey as D, detectExistingProject as E, detectGpu as F, detectHostOpenCode as G, detectLocalProviders as H, disableHostAkmSharing as I, enableHostAkmSharing as J, ensureAkmUserEnv as K, ensureHomeDirs as L, MigrationError as M, ensureMigrated as N, ensureOpenCodeConfig as O, PROVIDER_KEY_MAP as P, ensureOpenCodeSystemConfig as Q, ensureSecrets as R, executeAutomation as S, fetchProviderModels as T, getAddonProfileAvailability as U, getAddonProfileSelection as V, getAddonProfiles as W, getAddonServiceNames as X, getDockerEvents as Y, getHostAkmSharingStatus as Z, getRegistryAddonConfig as _, addonProfileId as a, importHostOpenCode as a0, isAllowedService as a1, isHostAkmAvailable as a2, isSetupComplete as a3, listAvailableAddonIds as a4, listEnabledAddonIds as a5, listSecretFiles as a6, loadAutomations as a7, parseComposeStderr as a8, parseEnvFile as a9, writeTaskFile as aA, writeUserEnvKey as aB, writeVoiceVars as aC, performSetup as aa, performUpgrade as ab, readAutomationLogs as ac, readSecret as ad, readSecretFile as ae, readStackEnv as af, readStackRuntimeEnv as ag, readStackSecretEnv as ah, readTaskFile as ai, readUserEnvFile as aj, recommendSetup as ak, removeSecretFile as al, removeTaskFile as am, resolveComposeProjectName as an, resolveDataDir as ao, resolveRuntimeFiles as ap, resolveStackDir as aq, seedUiBuild as ar, setAddonEnabled as as, setAddonProfileSelection as at, summarizeComposeStderr as au, validateProposedState as av, writeFileAtomic as aw, writeRuntimeFiles as ax, writeSecretFile as ay, writeStackSecretEnv as az, annotateAddonProfileAvailability as b, applyInstall as c, applyTagChange as d, applyUninstall as e, applyUpdate as f, assertSafeSecretFilename as g, assertSafeTaskFilename as h, authJsonPath as i, buildAkmEnv as j, buildComposeOptions as k, buildManagedServices as l, checkDocker as m, checkDockerCompose as n, composeDown as o, composeLogs as p, composePreflight as q, composePs as r, composePull as s, composeRestart as t, composeStart as u, composeStats as v, composeStop as w, composeUp as x, createLogger as y, createOpenCodeClient as z };
14881
- //# sourceMappingURL=src-b3nBkyhY.js.map
14881
+ //# sourceMappingURL=src-DkGZ5D6n.js.map