@runeya/runeya 2.0.73 → 2.0.75

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 (244) hide show
  1. package/agent/index.js +1057 -982
  2. package/agent/index.js.map +1 -1
  3. package/agent-manager-DM6C7BTF.js +7 -0
  4. package/{chunk-OTJQEK4D.js → chunk-E2SU5RSO.js} +121 -4
  5. package/chunk-E2SU5RSO.js.map +1 -0
  6. package/index.js +1 -1
  7. package/package.json +1 -1
  8. package/{src-MY5W5AYS.js → src-MEMRUBM6.js} +67 -19
  9. package/src-MEMRUBM6.js.map +1 -0
  10. package/web/assets/AgentScalarChatInterface.vue-CbsV-wvF.js +13 -0
  11. package/web/assets/AgentTerminalPage-CFX_cNje.js +1 -0
  12. package/web/assets/AiChatPage-aNp-79bj.js +1 -0
  13. package/web/assets/AppLayout-C8SJH7E2.js +1 -0
  14. package/web/assets/{AppLayout-Dj8VrBzz.css → AppLayout-Dvr7plrF.css} +1 -1
  15. package/web/assets/AuditPage-mPkN9IPs.js +1 -0
  16. package/web/assets/CloudAccountPage--8gMHEov.js +1 -0
  17. package/web/assets/CloudAccountPage-DwfKS8Ui.js +1 -0
  18. package/web/assets/CloudMessagingPage-BZda9W4V.js +2 -0
  19. package/web/assets/DashboardPage-BYoHvCSW.js +1 -0
  20. package/web/assets/DirectoryPickerDialog-GjBksDRF.js +1 -0
  21. package/web/assets/{EditorIcon-C32poOg-.js → EditorIcon-BGndPLGm.js} +2 -2
  22. package/web/assets/{EnvironmentForm-CjnghPBi.js → EnvironmentForm-5X5MccdS.js} +2 -2
  23. package/web/assets/EnvironmentFormPage-pWcZotB8.js +1 -0
  24. package/web/assets/EnvironmentListPage-D1u5GOUq.js +1 -0
  25. package/web/assets/KanbanBoardPage-B61sIHjE.js +4 -0
  26. package/web/assets/KanbanListPage-Dsg1wA9V.js +1 -0
  27. package/web/assets/LaunchProjectPage-BzLfT9xo.js +1 -0
  28. package/web/assets/LaunchServicesPage-DxRtzyc-.js +1 -0
  29. package/web/assets/LogViewer-DCTx3ncv.js +3 -0
  30. package/web/assets/OrgKeyPrompt-DGVXqIwV.js +1 -0
  31. package/web/assets/{ProcessControls-CNrbnTpl.js → ProcessControls-CKHLGdip.js} +1 -1
  32. package/web/assets/ProcessDetailPage-BTcbsw0H.js +1 -0
  33. package/web/assets/{ProcessMetrics-B6Zf110f.js → ProcessMetrics-B0mOAjpt.js} +2 -2
  34. package/web/assets/ProjectDetailPage-Do50Toy3.js +1 -0
  35. package/web/assets/ProjectListPage-FhR5Gkub.js +1 -0
  36. package/web/assets/RandomJobTestPage-CT1XUQ7l.js +2 -0
  37. package/web/assets/ScenarioEditorPage-CAZ18fLj.js +14 -0
  38. package/web/assets/SendToChatDialog-3VcAeiLB.js +1 -0
  39. package/web/assets/ServiceControlsBar-DMibK9Gk.js +1 -0
  40. package/web/assets/{ServiceDetailPage-DDSyACSv.css → ServiceDetailPage-DVOQdgmZ.css} +1 -1
  41. package/web/assets/ServiceDetailPage-DzTdnnmK.js +2 -0
  42. package/web/assets/ServiceFormPage-C3Av0wu_.js +1 -0
  43. package/web/assets/SettingsPage-Cb4cXWBn.js +2063 -0
  44. package/web/assets/{SettingsPage-ClUsbLPy.css → SettingsPage-CeFOjH68.css} +1 -1
  45. package/web/assets/UnlockPage-Cj9f3u9P.js +1 -0
  46. package/web/assets/VariablesTable-DNNf7eCt.css +1 -0
  47. package/web/assets/VariablesTable-_m1LCIc1.js +1 -0
  48. package/web/assets/VaultMigrationPage-4-aYgpPb.js +1 -0
  49. package/web/assets/VersionBadge-D-5Wk-zP.js +1 -0
  50. package/web/assets/WikiPage-Dr0BjWqx.js +1 -0
  51. package/web/assets/WikiView-Zx8Prvim.js +1 -0
  52. package/web/assets/add-scalar-classes-Bj8wq_Hs.js +387 -0
  53. package/web/assets/auth-errors-C98TqTeb.js +1 -0
  54. package/web/assets/{autocomplete-LUb8fDRi.js → autocomplete-CGdex9-e.js} +3 -3
  55. package/web/assets/{basic-shape-diamond.svg-CCzIrujg.js → basic-shape-diamond.svg-qeeRnNFT.js} +1 -1
  56. package/web/assets/{basic-shape-hexagon.svg-DdSh-N2z.js → basic-shape-hexagon.svg-CIlKhfGT.js} +1 -1
  57. package/web/assets/{basic-shape-primary-circle-ellipse-round.svg-DsMpzYdr.js → basic-shape-primary-circle-ellipse-round.svg-BqolxHsi.js} +1 -1
  58. package/web/assets/{basic-shape-primary-square-rectangle.svg-S5aiKynO.js → basic-shape-primary-square-rectangle.svg-CpdZYdXX.js} +1 -1
  59. package/web/assets/{basic-shape-shield.svg-06mLN5Kq.js → basic-shape-shield.svg-Dxhs7gEl.js} +1 -1
  60. package/web/assets/{browser-CvGRE98D.js → browser-DN1U-HwX.js} +1 -1
  61. package/web/assets/{browser-B6kPJYkH.js → browser-I2oYlD2i.js} +1 -1
  62. package/web/assets/{card-DQ-7UOQt.js → card-DtzNVDSZ.js} +2 -2
  63. package/web/assets/{checkbox-CIizqAL5.js → checkbox-GeePBqgX.js} +2 -2
  64. package/web/assets/{chip-CKY-cFPm.js → chip-BHIwNcot.js} +2 -2
  65. package/web/assets/{client-Cem5gxc3.js → client-BDHmFNrH.js} +2 -2
  66. package/web/assets/cloud-chat.store-B20ZLeeR.js +1 -0
  67. package/web/assets/cloud-session-BjfhcCqc.js +1 -0
  68. package/web/assets/column-DXHLG_CF.js +907 -0
  69. package/web/assets/{computer-device-desktop-monitor.svg-pZKLXVEO.js → computer-device-desktop-monitor.svg-cgtj7qaG.js} +1 -1
  70. package/web/assets/{computer-device-desktop.svg-CPuJoG2N.js → computer-device-desktop.svg-CtASuIzj.js} +1 -1
  71. package/web/assets/{computer-device-laptop.svg-B2lqbpvX.js → computer-device-laptop.svg-Bgrj-X1s.js} +1 -1
  72. package/web/assets/{computer-device-mobile-phone-android-samsung-back.svg-C91mPbw_.js → computer-device-mobile-phone-android-samsung-back.svg-BdGuG_w_.js} +1 -1
  73. package/web/assets/{computer-device-mobile-phone-android-samsung.svg-CgjjMhRB.js → computer-device-mobile-phone-android-samsung.svg-BRGfdLz4.js} +1 -1
  74. package/web/assets/{computer-device-mobile-phone-iphone-x-back.svg-DdpW-odT.js → computer-device-mobile-phone-iphone-x-back.svg-AqEKxnYo.js} +1 -1
  75. package/web/assets/{computer-device-mobile-phone-iphone-x.svg-B_qWFdEx.js → computer-device-mobile-phone-iphone-x.svg-DWFt-koa.js} +1 -1
  76. package/web/assets/{computer-device-mobile-tablet-touch.svg-BzehkLNH.js → computer-device-mobile-tablet-touch.svg-DJ52OpYh.js} +1 -1
  77. package/web/assets/{computer-device-mobile-tablet.svg-rkDIg0TG.js → computer-device-mobile-tablet.svg-Ce_rWOZi.js} +1 -1
  78. package/web/assets/{computer-device-network-ethernet-cat6.svg-B-d_wrR_.js → computer-device-network-ethernet-cat6.svg-DB9SlCtA.js} +1 -1
  79. package/web/assets/{computer-device-network-lan-www.svg-TIELALfm.js → computer-device-network-lan-www.svg-lHja183-.js} +1 -1
  80. package/web/assets/{computer-device-network-wifi-connection.svg-DbXW3PhA.js → computer-device-network-wifi-connection.svg-B1zLcvJN.js} +1 -1
  81. package/web/assets/{computer-device-network-wifi-router.svg-D_35yOXc.js → computer-device-network-wifi-router.svg-Drrwd9xP.js} +1 -1
  82. package/web/assets/{cssMode-B7e_eNPV.js → cssMode-D9jO-uTl.js} +1 -1
  83. package/web/assets/{divider-BHKktSGp.js → divider-B0vBDWbW.js} +2 -2
  84. package/web/assets/{docx-preview-DlxCg_6l.js → docx-preview-BTpCoAAq.js} +1 -1
  85. package/web/assets/{ecology-science-erlenmeyer-flask.svg-Dl6fsl4J.js → ecology-science-erlenmeyer-flask.svg--ysD_96O.js} +1 -1
  86. package/web/assets/{fieldset-De5JS2HC.js → fieldset-BFb-WHon.js} +2 -2
  87. package/web/assets/{freemarker2-BZ1pmGPV.js → freemarker2-DnkPMk4B.js} +1 -1
  88. package/web/assets/{handlebars-DQnFd9h7.js → handlebars-Dsj_qiK6.js} +1 -1
  89. package/web/assets/{html-C0efjIn9.js → html-t_OlpWku.js} +1 -1
  90. package/web/assets/{htmlMode-ChFMbKcf.js → htmlMode-DRcQv-pv.js} +1 -1
  91. package/web/assets/{image-flash-lightning.svg-B7e5E2Qw.js → image-flash-lightning.svg-6f9kbrTL.js} +1 -1
  92. package/web/assets/{image-picture-flower.svg-Cw1CZ_Iv.js → image-picture-flower.svg-i7zms3Ho.js} +1 -1
  93. package/web/assets/{index-nY5cynKj.js → index-GxI3bOA0.js} +210 -210
  94. package/web/assets/{interface-alert-exclamation-diamond.svg-BSUXkUin.js → interface-alert-exclamation-diamond.svg-DqUMmCtJ.js} +1 -1
  95. package/web/assets/{interface-alert-exclamation-triangle-warning.svg-BYqq_OZy.js → interface-alert-exclamation-triangle-warning.svg-DzDl1xOr.js} +1 -1
  96. package/web/assets/{interface-alert-information-circle.svg-BhCupwNF.js → interface-alert-information-circle.svg-DmCgkGPM.js} +1 -1
  97. package/web/assets/{interface-award-crown.svg-BSbmsgu7.js → interface-award-crown.svg-C9Fbg_RB.js} +1 -1
  98. package/web/assets/{interface-bookmark.svg-DImT79em.js → interface-bookmark-tag.svg-3gViLsvg.js} +1 -1
  99. package/web/assets/{interface-bookmark-tag.svg-C9Tj2VKg.js → interface-bookmark.svg-MqIoLfKE.js} +1 -1
  100. package/web/assets/{interface-calendar-date-one.svg-emGvRYfy.js → interface-calendar-date-one.svg-B9sbfbL9.js} +1 -1
  101. package/web/assets/{interface-content-book-open-pages.svg-DZvD8n9A.js → interface-content-book-open-pages.svg-1vSNOl7u.js} +1 -1
  102. package/web/assets/{interface-content-book-page.svg--RPY0ONx.js → interface-content-book-page.svg-DIEM6xdS.js} +1 -1
  103. package/web/assets/{interface-content-file.svg-BhkPpAIG.js → interface-content-file.svg-7VSdTCse.js} +1 -1
  104. package/web/assets/{interface-content-folder.svg-_Qz96t7R.js → interface-content-folder.svg-9g1Oeyk0.js} +1 -1
  105. package/web/assets/interface-content-folder.svg-CAHYAOYi.js +1 -0
  106. package/web/assets/{interface-copy-clipboard.svg-DBVvMdKB.js → interface-copy-clipboard.svg-aMsLLdqD.js} +1 -1
  107. package/web/assets/{interface-edit-attachment.svg-Bq9IjtmQ.js → interface-edit-attachment.svg-CVDpgAHo.js} +1 -1
  108. package/web/assets/{interface-edit-binocular.svg-BFUljAkg.js → interface-edit-binocular.svg-DCXRjTEQ.js} +1 -1
  109. package/web/assets/{interface-edit-magic-wand.svg-DSWYEf6V.js → interface-edit-magic-wand.svg-CDrPrWdl.js} +1 -1
  110. package/web/assets/{interface-edit-tool-paint-roller.svg-iMYCD-Af.js → interface-edit-tool-paint-roller.svg-UvpUIvX7.js} +1 -1
  111. package/web/assets/{interface-edit-tool-pencil.svg-D7jUKckt.js → interface-edit-tool-pencil.svg-vPXMlfGL.js} +1 -1
  112. package/web/assets/{interface-favorite-award.svg-CLCdfKlW.js → interface-favorite-award.svg-CZOrIvmM.js} +1 -1
  113. package/web/assets/{interface-favorite-flag.svg-CMNediEx.js → interface-favorite-flag.svg-CP5RiVtW.js} +1 -1
  114. package/web/assets/{interface-favorite-heart.svg-9AfGidiX.js → interface-favorite-heart.svg-B9yhOFXg.js} +1 -1
  115. package/web/assets/{interface-favorite-star.svg-DD76FDcq.js → interface-favorite-star.svg-B5Iv-JuP.js} +1 -1
  116. package/web/assets/{interface-favorite-stars-sparkles.svg-DZmc8XpZ.js → interface-favorite-stars-sparkles.svg-Cipb48vc.js} +1 -1
  117. package/web/assets/{interface-hierarchy-flowchart.svg-DbdQ6BrN.js → interface-hierarchy-flowchart.svg-BCEm8EoC.js} +1 -1
  118. package/web/assets/{interface-home-house.svg-BIWYFqhm.js → interface-home-house.svg-Bh5-1B_X.js} +1 -1
  119. package/web/assets/{interface-hyperlink.svg-CknF1YxB.js → interface-hyperlink.svg-DmOAt5ZG.js} +1 -1
  120. package/web/assets/{interface-lighting-brightness.svg-B3Svsmp0.js → interface-lighting-brightness.svg-DhHJhRaa.js} +1 -1
  121. package/web/assets/{interface-lock-closed.svg-CTmwhMsF.js → interface-lock-closed.svg-CDyidwZF.js} +1 -1
  122. package/web/assets/{interface-lock-open-unlock.svg-BSC0HJE5.js → interface-lock-open-unlock.svg-Y-4_5Lj-.js} +1 -1
  123. package/web/assets/{interface-login-key.svg-CmPadurO.js → interface-login-key.svg-C8M65861.js} +1 -1
  124. package/web/assets/{interface-search.svg-BbWqGsiC.js → interface-search.svg-gkEckiep.js} +1 -1
  125. package/web/assets/{interface-setting-cog.svg-D336jNxR.js → interface-setting-cog.svg-B42Ru0QR.js} +1 -1
  126. package/web/assets/{interface-share-megaphone-bullhorn.svg-BEPIq-yB.js → interface-share-megaphone-bullhorn.svg-BXgemPpH.js} +1 -1
  127. package/web/assets/{interface-share-rocket.svg-bi0Fp7B7.js → interface-share-rocket.svg-BpCNXSJv.js} +1 -1
  128. package/web/assets/{interface-share-satellite.svg-DZ-FBSOP.js → interface-share-satellite.svg-UqTKwPgB.js} +1 -1
  129. package/web/assets/{interface-share-space-ship.svg-CL8kfexn.js → interface-share-space-ship.svg-LjpxJCju.js} +1 -1
  130. package/web/assets/{interface-share.svg-B4NzC8MW.js → interface-share.svg-aTfbQymz.js} +1 -1
  131. package/web/assets/{interface-signal-square.svg-Do9HNC1g.js → interface-signal-square.svg-BV84IA7I.js} +1 -1
  132. package/web/assets/{interface-time-clock-circle.svg-BiwVEBFE.js → interface-time-clock-circle.svg-B9p8ScHG.js} +1 -1
  133. package/web/assets/{interface-time-hour-glass.svg-Bj4400VR.js → interface-time-hour-glass.svg-4jjplFkz.js} +1 -1
  134. package/web/assets/{interface-users-multiple.svg-wf0xHt7S.js → interface-users-multiple.svg-D4nN3V4C.js} +1 -1
  135. package/web/assets/{interface-weather-moon.svg-CHq44y1K.js → interface-weather-moon.svg-DyfDXGyQ.js} +1 -1
  136. package/web/assets/{javascript-C5gAX9Ho.js → javascript-DxiQ5ZFe.js} +1 -1
  137. package/web/assets/{jsonMode-Cah11eZC.js → jsonMode-R5AgiRt8.js} +2 -2
  138. package/web/assets/{liquid-CS5lfWiD.js → liquid-BPHysTNM.js} +1 -1
  139. package/web/assets/{lspLanguageFeatures-DrQCZerv.js → lspLanguageFeatures-DVsCw49O.js} +3 -3
  140. package/web/assets/{mail-chat-bubble-square.svg-Bn4lLCAH.js → mail-chat-bubble-square.svg-Bgj_m98i.js} +1 -1
  141. package/web/assets/{mail-send-email-paper-airplane.svg-0dbuhy9s.js → mail-send-email-paper-airplane.svg-Cmgs5A9c.js} +1 -1
  142. package/web/assets/{mail-send-envelope.svg-D7MrBGJp.js → mail-send-envelope.svg-DXtZA2de.js} +1 -1
  143. package/web/assets/{mdx-B4jzso3k.js → mdx-BmXvPH9O.js} +1 -1
  144. package/web/assets/{message-DnHiYCym.js → message-DUmeTDJC.js} +2 -2
  145. package/web/assets/{minus-BbLiFqfk.js → minus-_526hTAz.js} +2 -2
  146. package/web/assets/modal-DWnz3LAY.js +5 -0
  147. package/web/assets/modal-SaIxK3oE.js +1 -0
  148. package/web/assets/{money-cashier-receipt.svg-C3G7AK7q.js → money-cashier-receipt.svg-BKLBvJ6k.js} +1 -1
  149. package/web/assets/{money-currency-dollar-pay.svg-DCj0-yon.js → money-currency-dollar-pay.svg-Dy__wPDu.js} +1 -1
  150. package/web/assets/{money-graph-arrow-increase.svg-DxdQlcuf.js → money-graph-arrow-increase.svg-CY6efGa2.js} +1 -1
  151. package/web/assets/{money-graph-bar-chart-increase.svg-Cm-WIBNr.js → money-graph-bar-chart-increase.svg-DeWwVE-h.js} +1 -1
  152. package/web/assets/multiselect-sCEC4UBn.js +251 -0
  153. package/web/assets/{nature-ecology-leaf.svg-BDz3LTpd.js → nature-ecology-leaf.svg-CiA8xWzT.js} +1 -1
  154. package/web/assets/{password-DEuFV3TX.js → password-BjWenHiO.js} +4 -4
  155. package/web/assets/{phone-telephone.svg-DRL7_jEB.js → phone-telephone.svg-DFkp7qtJ.js} +1 -1
  156. package/web/assets/{plus-CdxO2Yq9.js → plus-CM2XaJYz.js} +6 -6
  157. package/web/assets/process.store-BdrVU3j7.js +1 -0
  158. package/web/assets/{programming-bug.svg-BDftmfZl.js → programming-bug.svg-iTd4z5Bn.js} +1 -1
  159. package/web/assets/{programming-cloud.svg-i-GCH3f4.js → programming-cloud.svg-BhZ7wR70.js} +1 -1
  160. package/web/assets/{programming-computer-database-server.svg-CC2MM4RA.js → programming-computer-database-server.svg-CNFgEADa.js} +1 -1
  161. package/web/assets/{programming-computer-database.svg-CwD3IE7b.js → programming-computer-database.svg-BLUoB0S3.js} +1 -1
  162. package/web/assets/{programming-module-four-layout.svg-L5WQW7eZ.js → programming-module-four-layout.svg---ShQt1c.js} +1 -1
  163. package/web/assets/{programming-module-three.svg-BqKxUh2a.js → programming-module-three.svg-Q915QePI.js} +1 -1
  164. package/web/assets/{programming-module.svg-B5HGxk_5.js → programming-module.svg-DGlB0gXU.js} +1 -1
  165. package/web/assets/{programming-script-code.svg-C6b1t67U.js → programming-script-code.svg-BXqoqM0a.js} +1 -1
  166. package/web/assets/{python-PWdcATjU.js → python-Bkcdd-GB.js} +1 -1
  167. package/web/assets/{razor-D2OFUF9W.js → razor-Dgss4zhv.js} +1 -1
  168. package/web/assets/router-CkyZcpB5.js +1 -0
  169. package/web/assets/settings-scope-UnTi3EI6.js +1 -0
  170. package/web/assets/settings.store-Bd6azayI.js +1 -0
  171. package/web/assets/{shopping-cart.svg-C4eUOPuW.js → shopping-cart.svg-DFzDn0s3.js} +1 -1
  172. package/web/assets/{shopping-gift-present.svg-DWR1Ue0b.js → shopping-gift-present.svg-CzoIs_fz.js} +1 -1
  173. package/web/assets/{shopping-shipping-box-parcel-package.svg-vIUMJCzM.js → shopping-shipping-box-parcel-package.svg-K83gZueW.js} +1 -1
  174. package/web/assets/src-Bn8iaJpP.js +1 -0
  175. package/web/assets/{src-D3B9QT3f.js → src-CrlKkUl0.js} +34 -34
  176. package/web/assets/{tabpanel-Dt8wxAUn.js → tabpanel-B8p6e6cv.js} +3 -3
  177. package/web/assets/{tag-new-circle.svg-CrLYLp-g.js → tag-new-circle.svg-BgOrOZ_K.js} +1 -1
  178. package/web/assets/{toggleswitch-DXNKoD3W.js → toggleswitch-BKr-TR6_.js} +2 -2
  179. package/web/assets/{travel-map-earth-globe.svg-CbJkEfGx.js → travel-map-earth-globe.svg-DZQQPdM1.js} +1 -1
  180. package/web/assets/trpc-CPHyoQZL.js +1 -0
  181. package/web/assets/{tsMode-BWnOhIDG.js → tsMode-BO9AVz77.js} +6 -6
  182. package/web/assets/{typescript-Ca6d0Xpt.js → typescript-BVxNZ4YH.js} +1 -1
  183. package/web/assets/useAiChatDrawer-tj6s1XKR.js +1 -0
  184. package/web/assets/useCloudOrg-CXnReqbv.js +97 -0
  185. package/web/assets/{useProjectCatalog-T9HoUKsV.js → useProjectCatalog-Cw3YywvF.js} +1 -1
  186. package/web/assets/{xml-DJnU4yP8.js → xml-Bv9vIo84.js} +1 -1
  187. package/web/assets/{yaml-DJC6BhFp.js → yaml-Brrhr_WI.js} +1 -1
  188. package/web/index.html +1 -1
  189. package/agent-manager-LBV3CVHB.js +0 -7
  190. package/chunk-OTJQEK4D.js.map +0 -1
  191. package/src-MY5W5AYS.js.map +0 -1
  192. package/web/assets/AgentScalarChatInterface.vue-369U2Skl.js +0 -13
  193. package/web/assets/AgentTerminalPage-RHehuR0e.js +0 -1
  194. package/web/assets/AiChatPage-BbgFeCu5.js +0 -1
  195. package/web/assets/AppLayout-CvEbrCSS.js +0 -1
  196. package/web/assets/AuditPage-BRBcRwff.js +0 -1
  197. package/web/assets/CloudAccountPage-C9Y4zQYc.js +0 -1
  198. package/web/assets/CloudAccountPage-DmDrYdSX.js +0 -1
  199. package/web/assets/CloudMessagingPage-j2dztUz1.js +0 -2
  200. package/web/assets/DashboardPage-DbgOaKaI.js +0 -1
  201. package/web/assets/DirectoryPickerDialog-B5a7tO0P.js +0 -1
  202. package/web/assets/EnvironmentFormPage-VkOp77jY.js +0 -1
  203. package/web/assets/EnvironmentListPage-GkrefCj6.js +0 -1
  204. package/web/assets/KanbanBoardPage-CkrXazSk.js +0 -4
  205. package/web/assets/KanbanListPage-CtC0GWl8.js +0 -1
  206. package/web/assets/LaunchProjectPage-Zx3L-5pP.js +0 -1
  207. package/web/assets/LaunchServicesPage-Du56bNpD.js +0 -1
  208. package/web/assets/LogViewer-CusYWOVz.js +0 -3
  209. package/web/assets/OrgKeyPrompt-BhsICoTI.js +0 -1
  210. package/web/assets/ProcessDetailPage-h8RXTZkW.js +0 -1
  211. package/web/assets/ProjectDetailPage-B_fowFne.js +0 -1
  212. package/web/assets/ProjectListPage-DA9HaZW1.js +0 -1
  213. package/web/assets/RandomJobTestPage-BlKmN8WR.js +0 -2
  214. package/web/assets/ScenarioEditorPage-DxmF9C9y.js +0 -14
  215. package/web/assets/SendToChatDialog-CKDis_oY.js +0 -1
  216. package/web/assets/ServiceControlsBar-DqWOWB8l.js +0 -1
  217. package/web/assets/ServiceDetailPage-D4w7i_m0.js +0 -2
  218. package/web/assets/ServiceFormPage-D9EeSeKX.js +0 -1
  219. package/web/assets/SettingsPage-1zz5wMpp.js +0 -2063
  220. package/web/assets/UnlockPage-C4b4tv9Z.js +0 -1
  221. package/web/assets/VariablesTable-B4h9eNC_.css +0 -1
  222. package/web/assets/VariablesTable-BQW0OS3C.js +0 -1
  223. package/web/assets/VaultMigrationPage-B24yEz24.js +0 -1
  224. package/web/assets/VersionBadge-AuIQKahq.js +0 -1
  225. package/web/assets/WikiPage-YnXchmy7.js +0 -1
  226. package/web/assets/WikiView-B4FOcZxi.js +0 -1
  227. package/web/assets/add-scalar-classes-Bb4tLm0z.js +0 -387
  228. package/web/assets/auth-errors-CtC8HAvD.js +0 -1
  229. package/web/assets/cloud-chat.store-JxTqY8hH.js +0 -1
  230. package/web/assets/cloud-session-BsgS9t9u.js +0 -1
  231. package/web/assets/column-C1iIQeFS.js +0 -907
  232. package/web/assets/interface-content-folder.svg-DNkHJfTi.js +0 -1
  233. package/web/assets/modal-BVB2xBJ_.js +0 -1
  234. package/web/assets/modal-dKcYqKht.js +0 -5
  235. package/web/assets/multiselect-C8IBJ6lu.js +0 -251
  236. package/web/assets/process.store-CauAk_PY.js +0 -1
  237. package/web/assets/router-WC51nlcm.js +0 -1
  238. package/web/assets/settings-scope-CIL2r-x6.js +0 -1
  239. package/web/assets/settings.store-Cx63DJSu.js +0 -1
  240. package/web/assets/src-CG6NRFnq.js +0 -1
  241. package/web/assets/trpc-BTkvhuSo.js +0 -1
  242. package/web/assets/useAiChatDrawer-DbiVGX1A.js +0 -1
  243. package/web/assets/useCloudOrg-JI0t8ZfS.js +0 -97
  244. /package/{agent-manager-LBV3CVHB.js.map → agent-manager-DM6C7BTF.js.map} +0 -0
package/agent/index.js CHANGED
@@ -66,767 +66,54 @@ import { TRPCError as TRPCError2 } from "@trpc/server";
66
66
  // src/services/process-manager.ts
67
67
  import { EventEmitter as EventEmitter7 } from "events";
68
68
  import { randomUUID as randomUUID3 } from "crypto";
69
- import { networkInterfaces } from "os";
69
+ import { networkInterfaces, homedir as homedir5, platform as platform2 } from "os";
70
70
  import { join as join3, isAbsolute, resolve } from "path";
71
71
 
72
- // ../../packages/runner-native/src/native-runner.ts
73
- import { execa } from "execa";
74
- import { execSync } from "child_process";
75
- import { homedir } from "os";
72
+ // ../../packages/shared/src/schemas/user.schema.ts
73
+ import { z } from "zod";
74
+ var UserSchema = z.object({
75
+ id: z.string().max(128),
76
+ email: z.string().email().max(320),
77
+ name: z.string().min(1).max(500),
78
+ avatar: z.string().url().max(2048).nullable().optional()
79
+ });
76
80
 
77
- // ../../node_modules/shellwords/dist/esm/index.js
78
- var scan = (string, pattern, callback) => {
79
- let result = "";
80
- while (string.length > 0) {
81
- const match = string.match(pattern);
82
- if (match && match.index != null && match[0] != null) {
83
- result += string.slice(0, match.index);
84
- result += callback(match);
85
- string = string.slice(match.index + match[0].length);
86
- } else {
87
- result += string;
88
- string = "";
89
- }
90
- }
91
- return result;
92
- };
93
- var split = (line = "") => {
94
- const words = [];
95
- let field = "";
96
- scan(
97
- line,
98
- /\s*(?:([^\s\\'"]+)|'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)"|(\\.?)|(\S))(\s|$)?/,
99
- (match) => {
100
- const [_raw, word, sq, dq, escape2, garbage, separator] = match;
101
- if (garbage != null) {
102
- throw new Error(`Unmatched quote: ${line}`);
103
- }
104
- if (word) {
105
- field += word;
106
- } else {
107
- let addition;
108
- if (sq) {
109
- addition = sq;
110
- } else if (dq) {
111
- addition = dq;
112
- } else if (escape2) {
113
- addition = escape2;
114
- }
115
- if (addition) {
116
- field += addition.replace(/\\(?=.)/, "");
117
- }
118
- }
119
- if (separator != null) {
120
- words.push(field);
121
- field = "";
122
- }
123
- }
124
- );
125
- if (field) {
126
- words.push(field);
127
- }
128
- return words;
129
- };
81
+ // ../../packages/shared/src/schemas/org.schema.ts
82
+ import { z as z2 } from "zod";
83
+ var OrgSchema = z2.object({
84
+ id: z2.string().max(128),
85
+ name: z2.string().min(1).max(100),
86
+ slug: z2.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),
87
+ ownerId: z2.string().max(128)
88
+ });
89
+ var OrgMemberSchema = z2.object({
90
+ id: z2.string().max(128),
91
+ orgId: z2.string().max(128),
92
+ userId: z2.string().max(128),
93
+ globalRole: z2.enum(["owner", "admin", "member"]),
94
+ invitedAt: z2.coerce.date(),
95
+ joinedAt: z2.coerce.date().nullable().optional()
96
+ });
130
97
 
131
- // ../../packages/runner-native/src/native-runner.ts
132
- var shellwordsSplit = split;
133
- function expandEnvVars(str, serviceEnv) {
134
- const withHome = str.replace(/^~(\/|$)/, `${homedir()}$1`);
135
- return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
136
- const name = braced ?? plain;
137
- return serviceEnv?.[name] ?? "";
138
- });
139
- }
140
- function resolveCwd(cwd, env2) {
141
- if (!cwd) return ".";
142
- return expandEnvVars(cwd, env2) || ".";
143
- }
144
- function findUnresolvedEnvVars(str, serviceEnv) {
145
- const unresolved = [];
146
- str.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
147
- const name = braced ?? plain;
148
- if (serviceEnv?.[name] === void 0) {
149
- unresolved.push(name);
150
- }
151
- return "";
152
- });
153
- return unresolved;
154
- }
155
- var SYSTEM_PATH_DIRS = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"];
156
- function buildSafeEnv(configEnv = {}) {
157
- const safeKeys = ["PATH", "HOME", "USER", "SHELL", "LANG", "TERM", "NODE_ENV", "TMPDIR", "TZ", "DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR"];
158
- const env2 = {};
159
- for (const key of safeKeys) {
160
- if (process.env[key]) {
161
- env2[key] = process.env[key];
162
- }
163
- }
164
- const existingPath = env2["PATH"] ?? "";
165
- const existingDirs = new Set(existingPath.split(":").filter(Boolean));
166
- const missingDirs = SYSTEM_PATH_DIRS.filter((d) => !existingDirs.has(d));
167
- if (missingDirs.length > 0) {
168
- env2["PATH"] = [existingPath, ...missingDirs].filter(Boolean).join(":");
169
- }
170
- return { ...env2, ...configEnv };
171
- }
172
- var NativeRunner = class {
173
- type = "native";
174
- start(config) {
175
- let subprocess;
176
- const cwd = resolveCwd(config.cwd, config.env);
177
- const isWindows = process.platform === "win32";
178
- if (config.shell) {
179
- subprocess = execa(config.command, {
180
- cwd,
181
- env: buildSafeEnv(config.env),
182
- shell: true,
183
- detached: !isWindows,
184
- // Create new process group for group kill (not supported on Windows)
185
- windowsHide: true,
186
- // Prevent terminal windows from appearing on Windows
187
- stdio: ["ignore", "pipe", "pipe"],
188
- reject: false,
189
- // Don't throw on non-zero exit
190
- buffer: false
191
- // Don't accumulate stdout/stderr in memory — we stream via readline
192
- });
193
- } else {
194
- const args = shellwordsSplit(config.command);
195
- const cmd = args.shift();
196
- if (!cmd) {
197
- throw new Error("Invalid command: cannot parse empty or whitespace-only command");
198
- }
199
- subprocess = execa(cmd, args, {
200
- cwd,
201
- env: buildSafeEnv(config.env),
202
- shell: false,
203
- // SECURITY: shell:false prevents command injection
204
- detached: !isWindows,
205
- // Create new process group for group kill (not supported on Windows)
206
- windowsHide: true,
207
- // Prevent terminal windows from appearing on Windows
208
- stdio: ["ignore", "pipe", "pipe"],
209
- reject: false,
210
- // Don't throw on non-zero exit
211
- buffer: false
212
- // Don't accumulate stdout/stderr in memory — we stream via readline
213
- });
214
- }
215
- const exitPromise = new Promise((resolve2) => {
216
- subprocess.then((result) => {
217
- resolve2({
218
- exitCode: result.exitCode ?? null,
219
- signal: result.signal ?? null,
220
- error: result.failed && result.shortMessage ? result.shortMessage : void 0
221
- });
222
- }).catch((err) => {
223
- resolve2({ exitCode: 1, signal: null, error: err.message ?? "Unknown error" });
224
- });
225
- });
226
- return {
227
- pid: subprocess.pid,
228
- kill(signal = "SIGTERM") {
229
- try {
230
- if (process.platform === "win32") {
231
- if (!subprocess.pid) return false;
232
- execSync(`taskkill /F /T /PID ${subprocess.pid}`, { stdio: "ignore" });
233
- return true;
234
- }
235
- if (subprocess.pid) {
236
- process.kill(-subprocess.pid, signal);
237
- return true;
238
- }
239
- return subprocess.kill(signal);
240
- } catch {
241
- return false;
242
- }
243
- },
244
- stdout: subprocess.stdout,
245
- stderr: subprocess.stderr,
246
- exitPromise
247
- };
248
- }
249
- async isAvailable() {
250
- return true;
251
- }
252
- };
253
-
254
- // ../../packages/runner-docker/src/index.ts
255
- import { execa as execa2 } from "execa";
256
- import { PassThrough } from "stream";
257
- import { randomUUID } from "crypto";
258
- import { writeFile, unlink, mkdir } from "fs/promises";
259
- import { tmpdir, homedir as homedir2, userInfo } from "os";
260
- import { join } from "path";
261
- function splitShellArgs(cmd) {
262
- const args = [];
263
- let current = "";
264
- let inSingle = false;
265
- let inDouble = false;
266
- for (let i = 0; i < cmd.length; i++) {
267
- const ch = cmd[i];
268
- if (ch === "'" && !inDouble) {
269
- inSingle = !inSingle;
270
- } else if (ch === '"' && !inSingle) {
271
- inDouble = !inDouble;
272
- } else if (ch === "\\" && inDouble && i + 1 < cmd.length) {
273
- current += cmd[++i];
274
- } else if (/\s/.test(ch) && !inSingle && !inDouble) {
275
- if (current) {
276
- args.push(current);
277
- current = "";
278
- }
279
- } else {
280
- current += ch;
281
- }
282
- }
283
- if (current) args.push(current);
284
- return args;
285
- }
286
- function sanitizeDockerName(name) {
287
- return name.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/-{2,}/g, "-");
288
- }
289
- function expandEnvVars2(str, serviceEnv) {
290
- const withHome = str.replace(/^~(\/|$)/, `${homedir2()}$1`);
291
- return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
292
- const name = braced ?? plain;
293
- return serviceEnv?.[name] ?? "";
294
- });
295
- }
296
- async function preMkdirVolumes(volumes, serviceEnv) {
297
- for (const v of volumes) {
298
- const expanded = expandEnvVars2(v, serviceEnv);
299
- const parts = expanded.split(":");
300
- if (parts.length < 2) continue;
301
- const hostPath = parts[0];
302
- if (!hostPath.startsWith("/") && !hostPath.startsWith(".")) continue;
303
- await mkdir(hostPath, { recursive: true }).catch(() => {
304
- });
305
- }
306
- }
307
- var DockerRunner = class {
308
- type = "docker";
309
- start(config) {
310
- const stdout = new PassThrough();
311
- const stderr = new PassThrough();
312
- const containerName = sanitizeDockerName(config.cmdId ? `runeya-${config.serviceId}-${config.cmdId}` : `runeya-${config.serviceId}`);
313
- let killed = false;
314
- const exitPromise = new Promise(
315
- (resolve2) => {
316
- void (async () => {
317
- try {
318
- await execa2("docker", ["rm", "-f", containerName], { reject: false });
319
- const dc = config.dockerConfig;
320
- let lastCardId = null;
321
- const envFlags = Object.entries(config.env ?? {}).flatMap(
322
- ([k, v]) => ["-e", `${k}=${v}`]
323
- );
324
- await preMkdirVolumes(dc.volumes ?? [], config.env);
325
- const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
326
- if (dc.mountRootpath && config.cwd) {
327
- volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
328
- }
329
- if (dc.image && !dc.dockerfile) {
330
- lastCardId = randomUUID();
331
- stdout.write(
332
- "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n"
333
- );
334
- const pull = execa2("docker", ["pull", dc.image], { reject: false });
335
- pull.stdout?.pipe(stdout, { end: false });
336
- pull.stderr?.pipe(stderr, { end: false });
337
- await pull;
338
- }
339
- let imageName = dc.image ?? containerName + ":latest";
340
- if (dc.dockerfile) {
341
- lastCardId = randomUUID();
342
- stdout.write(
343
- "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n"
344
- );
345
- const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
346
- try {
347
- await writeFile(tmpFile, dc.dockerfile, "utf8");
348
- const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(
349
- ([k, v]) => ["--build-arg", `${k}=${v}`]
350
- );
351
- const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
352
- const buildContext = dc.buildContext ?? config.cwd ?? ".";
353
- imageName = `${containerName}:latest`;
354
- const build = execa2(
355
- "docker",
356
- ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext],
357
- { reject: false }
358
- );
359
- build.stdout?.pipe(stdout, { end: false });
360
- build.stderr?.pipe(stderr, { end: false });
361
- await build;
362
- } finally {
363
- await unlink(tmpFile).catch(() => {
364
- });
365
- }
366
- }
367
- if (killed) {
368
- resolve2({ exitCode: null, signal: "SIGTERM" });
369
- return;
370
- }
371
- if (lastCardId) {
372
- stdout.write(
373
- "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n"
374
- );
375
- }
376
- const bootstrapCmds = config.skipBootstrap ? [] : (dc.bootstrapCommands ?? []).filter((c) => c.command.trim());
377
- for (const bsCmd of bootstrapCmds) {
378
- if (killed) {
379
- resolve2({ exitCode: null, signal: "SIGTERM" });
380
- return;
381
- }
382
- const bsCardId = randomUUID();
383
- const bsCmdName = bsCmd.label || bsCmd.command;
384
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "bootstrap", _cardId: bsCardId, _cardState: "open", message: `Bootstrap: ${bsCmdName}` })}
385
- `);
386
- const exitCode = await this.runBootstrap(bsCmd, imageName, config.env ?? {}, dc.volumes ?? [], stdout, stderr);
387
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: bsCardId, _cardState: "close" })}
388
- `);
389
- if (exitCode !== 0) {
390
- stderr.write(`Bootstrap command "${bsCmdName}" failed with exit code ${exitCode}
391
- `);
392
- resolve2({ exitCode, signal: null, error: `Bootstrap "${bsCmdName}" failed (exit ${exitCode})` });
393
- return;
394
- }
395
- }
396
- if (killed) {
397
- resolve2({ exitCode: null, signal: "SIGTERM" });
398
- return;
399
- }
400
- const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
401
- let cmdArgs;
402
- let entrypointFlags;
403
- if (dc.useNativeCommand) {
404
- const shell = dc.nativeShell || "sh";
405
- entrypointFlags = [];
406
- cmdArgs = config.command ? [shell, "-c", config.command] : [];
407
- } else {
408
- entrypointFlags = dc.entrypoint ? ["--entrypoint", dc.entrypoint] : [];
409
- cmdArgs = dc.command ? splitShellArgs(dc.command) : [];
410
- }
411
- const { uid, gid } = userInfo();
412
- const rmFlag = config.rm ? ["--rm"] : [];
413
- const runArgs = [
414
- "run",
415
- ...rmFlag,
416
- "--init",
417
- "--name",
418
- containerName,
419
- "--user",
420
- dc.user || `${uid}:${gid}`,
421
- ...networkFlags,
422
- ...envFlags,
423
- ...volumeFlags,
424
- ...entrypointFlags,
425
- imageName,
426
- ...cmdArgs
427
- ];
428
- const debugCardId = randomUUID();
429
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run" })}
430
- `);
431
- stdout.write(`docker ${runArgs.join(" ")}
432
- `);
433
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
434
- `);
435
- const runProc = execa2("docker", runArgs, { reject: false });
436
- runProc.stdout?.pipe(stdout, { end: false });
437
- runProc.stderr?.pipe(stderr, { end: false });
438
- const result = await runProc;
439
- resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
440
- } catch (err) {
441
- const msg = err instanceof Error ? err.message : String(err);
442
- stderr.write(`Docker infrastructure error: ${msg}
443
- `);
444
- resolve2({ exitCode: 1, signal: null });
445
- } finally {
446
- stdout.end();
447
- stderr.end();
448
- }
449
- })();
450
- }
451
- );
452
- return {
453
- pid: void 0,
454
- containerName,
455
- stdout,
456
- stderr,
457
- exitPromise,
458
- kill(_signal = "SIGTERM") {
459
- killed = true;
460
- execa2("docker", ["stop", containerName]).catch(() => {
461
- });
462
- return true;
463
- }
464
- };
465
- }
466
- /** Start a long-lived container (sleep infinity) for shared mode.
467
- * Returns the RunnerProcess (lifetime) plus a `containerReady` promise that resolves
468
- * once `docker run --detach` has completed and the container is confirmed running.
469
- * Callers must await `containerReady` before calling `execInContainer`. */
470
- startSharedContainer(config) {
471
- const stdout = new PassThrough();
472
- const stderr = new PassThrough();
473
- const containerName = sanitizeDockerName(`runeya-${config.serviceId}`);
474
- let killed = false;
475
- let resolveReady;
476
- let rejectReady;
477
- const containerReady = new Promise((res, rej) => {
478
- resolveReady = res;
479
- rejectReady = rej;
480
- });
481
- let exitResolve;
482
- const exitPromise = new Promise(
483
- (resolve2) => {
484
- exitResolve = resolve2;
485
- }
486
- );
487
- void (async () => {
488
- try {
489
- await execa2("docker", ["rm", "-f", containerName], { reject: false });
490
- const dc = config.dockerConfig;
491
- let lastCardId = null;
492
- const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
493
- await preMkdirVolumes(dc.volumes ?? [], config.env);
494
- const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
495
- if (dc.mountRootpath && config.cwd) {
496
- volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
497
- }
498
- if (dc.image && !dc.dockerfile) {
499
- lastCardId = randomUUID();
500
- stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n");
501
- const pull = execa2("docker", ["pull", dc.image], { reject: false });
502
- pull.stdout?.pipe(stdout, { end: false });
503
- pull.stderr?.pipe(stderr, { end: false });
504
- await pull;
505
- }
506
- let imageName = dc.image ?? containerName + ":latest";
507
- if (dc.dockerfile) {
508
- lastCardId = randomUUID();
509
- stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n");
510
- const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
511
- try {
512
- await writeFile(tmpFile, dc.dockerfile, "utf8");
513
- const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(([k, v]) => ["--build-arg", `${k}=${v}`]);
514
- const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
515
- const buildContext = dc.buildContext ?? config.cwd ?? ".";
516
- imageName = `${containerName}:latest`;
517
- const build = execa2("docker", ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext], { reject: false });
518
- build.stdout?.pipe(stdout, { end: false });
519
- build.stderr?.pipe(stderr, { end: false });
520
- await build;
521
- } finally {
522
- await unlink(tmpFile).catch(() => {
523
- });
524
- }
525
- }
526
- if (killed) {
527
- rejectReady(new Error("Killed before container started"));
528
- exitResolve({ exitCode: null, signal: "SIGTERM" });
529
- return;
530
- }
531
- if (lastCardId) {
532
- stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n");
533
- }
534
- const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
535
- const { uid, gid } = userInfo();
536
- const runArgs = [
537
- "run",
538
- "--detach",
539
- "--init",
540
- "--name",
541
- containerName,
542
- "--user",
543
- dc.user || `${uid}:${gid}`,
544
- ...networkFlags,
545
- ...envFlags,
546
- ...volumeFlags,
547
- imageName,
548
- "sleep",
549
- "infinity"
550
- ];
551
- const debugCardId = randomUUID();
552
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run (shared container)" })}
553
- `);
554
- stdout.write(`docker ${runArgs.join(" ")}
555
- `);
556
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
557
- `);
558
- const runProc = execa2("docker", runArgs, { reject: false });
559
- runProc.stdout?.pipe(stdout, { end: false });
560
- runProc.stderr?.pipe(stderr, { end: false });
561
- const runResult = await runProc;
562
- if (runResult.exitCode !== 0) {
563
- rejectReady(new Error(`docker run exited with code ${runResult.exitCode}`));
564
- exitResolve({ exitCode: runResult.exitCode ?? 1, signal: null });
565
- return;
566
- }
567
- resolveReady();
568
- const waitProc = execa2("docker", ["wait", containerName], { reject: false });
569
- await waitProc;
570
- exitResolve({ exitCode: 0, signal: null });
571
- } catch (err) {
572
- const msg = err instanceof Error ? err.message : String(err);
573
- stderr.write(`Docker infrastructure error: ${msg}
574
- `);
575
- rejectReady(new Error(msg));
576
- exitResolve({ exitCode: 1, signal: null });
577
- } finally {
578
- stdout.end();
579
- stderr.end();
580
- }
581
- })();
582
- return {
583
- pid: void 0,
584
- containerName,
585
- stdout,
586
- stderr,
587
- exitPromise,
588
- containerReady,
589
- kill(_signal = "SIGTERM") {
590
- killed = true;
591
- execa2("docker", ["kill", containerName]).then(() => exitResolve({ exitCode: null, signal: "SIGKILL" })).catch(() => exitResolve({ exitCode: 1, signal: null }));
592
- return true;
593
- }
594
- };
595
- }
596
- /** Run a command inside a running shared container via `docker exec`.
597
- * Kill terminates the docker-exec process but does NOT stop the container. */
598
- execInContainer(containerName, command, envVars = {}, shell = "sh") {
599
- const stdout = new PassThrough();
600
- const stderr = new PassThrough();
601
- let dockerProc = null;
602
- const exitPromise = new Promise(
603
- (resolve2) => {
604
- void (async () => {
605
- try {
606
- const envFlags = Object.entries(envVars).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
607
- const shellCmd = command.length ? command : "true";
608
- dockerProc = execa2(
609
- "docker",
610
- ["exec", ...envFlags, containerName, shell, "-c", shellCmd],
611
- { reject: false }
612
- );
613
- dockerProc.stdout?.pipe(stdout, { end: false });
614
- dockerProc.stderr?.pipe(stderr, { end: false });
615
- const result = await dockerProc;
616
- resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
617
- } catch (err) {
618
- const msg = err instanceof Error ? err.message : String(err);
619
- stderr.write(`docker execInContainer error: ${msg}
620
- `);
621
- resolve2({ exitCode: 1, signal: null });
622
- } finally {
623
- stdout.end();
624
- stderr.end();
625
- }
626
- })();
627
- }
628
- );
629
- return {
630
- pid: void 0,
631
- containerName,
632
- stdout,
633
- stderr,
634
- exitPromise,
635
- kill(_signal = "SIGTERM") {
636
- dockerProc?.kill("SIGTERM");
637
- return true;
638
- }
639
- };
640
- }
641
- /** Run a shortcut command in the context of a Docker service.
642
- * If a service container is running (shared or isolated), uses `docker exec`.
643
- * If not running, reuses `start()` with `--rm` and `skipBootstrap`. */
644
- runShortcut(config, shortcutCommand) {
645
- const stdout = new PassThrough();
646
- const stderr = new PassThrough();
647
- let innerProcess = null;
648
- let dockerProc = null;
649
- const exitPromise = new Promise(
650
- (resolve2) => {
651
- void (async () => {
652
- try {
653
- const psResult = await execa2(
654
- "docker",
655
- ["ps", "--filter", `name=runeya-${config.serviceId}`, "--format", "{{.Names}}"],
656
- { reject: false }
657
- );
658
- const runningContainer = psResult.stdout.trim().split("\n").find((n) => n.startsWith(`runeya-${config.serviceId}`));
659
- if (runningContainer) {
660
- const shell = config.dockerConfig.nativeShell || "sh";
661
- const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
662
- const args = ["exec", ...envFlags, runningContainer, shell, "-c", shortcutCommand || "true"];
663
- const cardId = randomUUID();
664
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "exec", _cardId: cardId, _cardState: "open", message: "Docker Exec" })}
665
- `);
666
- stdout.write(`docker ${args.join(" ")}
667
- `);
668
- stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: cardId, _cardState: "close" })}
669
- `);
670
- dockerProc = execa2("docker", args, { reject: false });
671
- dockerProc.stdout?.pipe(stdout, { end: false });
672
- dockerProc.stderr?.pipe(stderr, { end: false });
673
- const result = await dockerProc;
674
- resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
675
- } else {
676
- innerProcess = this.start({
677
- ...config,
678
- command: shortcutCommand,
679
- cmdId: `shortcut-${randomUUID()}`,
680
- rm: true,
681
- skipBootstrap: true,
682
- dockerConfig: { ...config.dockerConfig, useNativeCommand: true }
683
- });
684
- innerProcess.stdout?.pipe(stdout, { end: false });
685
- innerProcess.stderr?.pipe(stderr, { end: false });
686
- const result = await innerProcess.exitPromise;
687
- resolve2(result);
688
- }
689
- } catch (err) {
690
- const msg = err instanceof Error ? err.message : String(err);
691
- stderr.write(`docker shortcut error: ${msg}
692
- `);
693
- resolve2({ exitCode: 1, signal: null });
694
- } finally {
695
- stdout.end();
696
- stderr.end();
697
- }
698
- })();
699
- }
700
- );
701
- return {
702
- pid: void 0,
703
- stdout,
704
- stderr,
705
- exitPromise,
706
- kill(signal = "SIGTERM") {
707
- if (innerProcess) return innerProcess.kill(signal);
708
- dockerProc?.kill("SIGTERM");
709
- return true;
710
- }
711
- };
712
- }
713
- async isAvailable() {
714
- const result = await execa2("docker", ["info"], { reject: false });
715
- return result.exitCode === 0;
716
- }
717
- /** Run a single bootstrap command sequentially inside a temporary container (--rm).
718
- * Streams stdout/stderr into the provided PassThrough streams.
719
- * Resolves with the exit code when the container exits. */
720
- async runBootstrap(cmd, imageName, env2, volumes, stdout, stderr) {
721
- const containerName = sanitizeDockerName(`runeya-bootstrap-${randomUUID()}`);
722
- const envFlags = Object.entries(env2).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
723
- await preMkdirVolumes(volumes, env2);
724
- const volumeFlags = volumes.map((v) => expandEnvVars2(v, env2)).flatMap((v) => ["-v", v]);
725
- const entrypointFlags = cmd.entrypoint ? ["--entrypoint", cmd.entrypoint] : [];
726
- const { uid, gid } = userInfo();
727
- const defaultUser = `${uid}:${gid}`;
728
- const userFlags = ["--user", cmd.user || defaultUser];
729
- const cmdArgs = splitShellArgs(cmd.command);
730
- const runArgs = [
731
- "run",
732
- "--rm",
733
- "--init",
734
- "--name",
735
- containerName,
736
- "--network",
737
- "host",
738
- ...envFlags,
739
- ...volumeFlags,
740
- ...entrypointFlags,
741
- ...userFlags,
742
- imageName,
743
- ...cmdArgs
744
- ];
745
- const proc = execa2("docker", runArgs, { reject: false });
746
- proc.stdout?.pipe(stdout, { end: false });
747
- proc.stderr?.pipe(stderr, { end: false });
748
- const result = await proc;
749
- return result.exitCode ?? 1;
750
- }
751
- };
752
-
753
- // src/services/process-store.ts
754
- var ProcessStore = class {
755
- processes = /* @__PURE__ */ new Map();
756
- get(id) {
757
- return this.processes.get(id);
758
- }
759
- getAll() {
760
- return Array.from(this.processes.values());
761
- }
762
- set(id, process2) {
763
- this.processes.set(id, process2);
764
- }
765
- delete(id) {
766
- return this.processes.delete(id);
767
- }
768
- has(id) {
769
- return this.processes.has(id);
770
- }
771
- clear() {
772
- this.processes.clear();
773
- }
774
- getByServiceId(serviceId) {
775
- return this.getAll().find((p) => p.serviceConfig.id === serviceId);
776
- }
777
- };
778
- var processStore = new ProcessStore();
779
-
780
- // src/services/log-sources/console-log-source.ts
781
- import { createInterface } from "readline";
782
- import { EventEmitter } from "events";
783
- import { randomUUID as randomUUID2 } from "crypto";
784
-
785
- // ../../packages/shared/src/schemas/user.schema.ts
786
- import { z } from "zod";
787
- var UserSchema = z.object({
788
- id: z.string().max(128),
789
- email: z.string().email().max(320),
790
- name: z.string().min(1).max(500),
791
- avatar: z.string().url().max(2048).nullable().optional()
792
- });
793
-
794
- // ../../packages/shared/src/schemas/org.schema.ts
795
- import { z as z2 } from "zod";
796
- var OrgSchema = z2.object({
797
- id: z2.string().max(128),
798
- name: z2.string().min(1).max(100),
799
- slug: z2.string().min(1).max(100).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),
800
- ownerId: z2.string().max(128)
801
- });
802
- var OrgMemberSchema = z2.object({
803
- id: z2.string().max(128),
804
- orgId: z2.string().max(128),
805
- userId: z2.string().max(128),
806
- globalRole: z2.enum(["owner", "admin", "member"]),
807
- invitedAt: z2.coerce.date(),
808
- joinedAt: z2.coerce.date().nullable().optional()
809
- });
810
-
811
- // ../../packages/shared/src/schemas/project.schema.ts
812
- import { z as z3 } from "zod";
813
- var ProjectSchema = z3.object({
814
- id: z3.string().max(128),
815
- orgId: z3.string().max(128).nullable().optional(),
816
- name: z3.string().min(1).max(200),
817
- description: z3.string().max(1e4).optional().default(""),
818
- serviceIds: z3.array(z3.string().max(128)).max(1e4).default([]),
819
- // Environment support
820
- // NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)
821
- // It's initialized to 'local' by default at load time
822
- activeEnvironmentId: z3.string().max(128).optional(),
823
- environmentIds: z3.array(z3.string().max(128)).max(100).default([]),
824
- // Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).
825
- // Les groupes absents de cette liste sont affichés après, par ordre alphabétique.
826
- groupOrder: z3.array(z3.string().max(200)).max(100).default([])
827
- });
828
- var CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });
829
- var UpdateProjectSchema = ProjectSchema.partial().required({ id: true });
98
+ // ../../packages/shared/src/schemas/project.schema.ts
99
+ import { z as z3 } from "zod";
100
+ var ProjectSchema = z3.object({
101
+ id: z3.string().max(128),
102
+ orgId: z3.string().max(128).nullable().optional(),
103
+ name: z3.string().min(1).max(200),
104
+ description: z3.string().max(1e4).optional().default(""),
105
+ serviceIds: z3.array(z3.string().max(128)).max(1e4).default([]),
106
+ // Environment support
107
+ // NOTE: activeEnvironmentId is runtime-only (not persisted to JSON)
108
+ // It's initialized to 'local' by default at load time
109
+ activeEnvironmentId: z3.string().max(128).optional(),
110
+ environmentIds: z3.array(z3.string().max(128)).max(100).default([]),
111
+ // Ordre d'affichage des groupes de services dans la sidebar (noms de groupes).
112
+ // Les groupes absents de cette liste sont affichés après, par ordre alphabétique.
113
+ groupOrder: z3.array(z3.string().max(200)).max(100).default([])
114
+ });
115
+ var CreateProjectSchema = ProjectSchema.omit({ id: true }).partial().required({ name: true });
116
+ var UpdateProjectSchema = ProjectSchema.partial().required({ id: true });
830
117
 
831
118
  // ../../packages/shared/src/schemas/service.schema.ts
832
119
  import { z as z7 } from "zod";
@@ -1309,7 +596,16 @@ var AgentStatusSchema = z10.object({
1309
596
  lastSeen: z10.string().nullable().optional(),
1310
597
  uptime: z10.number().nonnegative().default(0),
1311
598
  runnersAvailable: z10.array(z10.enum(["native", "docker"])).default(["native"]),
1312
- lanIp: z10.string().optional()
599
+ lanIp: z10.string().optional(),
600
+ /**
601
+ * Ce que la machine de l'agent vaut pour les builtins de portée `agent`.
602
+ * Sert à PRÉVISUALISER — la valeur injectée reste calculée au lancement, par
603
+ * l'agent lui-même : une IP change, un agent se déconnecte, et un statut
604
+ * n'est qu'un cliché.
605
+ */
606
+ os: z10.string().max(64).optional(),
607
+ home: z10.string().max(4096).optional(),
608
+ cwd: z10.string().max(4096).optional()
1313
609
  });
1314
610
 
1315
611
  // ../../packages/shared/src/schemas/permission.schema.ts
@@ -1721,238 +1017,1000 @@ var KanbanCardRefSchema = z19.object({
1721
1017
  commentCount: z19.number().int().nonnegative().default(0)
1722
1018
  });
1723
1019
 
1724
- // ../../packages/shared/src/schemas/cloud-api-key.schema.ts
1725
- import { z as z20 } from "zod";
1726
- var CloudApiScopeSchema = z20.enum([
1727
- "kanban:read",
1728
- "kanban:write",
1729
- "kanban:comment",
1730
- "kanban:delete"
1731
- ]);
1732
- var CloudApiKeySecretSchema = z20.string().regex(/^rk_[0-9a-f]{64}$/);
1733
- var CloudApiKeySchema = z20.object({
1734
- id: z20.string().max(128),
1735
- organizationId: z20.string().max(128),
1736
- name: z20.string().min(1).max(200),
1737
- scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
1738
- /**
1739
- * Les tableaux que la clé peut atteindre, ou `null` pour « tous ceux de
1740
- * l'organisation ».
1741
- *
1742
- * `null` et `[]` ne sont pas la même chose : la liste vide n'ouvre rien, et
1743
- * c'est délibéré — un tableau supprimé ne doit pas élargir une clé qui ne le
1744
- * nommait plus que lui.
1745
- */
1746
- boards: z20.array(z20.string().max(64)).max(200).nullable(),
1747
- createdAt: z20.string().max(64),
1748
- /** Dernier usage constaté, pour reconnaître une clé oubliée. */
1749
- lastUsedAt: z20.string().max(64).nullable(),
1750
- /** Qui l'a émise — une clé sans visage ne se révoque jamais sereinement. */
1751
- createdBy: z20.object({ id: z20.string().max(128), name: z20.string().max(200) }),
1752
- /** Les 4 derniers caractères du secret, pour reconnaître une clé dans une liste. */
1753
- keyPreview: z20.string().max(8)
1754
- });
1755
- var CreatedCloudApiKeySchema = z20.object({
1756
- key: CloudApiKeySchema,
1757
- secret: CloudApiKeySecretSchema
1758
- });
1759
- var CreateCloudApiKeyInput = z20.object({
1760
- organizationId: z20.string().min(1).max(128),
1761
- name: z20.string().min(1).max(200),
1762
- scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
1763
- boards: z20.array(z20.string().max(64)).max(200).nullable().default(null)
1764
- });
1765
- var UpdateCloudApiKeyInput = z20.object({
1766
- id: z20.string().min(1).max(128),
1767
- name: z20.string().min(1).max(200).optional(),
1768
- scopes: z20.array(CloudApiScopeSchema).min(1).max(10).optional(),
1769
- boards: z20.array(z20.string().max(64)).max(200).nullable().optional()
1770
- });
1020
+ // ../../packages/shared/src/schemas/cloud-api-key.schema.ts
1021
+ import { z as z20 } from "zod";
1022
+ var CloudApiScopeSchema = z20.enum([
1023
+ "kanban:read",
1024
+ "kanban:write",
1025
+ "kanban:comment",
1026
+ "kanban:delete"
1027
+ ]);
1028
+ var CloudApiKeySecretSchema = z20.string().regex(/^rk_[0-9a-f]{64}$/);
1029
+ var CloudApiKeySchema = z20.object({
1030
+ id: z20.string().max(128),
1031
+ organizationId: z20.string().max(128),
1032
+ name: z20.string().min(1).max(200),
1033
+ scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
1034
+ /**
1035
+ * Les tableaux que la clé peut atteindre, ou `null` pour « tous ceux de
1036
+ * l'organisation ».
1037
+ *
1038
+ * `null` et `[]` ne sont pas la même chose : la liste vide n'ouvre rien, et
1039
+ * c'est délibéré — un tableau supprimé ne doit pas élargir une clé qui ne le
1040
+ * nommait plus que lui.
1041
+ */
1042
+ boards: z20.array(z20.string().max(64)).max(200).nullable(),
1043
+ createdAt: z20.string().max(64),
1044
+ /** Dernier usage constaté, pour reconnaître une clé oubliée. */
1045
+ lastUsedAt: z20.string().max(64).nullable(),
1046
+ /** Qui l'a émise — une clé sans visage ne se révoque jamais sereinement. */
1047
+ createdBy: z20.object({ id: z20.string().max(128), name: z20.string().max(200) }),
1048
+ /** Les 4 derniers caractères du secret, pour reconnaître une clé dans une liste. */
1049
+ keyPreview: z20.string().max(8)
1050
+ });
1051
+ var CreatedCloudApiKeySchema = z20.object({
1052
+ key: CloudApiKeySchema,
1053
+ secret: CloudApiKeySecretSchema
1054
+ });
1055
+ var CreateCloudApiKeyInput = z20.object({
1056
+ organizationId: z20.string().min(1).max(128),
1057
+ name: z20.string().min(1).max(200),
1058
+ scopes: z20.array(CloudApiScopeSchema).min(1).max(10),
1059
+ boards: z20.array(z20.string().max(64)).max(200).nullable().default(null)
1060
+ });
1061
+ var UpdateCloudApiKeyInput = z20.object({
1062
+ id: z20.string().min(1).max(128),
1063
+ name: z20.string().min(1).max(200).optional(),
1064
+ scopes: z20.array(CloudApiScopeSchema).min(1).max(10).optional(),
1065
+ boards: z20.array(z20.string().max(64)).max(200).nullable().optional()
1066
+ });
1067
+
1068
+ // ../../packages/shared/src/utils/crypto.ts
1069
+ import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from "crypto";
1070
+
1071
+ // ../../packages/shared/src/js-log-parser.ts
1072
+ import vm from "vm";
1073
+ var VALID_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error", "fatal"]);
1074
+ var PARSE_TIMEOUT_MS = 50;
1075
+ var MAX_CONSECUTIVE_TIMEOUTS = 10;
1076
+ var JSLogParser = class {
1077
+ parsers = [];
1078
+ constructor(definitions = []) {
1079
+ this.setParsers(definitions);
1080
+ }
1081
+ setParsers(definitions) {
1082
+ this.parsers = [];
1083
+ for (const def of definitions) {
1084
+ if (!def.enabled) continue;
1085
+ try {
1086
+ const compiled = this.compileParser(def);
1087
+ this.parsers.push({
1088
+ id: def.id,
1089
+ name: def.name,
1090
+ enabled: true,
1091
+ fn: compiled
1092
+ });
1093
+ } catch (err) {
1094
+ console.warn(
1095
+ `[js-log-parser] Failed to compile parser "${def.name}" (${def.id}): ${err instanceof Error ? err.message : String(err)}`
1096
+ );
1097
+ }
1098
+ }
1099
+ }
1100
+ parse(line) {
1101
+ let current = line;
1102
+ for (const parser of this.parsers) {
1103
+ try {
1104
+ current = parser.fn(current);
1105
+ } catch (err) {
1106
+ console.warn(
1107
+ `[js-log-parser] Parser "${parser.name}" threw error: ${err instanceof Error ? err.message : String(err)}`
1108
+ );
1109
+ }
1110
+ }
1111
+ return this.sanitize(current);
1112
+ }
1113
+ /**
1114
+ * Compile le code utilisateur en une fonction bornée en temps.
1115
+ *
1116
+ * Le `timeout` de `runInNewContext` ne couvre que l'évaluation de la factory :
1117
+ * la closure retournée s'exécutait ensuite ligne par ligne directement sur
1118
+ * l'event loop, sans aucune borne. Une regex à backtracking exponentiel
1119
+ * fournie par l'utilisateur figeait donc l'agent entier — logs, statuts et
1120
+ * métriques de *tous* les services. Chaque invocation repasse maintenant par
1121
+ * la vm, avec son propre budget.
1122
+ */
1123
+ compileParser(def) {
1124
+ const forbidden = ["require(", "import ", "eval("];
1125
+ for (const pat of forbidden) {
1126
+ if (def.code.includes(pat)) {
1127
+ throw new Error("Code contains forbidden patterns (require, import, eval)");
1128
+ }
1129
+ }
1130
+ const sandbox = {
1131
+ RegExp,
1132
+ String,
1133
+ Object,
1134
+ Array,
1135
+ JSON,
1136
+ Math,
1137
+ Date,
1138
+ undefined: void 0,
1139
+ null: null
1140
+ };
1141
+ let script;
1142
+ try {
1143
+ script = new vm.Script(`(${def.code})`, { filename: `parser-${def.id}.js` });
1144
+ } catch (err) {
1145
+ throw new Error(`Compilation failed: ${err instanceof Error ? err.message : String(err)}`);
1146
+ }
1147
+ const context = vm.createContext({ ...sandbox, __line: null, __result: null });
1148
+ let parserFn;
1149
+ try {
1150
+ parserFn = script.runInContext(context, { timeout: 100 });
1151
+ } catch (err) {
1152
+ throw new Error(`Execution failed: ${err instanceof Error ? err.message : String(err)}`);
1153
+ }
1154
+ if (typeof parserFn !== "function") {
1155
+ throw new Error("Parser code must export a function");
1156
+ }
1157
+ context["__parserFn"] = parserFn;
1158
+ const callScript = new vm.Script("__result = __parserFn(__line);", {
1159
+ filename: `parser-${def.id}-call.js`
1160
+ });
1161
+ let consecutiveTimeouts = 0;
1162
+ let disabled = false;
1163
+ return (line) => {
1164
+ if (disabled) return line;
1165
+ const ctx = context;
1166
+ ctx["__line"] = line;
1167
+ ctx["__result"] = null;
1168
+ try {
1169
+ callScript.runInContext(context, { timeout: PARSE_TIMEOUT_MS });
1170
+ consecutiveTimeouts = 0;
1171
+ } catch (err) {
1172
+ const e = err;
1173
+ const timedOut = !!e && (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || typeof e.message === "string" && /execution timed out/i.test(e.message));
1174
+ if (!timedOut) throw err;
1175
+ consecutiveTimeouts += 1;
1176
+ if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {
1177
+ disabled = true;
1178
+ console.warn(
1179
+ `[js-log-parser] Parser "${def.name}" (${def.id}) disabled after ${MAX_CONSECUTIVE_TIMEOUTS} consecutive timeouts`
1180
+ );
1181
+ }
1182
+ return line;
1183
+ }
1184
+ const result = ctx["__result"];
1185
+ if (result === null || result === void 0 || typeof result !== "object") {
1186
+ return line;
1187
+ }
1188
+ return result;
1189
+ };
1190
+ }
1191
+ /** Sanitize the final LogLine: truncate message, limit metadata, validate level */
1192
+ sanitize(line) {
1193
+ let { message, metadata, level } = line;
1194
+ if (message.length > 16384) {
1195
+ message = message.substring(0, 16384) + "...[truncated]";
1196
+ }
1197
+ metadata = metadata ?? {};
1198
+ const metaKeys = Object.keys(metadata);
1199
+ if (metaKeys.length > 100) {
1200
+ const limited = {};
1201
+ for (let i = 0; i < 100; i++) {
1202
+ limited[metaKeys[i]] = metadata[metaKeys[i]];
1203
+ }
1204
+ metadata = limited;
1205
+ }
1206
+ if (!VALID_LEVELS.has(level)) {
1207
+ level = "info";
1208
+ }
1209
+ if (message !== line.message || metadata !== line.metadata || level !== line.level) {
1210
+ return { ...line, message, metadata, level };
1211
+ }
1212
+ return line;
1213
+ }
1214
+ };
1215
+
1216
+ // ../../packages/shared/src/builtins.ts
1217
+ var BUILTIN_VARIABLES = [
1218
+ // ── Le service ───────────────────────────────────────────────────────────
1219
+ { name: "service.NAME", scope: "server", descriptionKey: "serviceName" },
1220
+ { name: "service.ID", scope: "server", descriptionKey: "serviceId" },
1221
+ { name: "service.PORT", scope: "server", descriptionKey: "servicePort" },
1222
+ { name: "service.URL", scope: "server", descriptionKey: "serviceUrl" },
1223
+ { name: "service.BASE_URL", scope: "server", descriptionKey: "serviceBaseUrl" },
1224
+ { name: "service.CWD", scope: "agent", descriptionKey: "serviceCwd" },
1225
+ // ── Le projet et l'environnement actif ───────────────────────────────────
1226
+ { name: "project.NAME", scope: "server", descriptionKey: "projectName" },
1227
+ { name: "runeya.ENV_NAME", scope: "server", descriptionKey: "envName" },
1228
+ // ── Le serveur Runeya ────────────────────────────────────────────────────
1229
+ // `service.HOST` a toujours désigné l'adresse d'écoute du SERVEUR, pas une
1230
+ // propriété du service : le nom trompait, il devient un alias.
1231
+ { name: "runeya.HOST", scope: "server", descriptionKey: "runeyaHost", deprecatedAlias: "service.HOST" },
1232
+ // ── La machine qui exécute ───────────────────────────────────────────────
1233
+ { name: "agent.HOST_LAN", scope: "agent", descriptionKey: "agentHostLan", deprecatedAlias: "service.HOST_LAN" },
1234
+ // Le NOM de l'agent est une étiquette de la configuration du serveur, pas
1235
+ // une propriété de la machine : c'est le serveur qui le connaît et le résout.
1236
+ { name: "agent.NAME", scope: "server", descriptionKey: "agentName" },
1237
+ { name: "agent.OS", scope: "agent", descriptionKey: "agentOs" },
1238
+ { name: "agent.HOME", scope: "agent", descriptionKey: "agentHome" }
1239
+ ];
1240
+ var BUILTIN_REFERENCE_RE = /\{\{([A-Za-z][A-Za-z0-9_.-]*)\}\}/g;
1241
+ var ENVIRONMENT_NAMESPACE = "environment.";
1242
+ function interpolateBuiltins(text, values) {
1243
+ return text.replace(BUILTIN_REFERENCE_RE, (match, name) => {
1244
+ if (name.startsWith(ENVIRONMENT_NAMESPACE)) return match;
1245
+ return values[name] ?? match;
1246
+ });
1247
+ }
1248
+ function interpolateBuiltinsInEnv(env2, values) {
1249
+ const out = {};
1250
+ for (const [key, value] of Object.entries(env2)) {
1251
+ out[key] = interpolateBuiltins(value, values);
1252
+ }
1253
+ return out;
1254
+ }
1255
+ function withDeprecatedAliases(values) {
1256
+ const out = { ...values };
1257
+ for (const builtin of BUILTIN_VARIABLES) {
1258
+ if (builtin.deprecatedAlias && out[builtin.name] !== void 0) {
1259
+ out[builtin.deprecatedAlias] = out[builtin.name];
1260
+ }
1261
+ }
1262
+ return out;
1263
+ }
1771
1264
 
1772
- // ../../packages/shared/src/utils/crypto.ts
1773
- import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from "crypto";
1265
+ // ../../packages/shared/src/constants/intervals.ts
1266
+ var HEALTH_CHECK_INTERVAL = 3e4;
1267
+ var METRICS_INTERVAL = 5e3;
1268
+ var HEALTH_CHECK_INITIAL_DELAY = 5e3;
1269
+ var HEALTH_WS_INTERVAL = 1e4;
1270
+
1271
+ // ../../packages/shared/src/constants/buffers.ts
1272
+ var LOG_BUFFER_SIZE = 5e3;
1273
+
1274
+ // ../../packages/shared/src/constants/timeouts.ts
1275
+ var GRACE_PERIOD = 1e4;
1276
+ var AGENT_STOP_FETCH_TIMEOUT = GRACE_PERIOD + 15e3;
1277
+
1278
+ // ../../packages/shared/src/constants/editors.ts
1279
+ var SUPPORTED_EDITORS = [
1280
+ { key: "vscode", name: "Visual Studio Code", command: "code" },
1281
+ { key: "cursor", name: "Cursor", command: "cursor" },
1282
+ { key: "windsurf", name: "Windsurf", command: "windsurf" },
1283
+ { key: "sublime", name: "Sublime Text", command: "subl" },
1284
+ { key: "atom", name: "Atom", command: "atom" },
1285
+ { key: "antigravity", name: "Antigravity", command: "antigravity" },
1286
+ { key: "intellij", name: "IntelliJ IDEA", command: "idea" },
1287
+ { key: "android-studio", name: "Android Studio", command: "studio" },
1288
+ { key: "webstorm", name: "WebStorm", command: "webstorm" },
1289
+ { key: "zed", name: "Zed", command: "zed" },
1290
+ { key: "neovim", name: "Neovim", command: "nvim" },
1291
+ { key: "vim", name: "Vim", command: "vim" },
1292
+ { key: "emacs", name: "Emacs", command: "emacs" },
1293
+ { key: "fleet", name: "Fleet", command: "fleet" }
1294
+ ];
1295
+ var EDITOR_BY_KEY = new Map(
1296
+ SUPPORTED_EDITORS.map((e) => [e.key, e])
1297
+ );
1298
+
1299
+ // ../../packages/shared/src/sync/json-crdt.ts
1300
+ import * as Y from "yjs";
1301
+
1302
+ // ../../packages/runner-native/src/native-runner.ts
1303
+ import { execa } from "execa";
1304
+ import { execSync } from "child_process";
1305
+ import { homedir } from "os";
1306
+
1307
+ // ../../node_modules/shellwords/dist/esm/index.js
1308
+ var scan = (string, pattern, callback) => {
1309
+ let result = "";
1310
+ while (string.length > 0) {
1311
+ const match = string.match(pattern);
1312
+ if (match && match.index != null && match[0] != null) {
1313
+ result += string.slice(0, match.index);
1314
+ result += callback(match);
1315
+ string = string.slice(match.index + match[0].length);
1316
+ } else {
1317
+ result += string;
1318
+ string = "";
1319
+ }
1320
+ }
1321
+ return result;
1322
+ };
1323
+ var split = (line = "") => {
1324
+ const words = [];
1325
+ let field = "";
1326
+ scan(
1327
+ line,
1328
+ /\s*(?:([^\s\\'"]+)|'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)"|(\\.?)|(\S))(\s|$)?/,
1329
+ (match) => {
1330
+ const [_raw, word, sq, dq, escape2, garbage, separator] = match;
1331
+ if (garbage != null) {
1332
+ throw new Error(`Unmatched quote: ${line}`);
1333
+ }
1334
+ if (word) {
1335
+ field += word;
1336
+ } else {
1337
+ let addition;
1338
+ if (sq) {
1339
+ addition = sq;
1340
+ } else if (dq) {
1341
+ addition = dq;
1342
+ } else if (escape2) {
1343
+ addition = escape2;
1344
+ }
1345
+ if (addition) {
1346
+ field += addition.replace(/\\(?=.)/, "");
1347
+ }
1348
+ }
1349
+ if (separator != null) {
1350
+ words.push(field);
1351
+ field = "";
1352
+ }
1353
+ }
1354
+ );
1355
+ if (field) {
1356
+ words.push(field);
1357
+ }
1358
+ return words;
1359
+ };
1360
+
1361
+ // ../../packages/runner-native/src/native-runner.ts
1362
+ var shellwordsSplit = split;
1363
+ function expandEnvVars(str, serviceEnv) {
1364
+ const withHome = str.replace(/^~(\/|$)/, `${homedir()}$1`);
1365
+ return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
1366
+ const name = braced ?? plain;
1367
+ return serviceEnv?.[name] ?? "";
1368
+ });
1369
+ }
1370
+ function resolveCwd(cwd, env2) {
1371
+ if (!cwd) return ".";
1372
+ return expandEnvVars(cwd, env2) || ".";
1373
+ }
1374
+ function findUnresolvedEnvVars(str, serviceEnv) {
1375
+ const unresolved = [];
1376
+ str.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
1377
+ const name = braced ?? plain;
1378
+ if (serviceEnv?.[name] === void 0) {
1379
+ unresolved.push(name);
1380
+ }
1381
+ return "";
1382
+ });
1383
+ return unresolved;
1384
+ }
1385
+ var SYSTEM_PATH_DIRS = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"];
1386
+ function buildSafeEnv(configEnv = {}) {
1387
+ const safeKeys = ["PATH", "HOME", "USER", "SHELL", "LANG", "TERM", "NODE_ENV", "TMPDIR", "TZ", "DBUS_SESSION_BUS_ADDRESS", "XDG_RUNTIME_DIR"];
1388
+ const env2 = {};
1389
+ for (const key of safeKeys) {
1390
+ if (process.env[key]) {
1391
+ env2[key] = process.env[key];
1392
+ }
1393
+ }
1394
+ const existingPath = env2["PATH"] ?? "";
1395
+ const existingDirs = new Set(existingPath.split(":").filter(Boolean));
1396
+ const missingDirs = SYSTEM_PATH_DIRS.filter((d) => !existingDirs.has(d));
1397
+ if (missingDirs.length > 0) {
1398
+ env2["PATH"] = [existingPath, ...missingDirs].filter(Boolean).join(":");
1399
+ }
1400
+ return { ...env2, ...configEnv };
1401
+ }
1402
+ var NativeRunner = class {
1403
+ type = "native";
1404
+ start(config) {
1405
+ let subprocess;
1406
+ const cwd = resolveCwd(config.cwd, config.env);
1407
+ const isWindows = process.platform === "win32";
1408
+ if (config.shell) {
1409
+ subprocess = execa(config.command, {
1410
+ cwd,
1411
+ env: buildSafeEnv(config.env),
1412
+ shell: true,
1413
+ detached: !isWindows,
1414
+ // Create new process group for group kill (not supported on Windows)
1415
+ windowsHide: true,
1416
+ // Prevent terminal windows from appearing on Windows
1417
+ stdio: ["ignore", "pipe", "pipe"],
1418
+ reject: false,
1419
+ // Don't throw on non-zero exit
1420
+ buffer: false
1421
+ // Don't accumulate stdout/stderr in memory — we stream via readline
1422
+ });
1423
+ } else {
1424
+ const args = shellwordsSplit(config.command);
1425
+ const cmd = args.shift();
1426
+ if (!cmd) {
1427
+ throw new Error("Invalid command: cannot parse empty or whitespace-only command");
1428
+ }
1429
+ subprocess = execa(cmd, args, {
1430
+ cwd,
1431
+ env: buildSafeEnv(config.env),
1432
+ shell: false,
1433
+ // SECURITY: shell:false prevents command injection
1434
+ detached: !isWindows,
1435
+ // Create new process group for group kill (not supported on Windows)
1436
+ windowsHide: true,
1437
+ // Prevent terminal windows from appearing on Windows
1438
+ stdio: ["ignore", "pipe", "pipe"],
1439
+ reject: false,
1440
+ // Don't throw on non-zero exit
1441
+ buffer: false
1442
+ // Don't accumulate stdout/stderr in memory — we stream via readline
1443
+ });
1444
+ }
1445
+ const exitPromise = new Promise((resolve2) => {
1446
+ subprocess.then((result) => {
1447
+ resolve2({
1448
+ exitCode: result.exitCode ?? null,
1449
+ signal: result.signal ?? null,
1450
+ error: result.failed && result.shortMessage ? result.shortMessage : void 0
1451
+ });
1452
+ }).catch((err) => {
1453
+ resolve2({ exitCode: 1, signal: null, error: err.message ?? "Unknown error" });
1454
+ });
1455
+ });
1456
+ return {
1457
+ pid: subprocess.pid,
1458
+ kill(signal = "SIGTERM") {
1459
+ try {
1460
+ if (process.platform === "win32") {
1461
+ if (!subprocess.pid) return false;
1462
+ execSync(`taskkill /F /T /PID ${subprocess.pid}`, { stdio: "ignore" });
1463
+ return true;
1464
+ }
1465
+ if (subprocess.pid) {
1466
+ process.kill(-subprocess.pid, signal);
1467
+ return true;
1468
+ }
1469
+ return subprocess.kill(signal);
1470
+ } catch {
1471
+ return false;
1472
+ }
1473
+ },
1474
+ stdout: subprocess.stdout,
1475
+ stderr: subprocess.stderr,
1476
+ exitPromise
1477
+ };
1478
+ }
1479
+ async isAvailable() {
1480
+ return true;
1481
+ }
1482
+ };
1774
1483
 
1775
- // ../../packages/shared/src/js-log-parser.ts
1776
- import vm from "vm";
1777
- var VALID_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error", "fatal"]);
1778
- var PARSE_TIMEOUT_MS = 50;
1779
- var MAX_CONSECUTIVE_TIMEOUTS = 10;
1780
- var JSLogParser = class {
1781
- parsers = [];
1782
- constructor(definitions = []) {
1783
- this.setParsers(definitions);
1484
+ // ../../packages/runner-docker/src/index.ts
1485
+ import { execa as execa2 } from "execa";
1486
+ import { PassThrough } from "stream";
1487
+ import { randomUUID } from "crypto";
1488
+ import { writeFile, unlink, mkdir } from "fs/promises";
1489
+ import { tmpdir, homedir as homedir2, userInfo } from "os";
1490
+ import { join } from "path";
1491
+ function splitShellArgs(cmd) {
1492
+ const args = [];
1493
+ let current = "";
1494
+ let inSingle = false;
1495
+ let inDouble = false;
1496
+ for (let i = 0; i < cmd.length; i++) {
1497
+ const ch = cmd[i];
1498
+ if (ch === "'" && !inDouble) {
1499
+ inSingle = !inSingle;
1500
+ } else if (ch === '"' && !inSingle) {
1501
+ inDouble = !inDouble;
1502
+ } else if (ch === "\\" && inDouble && i + 1 < cmd.length) {
1503
+ current += cmd[++i];
1504
+ } else if (/\s/.test(ch) && !inSingle && !inDouble) {
1505
+ if (current) {
1506
+ args.push(current);
1507
+ current = "";
1508
+ }
1509
+ } else {
1510
+ current += ch;
1511
+ }
1784
1512
  }
1785
- setParsers(definitions) {
1786
- this.parsers = [];
1787
- for (const def of definitions) {
1788
- if (!def.enabled) continue;
1789
- try {
1790
- const compiled = this.compileParser(def);
1791
- this.parsers.push({
1792
- id: def.id,
1793
- name: def.name,
1794
- enabled: true,
1795
- fn: compiled
1513
+ if (current) args.push(current);
1514
+ return args;
1515
+ }
1516
+ function sanitizeDockerName(name) {
1517
+ return name.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/-{2,}/g, "-");
1518
+ }
1519
+ function expandEnvVars2(str, serviceEnv) {
1520
+ const withHome = str.replace(/^~(\/|$)/, `${homedir2()}$1`);
1521
+ return withHome.replace(/\$\{(\w+)\}|\$(\w+)/g, (_, braced, plain) => {
1522
+ const name = braced ?? plain;
1523
+ return serviceEnv?.[name] ?? "";
1524
+ });
1525
+ }
1526
+ async function preMkdirVolumes(volumes, serviceEnv) {
1527
+ for (const v of volumes) {
1528
+ const expanded = expandEnvVars2(v, serviceEnv);
1529
+ const parts = expanded.split(":");
1530
+ if (parts.length < 2) continue;
1531
+ const hostPath = parts[0];
1532
+ if (!hostPath.startsWith("/") && !hostPath.startsWith(".")) continue;
1533
+ await mkdir(hostPath, { recursive: true }).catch(() => {
1534
+ });
1535
+ }
1536
+ }
1537
+ var DockerRunner = class {
1538
+ type = "docker";
1539
+ start(config) {
1540
+ const stdout = new PassThrough();
1541
+ const stderr = new PassThrough();
1542
+ const containerName = sanitizeDockerName(config.cmdId ? `runeya-${config.serviceId}-${config.cmdId}` : `runeya-${config.serviceId}`);
1543
+ let killed = false;
1544
+ const exitPromise = new Promise(
1545
+ (resolve2) => {
1546
+ void (async () => {
1547
+ try {
1548
+ await execa2("docker", ["rm", "-f", containerName], { reject: false });
1549
+ const dc = config.dockerConfig;
1550
+ let lastCardId = null;
1551
+ const envFlags = Object.entries(config.env ?? {}).flatMap(
1552
+ ([k, v]) => ["-e", `${k}=${v}`]
1553
+ );
1554
+ await preMkdirVolumes(dc.volumes ?? [], config.env);
1555
+ const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
1556
+ if (dc.mountRootpath && config.cwd) {
1557
+ volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
1558
+ }
1559
+ if (dc.image && !dc.dockerfile) {
1560
+ lastCardId = randomUUID();
1561
+ stdout.write(
1562
+ "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n"
1563
+ );
1564
+ const pull = execa2("docker", ["pull", dc.image], { reject: false });
1565
+ pull.stdout?.pipe(stdout, { end: false });
1566
+ pull.stderr?.pipe(stderr, { end: false });
1567
+ await pull;
1568
+ }
1569
+ let imageName = dc.image ?? containerName + ":latest";
1570
+ if (dc.dockerfile) {
1571
+ lastCardId = randomUUID();
1572
+ stdout.write(
1573
+ "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n"
1574
+ );
1575
+ const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
1576
+ try {
1577
+ await writeFile(tmpFile, dc.dockerfile, "utf8");
1578
+ const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(
1579
+ ([k, v]) => ["--build-arg", `${k}=${v}`]
1580
+ );
1581
+ const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
1582
+ const buildContext = dc.buildContext ?? config.cwd ?? ".";
1583
+ imageName = `${containerName}:latest`;
1584
+ const build = execa2(
1585
+ "docker",
1586
+ ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext],
1587
+ { reject: false }
1588
+ );
1589
+ build.stdout?.pipe(stdout, { end: false });
1590
+ build.stderr?.pipe(stderr, { end: false });
1591
+ await build;
1592
+ } finally {
1593
+ await unlink(tmpFile).catch(() => {
1594
+ });
1595
+ }
1596
+ }
1597
+ if (killed) {
1598
+ resolve2({ exitCode: null, signal: "SIGTERM" });
1599
+ return;
1600
+ }
1601
+ if (lastCardId) {
1602
+ stdout.write(
1603
+ "\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n"
1604
+ );
1605
+ }
1606
+ const bootstrapCmds = config.skipBootstrap ? [] : (dc.bootstrapCommands ?? []).filter((c) => c.command.trim());
1607
+ for (const bsCmd of bootstrapCmds) {
1608
+ if (killed) {
1609
+ resolve2({ exitCode: null, signal: "SIGTERM" });
1610
+ return;
1611
+ }
1612
+ const bsCardId = randomUUID();
1613
+ const bsCmdName = bsCmd.label || bsCmd.command;
1614
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "bootstrap", _cardId: bsCardId, _cardState: "open", message: `Bootstrap: ${bsCmdName}` })}
1615
+ `);
1616
+ const exitCode = await this.runBootstrap(bsCmd, imageName, config.env ?? {}, dc.volumes ?? [], stdout, stderr);
1617
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: bsCardId, _cardState: "close" })}
1618
+ `);
1619
+ if (exitCode !== 0) {
1620
+ stderr.write(`Bootstrap command "${bsCmdName}" failed with exit code ${exitCode}
1621
+ `);
1622
+ resolve2({ exitCode, signal: null, error: `Bootstrap "${bsCmdName}" failed (exit ${exitCode})` });
1623
+ return;
1624
+ }
1625
+ }
1626
+ if (killed) {
1627
+ resolve2({ exitCode: null, signal: "SIGTERM" });
1628
+ return;
1629
+ }
1630
+ const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
1631
+ let cmdArgs;
1632
+ let entrypointFlags;
1633
+ if (dc.useNativeCommand) {
1634
+ const shell = dc.nativeShell || "sh";
1635
+ entrypointFlags = [];
1636
+ cmdArgs = config.command ? [shell, "-c", config.command] : [];
1637
+ } else {
1638
+ entrypointFlags = dc.entrypoint ? ["--entrypoint", dc.entrypoint] : [];
1639
+ cmdArgs = dc.command ? splitShellArgs(dc.command) : [];
1640
+ }
1641
+ const { uid, gid } = userInfo();
1642
+ const rmFlag = config.rm ? ["--rm"] : [];
1643
+ const runArgs = [
1644
+ "run",
1645
+ ...rmFlag,
1646
+ "--init",
1647
+ "--name",
1648
+ containerName,
1649
+ "--user",
1650
+ dc.user || `${uid}:${gid}`,
1651
+ ...networkFlags,
1652
+ ...envFlags,
1653
+ ...volumeFlags,
1654
+ ...entrypointFlags,
1655
+ imageName,
1656
+ ...cmdArgs
1657
+ ];
1658
+ const debugCardId = randomUUID();
1659
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run" })}
1660
+ `);
1661
+ stdout.write(`docker ${runArgs.join(" ")}
1662
+ `);
1663
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
1664
+ `);
1665
+ const runProc = execa2("docker", runArgs, { reject: false });
1666
+ runProc.stdout?.pipe(stdout, { end: false });
1667
+ runProc.stderr?.pipe(stderr, { end: false });
1668
+ const result = await runProc;
1669
+ resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
1670
+ } catch (err) {
1671
+ const msg = err instanceof Error ? err.message : String(err);
1672
+ stderr.write(`Docker infrastructure error: ${msg}
1673
+ `);
1674
+ resolve2({ exitCode: 1, signal: null });
1675
+ } finally {
1676
+ stdout.end();
1677
+ stderr.end();
1678
+ }
1679
+ })();
1680
+ }
1681
+ );
1682
+ return {
1683
+ pid: void 0,
1684
+ containerName,
1685
+ stdout,
1686
+ stderr,
1687
+ exitPromise,
1688
+ kill(_signal = "SIGTERM") {
1689
+ killed = true;
1690
+ execa2("docker", ["stop", containerName]).catch(() => {
1796
1691
  });
1797
- } catch (err) {
1798
- console.warn(
1799
- `[js-log-parser] Failed to compile parser "${def.name}" (${def.id}): ${err instanceof Error ? err.message : String(err)}`
1800
- );
1692
+ return true;
1801
1693
  }
1802
- }
1694
+ };
1803
1695
  }
1804
- parse(line) {
1805
- let current = line;
1806
- for (const parser of this.parsers) {
1696
+ /** Start a long-lived container (sleep infinity) for shared mode.
1697
+ * Returns the RunnerProcess (lifetime) plus a `containerReady` promise that resolves
1698
+ * once `docker run --detach` has completed and the container is confirmed running.
1699
+ * Callers must await `containerReady` before calling `execInContainer`. */
1700
+ startSharedContainer(config) {
1701
+ const stdout = new PassThrough();
1702
+ const stderr = new PassThrough();
1703
+ const containerName = sanitizeDockerName(`runeya-${config.serviceId}`);
1704
+ let killed = false;
1705
+ let resolveReady;
1706
+ let rejectReady;
1707
+ const containerReady = new Promise((res, rej) => {
1708
+ resolveReady = res;
1709
+ rejectReady = rej;
1710
+ });
1711
+ let exitResolve;
1712
+ const exitPromise = new Promise(
1713
+ (resolve2) => {
1714
+ exitResolve = resolve2;
1715
+ }
1716
+ );
1717
+ void (async () => {
1807
1718
  try {
1808
- current = parser.fn(current);
1719
+ await execa2("docker", ["rm", "-f", containerName], { reject: false });
1720
+ const dc = config.dockerConfig;
1721
+ let lastCardId = null;
1722
+ const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
1723
+ await preMkdirVolumes(dc.volumes ?? [], config.env);
1724
+ const volumeFlags = (dc.volumes ?? []).flatMap((v) => ["-v", expandEnvVars2(v, config.env)]);
1725
+ if (dc.mountRootpath && config.cwd) {
1726
+ volumeFlags.push("-v", `${config.cwd}:${config.cwd}`);
1727
+ }
1728
+ if (dc.image && !dc.dockerfile) {
1729
+ lastCardId = randomUUID();
1730
+ stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "pull", _cardId: lastCardId, _cardState: "open", message: `--- Docker Pull: ${dc.image} ---` }) + "\n");
1731
+ const pull = execa2("docker", ["pull", dc.image], { reject: false });
1732
+ pull.stdout?.pipe(stdout, { end: false });
1733
+ pull.stderr?.pipe(stderr, { end: false });
1734
+ await pull;
1735
+ }
1736
+ let imageName = dc.image ?? containerName + ":latest";
1737
+ if (dc.dockerfile) {
1738
+ lastCardId = randomUUID();
1739
+ stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "build", _cardId: lastCardId, _cardState: "open", message: "--- Docker Build ---" }) + "\n");
1740
+ const tmpFile = join(tmpdir(), `runeya-${config.serviceId}-${randomUUID()}.dockerfile`);
1741
+ try {
1742
+ await writeFile(tmpFile, dc.dockerfile, "utf8");
1743
+ const buildArgs = Object.entries(dc.buildArgs ?? {}).flatMap(([k, v]) => ["--build-arg", `${k}=${v}`]);
1744
+ const targetArgs = dc.targetStage ? ["--target", dc.targetStage] : [];
1745
+ const buildContext = dc.buildContext ?? config.cwd ?? ".";
1746
+ imageName = `${containerName}:latest`;
1747
+ const build = execa2("docker", ["build", "-f", tmpFile, "-t", imageName, ...buildArgs, ...targetArgs, buildContext], { reject: false });
1748
+ build.stdout?.pipe(stdout, { end: false });
1749
+ build.stderr?.pipe(stderr, { end: false });
1750
+ await build;
1751
+ } finally {
1752
+ await unlink(tmpFile).catch(() => {
1753
+ });
1754
+ }
1755
+ }
1756
+ if (killed) {
1757
+ rejectReady(new Error("Killed before container started"));
1758
+ exitResolve({ exitCode: null, signal: "SIGTERM" });
1759
+ return;
1760
+ }
1761
+ if (lastCardId) {
1762
+ stdout.write("\0DOCKER_PHASE:" + JSON.stringify({ _dockerPhase: "close", _cardId: lastCardId, _cardState: "close" }) + "\n");
1763
+ }
1764
+ const networkFlags = dc.networkMode === "host" ? ["--network", "host"] : (dc.ports ?? []).flatMap((p) => ["-p", p]);
1765
+ const { uid, gid } = userInfo();
1766
+ const runArgs = [
1767
+ "run",
1768
+ "--detach",
1769
+ "--init",
1770
+ "--name",
1771
+ containerName,
1772
+ "--user",
1773
+ dc.user || `${uid}:${gid}`,
1774
+ ...networkFlags,
1775
+ ...envFlags,
1776
+ ...volumeFlags,
1777
+ imageName,
1778
+ "sleep",
1779
+ "infinity"
1780
+ ];
1781
+ const debugCardId = randomUUID();
1782
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "run", _cardId: debugCardId, _cardState: "open", message: "Docker Run (shared container)" })}
1783
+ `);
1784
+ stdout.write(`docker ${runArgs.join(" ")}
1785
+ `);
1786
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: debugCardId, _cardState: "close" })}
1787
+ `);
1788
+ const runProc = execa2("docker", runArgs, { reject: false });
1789
+ runProc.stdout?.pipe(stdout, { end: false });
1790
+ runProc.stderr?.pipe(stderr, { end: false });
1791
+ const runResult = await runProc;
1792
+ if (runResult.exitCode !== 0) {
1793
+ rejectReady(new Error(`docker run exited with code ${runResult.exitCode}`));
1794
+ exitResolve({ exitCode: runResult.exitCode ?? 1, signal: null });
1795
+ return;
1796
+ }
1797
+ resolveReady();
1798
+ const waitProc = execa2("docker", ["wait", containerName], { reject: false });
1799
+ await waitProc;
1800
+ exitResolve({ exitCode: 0, signal: null });
1809
1801
  } catch (err) {
1810
- console.warn(
1811
- `[js-log-parser] Parser "${parser.name}" threw error: ${err instanceof Error ? err.message : String(err)}`
1812
- );
1802
+ const msg = err instanceof Error ? err.message : String(err);
1803
+ stderr.write(`Docker infrastructure error: ${msg}
1804
+ `);
1805
+ rejectReady(new Error(msg));
1806
+ exitResolve({ exitCode: 1, signal: null });
1807
+ } finally {
1808
+ stdout.end();
1809
+ stderr.end();
1813
1810
  }
1814
- }
1815
- return this.sanitize(current);
1811
+ })();
1812
+ return {
1813
+ pid: void 0,
1814
+ containerName,
1815
+ stdout,
1816
+ stderr,
1817
+ exitPromise,
1818
+ containerReady,
1819
+ kill(_signal = "SIGTERM") {
1820
+ killed = true;
1821
+ execa2("docker", ["kill", containerName]).then(() => exitResolve({ exitCode: null, signal: "SIGKILL" })).catch(() => exitResolve({ exitCode: 1, signal: null }));
1822
+ return true;
1823
+ }
1824
+ };
1816
1825
  }
1817
- /**
1818
- * Compile le code utilisateur en une fonction bornée en temps.
1819
- *
1820
- * Le `timeout` de `runInNewContext` ne couvre que l'évaluation de la factory :
1821
- * la closure retournée s'exécutait ensuite ligne par ligne directement sur
1822
- * l'event loop, sans aucune borne. Une regex à backtracking exponentiel
1823
- * fournie par l'utilisateur figeait donc l'agent entier — logs, statuts et
1824
- * métriques de *tous* les services. Chaque invocation repasse maintenant par
1825
- * la vm, avec son propre budget.
1826
- */
1827
- compileParser(def) {
1828
- const forbidden = ["require(", "import ", "eval("];
1829
- for (const pat of forbidden) {
1830
- if (def.code.includes(pat)) {
1831
- throw new Error("Code contains forbidden patterns (require, import, eval)");
1826
+ /** Run a command inside a running shared container via `docker exec`.
1827
+ * Kill terminates the docker-exec process but does NOT stop the container. */
1828
+ execInContainer(containerName, command, envVars = {}, shell = "sh") {
1829
+ const stdout = new PassThrough();
1830
+ const stderr = new PassThrough();
1831
+ let dockerProc = null;
1832
+ const exitPromise = new Promise(
1833
+ (resolve2) => {
1834
+ void (async () => {
1835
+ try {
1836
+ const envFlags = Object.entries(envVars).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
1837
+ const shellCmd = command.length ? command : "true";
1838
+ dockerProc = execa2(
1839
+ "docker",
1840
+ ["exec", ...envFlags, containerName, shell, "-c", shellCmd],
1841
+ { reject: false }
1842
+ );
1843
+ dockerProc.stdout?.pipe(stdout, { end: false });
1844
+ dockerProc.stderr?.pipe(stderr, { end: false });
1845
+ const result = await dockerProc;
1846
+ resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
1847
+ } catch (err) {
1848
+ const msg = err instanceof Error ? err.message : String(err);
1849
+ stderr.write(`docker execInContainer error: ${msg}
1850
+ `);
1851
+ resolve2({ exitCode: 1, signal: null });
1852
+ } finally {
1853
+ stdout.end();
1854
+ stderr.end();
1855
+ }
1856
+ })();
1857
+ }
1858
+ );
1859
+ return {
1860
+ pid: void 0,
1861
+ containerName,
1862
+ stdout,
1863
+ stderr,
1864
+ exitPromise,
1865
+ kill(_signal = "SIGTERM") {
1866
+ dockerProc?.kill("SIGTERM");
1867
+ return true;
1832
1868
  }
1833
- }
1834
- const sandbox = {
1835
- RegExp,
1836
- String,
1837
- Object,
1838
- Array,
1839
- JSON,
1840
- Math,
1841
- Date,
1842
- undefined: void 0,
1843
- null: null
1844
1869
  };
1845
- let script;
1846
- try {
1847
- script = new vm.Script(`(${def.code})`, { filename: `parser-${def.id}.js` });
1848
- } catch (err) {
1849
- throw new Error(`Compilation failed: ${err instanceof Error ? err.message : String(err)}`);
1850
- }
1851
- const context = vm.createContext({ ...sandbox, __line: null, __result: null });
1852
- let parserFn;
1853
- try {
1854
- parserFn = script.runInContext(context, { timeout: 100 });
1855
- } catch (err) {
1856
- throw new Error(`Execution failed: ${err instanceof Error ? err.message : String(err)}`);
1857
- }
1858
- if (typeof parserFn !== "function") {
1859
- throw new Error("Parser code must export a function");
1860
- }
1861
- context["__parserFn"] = parserFn;
1862
- const callScript = new vm.Script("__result = __parserFn(__line);", {
1863
- filename: `parser-${def.id}-call.js`
1864
- });
1865
- let consecutiveTimeouts = 0;
1866
- let disabled = false;
1867
- return (line) => {
1868
- if (disabled) return line;
1869
- const ctx = context;
1870
- ctx["__line"] = line;
1871
- ctx["__result"] = null;
1872
- try {
1873
- callScript.runInContext(context, { timeout: PARSE_TIMEOUT_MS });
1874
- consecutiveTimeouts = 0;
1875
- } catch (err) {
1876
- const e = err;
1877
- const timedOut = !!e && (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || typeof e.message === "string" && /execution timed out/i.test(e.message));
1878
- if (!timedOut) throw err;
1879
- consecutiveTimeouts += 1;
1880
- if (consecutiveTimeouts >= MAX_CONSECUTIVE_TIMEOUTS) {
1881
- disabled = true;
1882
- console.warn(
1883
- `[js-log-parser] Parser "${def.name}" (${def.id}) disabled after ${MAX_CONSECUTIVE_TIMEOUTS} consecutive timeouts`
1884
- );
1885
- }
1886
- return line;
1870
+ }
1871
+ /** Run a shortcut command in the context of a Docker service.
1872
+ * If a service container is running (shared or isolated), uses `docker exec`.
1873
+ * If not running, reuses `start()` with `--rm` and `skipBootstrap`. */
1874
+ runShortcut(config, shortcutCommand) {
1875
+ const stdout = new PassThrough();
1876
+ const stderr = new PassThrough();
1877
+ let innerProcess = null;
1878
+ let dockerProc = null;
1879
+ const exitPromise = new Promise(
1880
+ (resolve2) => {
1881
+ void (async () => {
1882
+ try {
1883
+ const psResult = await execa2(
1884
+ "docker",
1885
+ ["ps", "--filter", `name=runeya-${config.serviceId}`, "--format", "{{.Names}}"],
1886
+ { reject: false }
1887
+ );
1888
+ const runningContainer = psResult.stdout.trim().split("\n").find((n) => n.startsWith(`runeya-${config.serviceId}`));
1889
+ if (runningContainer) {
1890
+ const shell = config.dockerConfig.nativeShell || "sh";
1891
+ const envFlags = Object.entries(config.env ?? {}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
1892
+ const args = ["exec", ...envFlags, runningContainer, shell, "-c", shortcutCommand || "true"];
1893
+ const cardId = randomUUID();
1894
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "exec", _cardId: cardId, _cardState: "open", message: "Docker Exec" })}
1895
+ `);
1896
+ stdout.write(`docker ${args.join(" ")}
1897
+ `);
1898
+ stdout.write(`\0DOCKER_PHASE:${JSON.stringify({ _dockerPhase: "close", _cardId: cardId, _cardState: "close" })}
1899
+ `);
1900
+ dockerProc = execa2("docker", args, { reject: false });
1901
+ dockerProc.stdout?.pipe(stdout, { end: false });
1902
+ dockerProc.stderr?.pipe(stderr, { end: false });
1903
+ const result = await dockerProc;
1904
+ resolve2({ exitCode: result.exitCode ?? null, signal: result.signal ?? null });
1905
+ } else {
1906
+ innerProcess = this.start({
1907
+ ...config,
1908
+ command: shortcutCommand,
1909
+ cmdId: `shortcut-${randomUUID()}`,
1910
+ rm: true,
1911
+ skipBootstrap: true,
1912
+ dockerConfig: { ...config.dockerConfig, useNativeCommand: true }
1913
+ });
1914
+ innerProcess.stdout?.pipe(stdout, { end: false });
1915
+ innerProcess.stderr?.pipe(stderr, { end: false });
1916
+ const result = await innerProcess.exitPromise;
1917
+ resolve2(result);
1918
+ }
1919
+ } catch (err) {
1920
+ const msg = err instanceof Error ? err.message : String(err);
1921
+ stderr.write(`docker shortcut error: ${msg}
1922
+ `);
1923
+ resolve2({ exitCode: 1, signal: null });
1924
+ } finally {
1925
+ stdout.end();
1926
+ stderr.end();
1927
+ }
1928
+ })();
1887
1929
  }
1888
- const result = ctx["__result"];
1889
- if (result === null || result === void 0 || typeof result !== "object") {
1890
- return line;
1930
+ );
1931
+ return {
1932
+ pid: void 0,
1933
+ stdout,
1934
+ stderr,
1935
+ exitPromise,
1936
+ kill(signal = "SIGTERM") {
1937
+ if (innerProcess) return innerProcess.kill(signal);
1938
+ dockerProc?.kill("SIGTERM");
1939
+ return true;
1891
1940
  }
1892
- return result;
1893
1941
  };
1894
1942
  }
1895
- /** Sanitize the final LogLine: truncate message, limit metadata, validate level */
1896
- sanitize(line) {
1897
- let { message, metadata, level } = line;
1898
- if (message.length > 16384) {
1899
- message = message.substring(0, 16384) + "...[truncated]";
1900
- }
1901
- metadata = metadata ?? {};
1902
- const metaKeys = Object.keys(metadata);
1903
- if (metaKeys.length > 100) {
1904
- const limited = {};
1905
- for (let i = 0; i < 100; i++) {
1906
- limited[metaKeys[i]] = metadata[metaKeys[i]];
1907
- }
1908
- metadata = limited;
1909
- }
1910
- if (!VALID_LEVELS.has(level)) {
1911
- level = "info";
1912
- }
1913
- if (message !== line.message || metadata !== line.metadata || level !== line.level) {
1914
- return { ...line, message, metadata, level };
1915
- }
1916
- return line;
1943
+ async isAvailable() {
1944
+ const result = await execa2("docker", ["info"], { reject: false });
1945
+ return result.exitCode === 0;
1946
+ }
1947
+ /** Run a single bootstrap command sequentially inside a temporary container (--rm).
1948
+ * Streams stdout/stderr into the provided PassThrough streams.
1949
+ * Resolves with the exit code when the container exits. */
1950
+ async runBootstrap(cmd, imageName, env2, volumes, stdout, stderr) {
1951
+ const containerName = sanitizeDockerName(`runeya-bootstrap-${randomUUID()}`);
1952
+ const envFlags = Object.entries(env2).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
1953
+ await preMkdirVolumes(volumes, env2);
1954
+ const volumeFlags = volumes.map((v) => expandEnvVars2(v, env2)).flatMap((v) => ["-v", v]);
1955
+ const entrypointFlags = cmd.entrypoint ? ["--entrypoint", cmd.entrypoint] : [];
1956
+ const { uid, gid } = userInfo();
1957
+ const defaultUser = `${uid}:${gid}`;
1958
+ const userFlags = ["--user", cmd.user || defaultUser];
1959
+ const cmdArgs = splitShellArgs(cmd.command);
1960
+ const runArgs = [
1961
+ "run",
1962
+ "--rm",
1963
+ "--init",
1964
+ "--name",
1965
+ containerName,
1966
+ "--network",
1967
+ "host",
1968
+ ...envFlags,
1969
+ ...volumeFlags,
1970
+ ...entrypointFlags,
1971
+ ...userFlags,
1972
+ imageName,
1973
+ ...cmdArgs
1974
+ ];
1975
+ const proc = execa2("docker", runArgs, { reject: false });
1976
+ proc.stdout?.pipe(stdout, { end: false });
1977
+ proc.stderr?.pipe(stderr, { end: false });
1978
+ const result = await proc;
1979
+ return result.exitCode ?? 1;
1917
1980
  }
1918
1981
  };
1919
1982
 
1920
- // ../../packages/shared/src/constants/intervals.ts
1921
- var HEALTH_CHECK_INTERVAL = 3e4;
1922
- var METRICS_INTERVAL = 5e3;
1923
- var HEALTH_CHECK_INITIAL_DELAY = 5e3;
1924
- var HEALTH_WS_INTERVAL = 1e4;
1925
-
1926
- // ../../packages/shared/src/constants/buffers.ts
1927
- var LOG_BUFFER_SIZE = 5e3;
1928
-
1929
- // ../../packages/shared/src/constants/timeouts.ts
1930
- var GRACE_PERIOD = 1e4;
1931
- var AGENT_STOP_FETCH_TIMEOUT = GRACE_PERIOD + 15e3;
1932
-
1933
- // ../../packages/shared/src/constants/editors.ts
1934
- var SUPPORTED_EDITORS = [
1935
- { key: "vscode", name: "Visual Studio Code", command: "code" },
1936
- { key: "cursor", name: "Cursor", command: "cursor" },
1937
- { key: "windsurf", name: "Windsurf", command: "windsurf" },
1938
- { key: "sublime", name: "Sublime Text", command: "subl" },
1939
- { key: "atom", name: "Atom", command: "atom" },
1940
- { key: "antigravity", name: "Antigravity", command: "antigravity" },
1941
- { key: "intellij", name: "IntelliJ IDEA", command: "idea" },
1942
- { key: "android-studio", name: "Android Studio", command: "studio" },
1943
- { key: "webstorm", name: "WebStorm", command: "webstorm" },
1944
- { key: "zed", name: "Zed", command: "zed" },
1945
- { key: "neovim", name: "Neovim", command: "nvim" },
1946
- { key: "vim", name: "Vim", command: "vim" },
1947
- { key: "emacs", name: "Emacs", command: "emacs" },
1948
- { key: "fleet", name: "Fleet", command: "fleet" }
1949
- ];
1950
- var EDITOR_BY_KEY = new Map(
1951
- SUPPORTED_EDITORS.map((e) => [e.key, e])
1952
- );
1983
+ // src/services/process-store.ts
1984
+ var ProcessStore = class {
1985
+ processes = /* @__PURE__ */ new Map();
1986
+ get(id) {
1987
+ return this.processes.get(id);
1988
+ }
1989
+ getAll() {
1990
+ return Array.from(this.processes.values());
1991
+ }
1992
+ set(id, process2) {
1993
+ this.processes.set(id, process2);
1994
+ }
1995
+ delete(id) {
1996
+ return this.processes.delete(id);
1997
+ }
1998
+ has(id) {
1999
+ return this.processes.has(id);
2000
+ }
2001
+ clear() {
2002
+ this.processes.clear();
2003
+ }
2004
+ getByServiceId(serviceId) {
2005
+ return this.getAll().find((p) => p.serviceConfig.id === serviceId);
2006
+ }
2007
+ };
2008
+ var processStore = new ProcessStore();
1953
2009
 
1954
- // ../../packages/shared/src/sync/json-crdt.ts
1955
- import * as Y from "yjs";
2010
+ // src/services/log-sources/console-log-source.ts
2011
+ import { createInterface } from "readline";
2012
+ import { EventEmitter } from "events";
2013
+ import { randomUUID as randomUUID2 } from "crypto";
1956
2014
 
1957
2015
  // src/services/log-parser.ts
1958
2016
  var DEFAULT_LEVEL_PATTERNS = [
@@ -3596,13 +3654,20 @@ function getLanIp() {
3596
3654
  }
3597
3655
  return "127.0.0.1";
3598
3656
  }
3599
- function resolveServiceBuiltins(serviceEnv) {
3600
- const hostLan = getLanIp();
3601
- const resolved = {};
3602
- for (const [key, value] of Object.entries(serviceEnv)) {
3603
- resolved[key] = value.replaceAll("{{service.HOST_LAN}}", hostLan);
3604
- }
3605
- return resolved;
3657
+ function resolveAgentBuiltins(serviceConfig) {
3658
+ const values = {
3659
+ "agent.HOST_LAN": getLanIp(),
3660
+ "agent.OS": platform2(),
3661
+ "agent.HOME": homedir5(),
3662
+ // Le cwd est calculé avec l'env AVANT substitution : une variable qui
3663
+ // référencerait `{{service.CWD}}` ne peut donc pas se boucler sur
3664
+ // elle-même — la substitution ne repasse jamais sur son propre résultat.
3665
+ "service.CWD": resolve(resolveCwd(
3666
+ serviceConfig.resolvedCwd ?? serviceConfig.cwd,
3667
+ resolveEnv(serviceConfig.env)
3668
+ ))
3669
+ };
3670
+ return withDeprecatedAliases(values);
3606
3671
  }
3607
3672
  var ProcessManager = class extends EventEmitter7 {
3608
3673
  runners = /* @__PURE__ */ new Map();
@@ -3701,7 +3766,10 @@ var ProcessManager = class extends EventEmitter7 {
3701
3766
  throw new Error(`Process ${processId} is already ${proc.state}`);
3702
3767
  }
3703
3768
  if (proc.serviceConfig.env) {
3704
- proc.serviceConfig = { ...proc.serviceConfig, env: resolveServiceBuiltins(proc.serviceConfig.env) };
3769
+ proc.serviceConfig = {
3770
+ ...proc.serviceConfig,
3771
+ env: interpolateBuiltinsInEnv(proc.serviceConfig.env, resolveAgentBuiltins(proc.serviceConfig))
3772
+ };
3705
3773
  }
3706
3774
  const commands = (proc.serviceConfig.commands ?? []).filter((c) => c.command.trim());
3707
3775
  const isDocker = proc.serviceConfig.runner === "docker";
@@ -4549,7 +4617,7 @@ var processRouter = router({
4549
4617
  });
4550
4618
 
4551
4619
  // src/trpc/routers/health.ts
4552
- import { networkInterfaces as networkInterfaces2 } from "os";
4620
+ import { networkInterfaces as networkInterfaces2, homedir as homedir6, platform as platform3 } from "os";
4553
4621
  import { execFile as execFile3 } from "child_process";
4554
4622
  import { promisify } from "util";
4555
4623
  var execFileAsync = promisify(execFile3);
@@ -4574,7 +4642,14 @@ async function getHealthData() {
4574
4642
  runnersAvailable: runners,
4575
4643
  processCount: processes.length,
4576
4644
  runningCount: processes.filter((p) => p.state === "running").length,
4577
- lanIp: getLanIp2()
4645
+ lanIp: getLanIp2(),
4646
+ // Ce qui décrit la machine, pour que l'interface puisse montrer la valeur
4647
+ // qu'aura `{{agent.OS}}`, `{{agent.HOME}}`, `{{service.CWD}}` AVANT que le
4648
+ // service ne démarre. La résolution, elle, reste faite ici au lancement :
4649
+ // ce statut n'est qu'un cliché, et l'agent reste l'autorité sur sa machine.
4650
+ os: platform3(),
4651
+ home: homedir6(),
4652
+ cwd: process.cwd()
4578
4653
  };
4579
4654
  }
4580
4655
  var healthRouter = router({
@@ -6469,7 +6544,7 @@ function appendToPath(dir, environment = process.env) {
6469
6544
  // ../../packages/shared/src/node/user-path.ts
6470
6545
  import { execFile as execFile5 } from "child_process";
6471
6546
  import { promisify as promisify3 } from "util";
6472
- import { homedir as homedir5 } from "os";
6547
+ import { homedir as homedir7 } from "os";
6473
6548
  import { existsSync as existsSync4, statSync } from "fs";
6474
6549
  import { join as join6, delimiter as delimiter2 } from "path";
6475
6550
  var execFileAsync3 = promisify3(execFile5);
@@ -6506,7 +6581,7 @@ async function readLoginShellPath() {
6506
6581
  return null;
6507
6582
  }
6508
6583
  }
6509
- async function ensureUserBinsOnPath(environment = process.env, home = homedir5()) {
6584
+ async function ensureUserBinsOnPath(environment = process.env, home = homedir7()) {
6510
6585
  const shellPath = await readLoginShellPath();
6511
6586
  if (shellPath) {
6512
6587
  for (const entry of shellPath.split(delimiter2).filter(Boolean)) {